Skip to content

Commit

Permalink
Initial commit 🎉
Browse files Browse the repository at this point in the history
  • Loading branch information
vernondegoede committed Feb 28, 2018
0 parents commit cdf5fd8
Show file tree
Hide file tree
Showing 25 changed files with 494 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

# rspec failure tracking
.rspec_status
.idea/
3 changes: 3 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--format documentation
--color
--require spec_helper
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
sudo: false
language: ruby
rvm:
- 2.2.7
before_install: gem install bundler -v 1.16.1
8 changes: 8 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'mollie-api-ruby', '~> 3.1.3'

# Specify your gem's dependencies in spree_mollie_gateway.gemspec
gemspec
38 changes: 38 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
PATH
remote: .
specs:
spree_mollie_gateway (0.1.0)
mollie-api-ruby (~> 3.1.3)

GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.3)
mollie-api-ruby (3.1.3)
rake (10.5.0)
rspec (3.7.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-core (3.7.1)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-support (3.7.1)

PLATFORMS
ruby

DEPENDENCIES
bundler (~> 1.16)
mollie-api-ruby (~> 3.1.3)
rake (~> 10.0)
rspec (~> 3.0)
spree_mollie_gateway!

BUNDLED WITH
1.16.1
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# SpreeMollieGateway

Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/spree_mollie_gateway`. To experiment with that code, run `bin/console` for an interactive prompt.

TODO: Delete this and the text above, and describe your gem

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'spree_mollie_gateway'
```

And then execute:

$ bundle

Or install it yourself as:

$ gem install spree_mollie_gateway

## Usage

TODO: Write usage instructions here

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/spree_mollie_gateway.
6 changes: 6 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

task :default => :spec
41 changes: 41 additions & 0 deletions app/controllers/spree/checkout_controller_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
module Spree
module CheckoutWithMollie
def update
if payment_params_valid? && paying_with_mollie?
if @order.update_from_params(params, permitted_checkout_attributes, request.headers.env)
payment = @order.payments.last
payment.create_transaction!
mollie_payment_url = payment.payment_source.payment_url

redirect_to mollie_payment_url
else
render :edit
end
else
super
end
end
end

CheckoutController.class_eval do
prepend CheckoutWithMollie
private

def payment_method_id_param
params[:order][:payments_attributes].first[:payment_method_id]
end

def paying_with_mollie?
payment_method = PaymentMethod.find(payment_method_id_param)
mollie_payment_method?(payment_method)
end

def payment_params_valid?
(params[:state] === 'payment') && params[:order][:payments_attributes]
end

def mollie_payment_method?(payment_method)
payment_method.is_a?(Gateway::MollieGateway)
end
end
end
26 changes: 26 additions & 0 deletions app/controllers/spree/mollie_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Spree
class MollieController < BaseController
skip_before_action :verify_authenticity_token, :only => [:update_payment_status]

# When the user is redirected from Mollie back to the shop, we can check the
# mollie transaction status and set the Spree order state accordingly.
def validate_payment
order = Spree::Order.find_by_number(params[:order_number])
payment = order.payments.last
mollie = Spree::PaymentMethod.find_by_type('Spree::Gateway::MollieGateway')
mollie.update_payment_status(payment)

redirect_to order.reload.paid? ? order_path(order) : checkout_state_path(:payment)
end

# Mollie might send us information about a transaction through the webhook.
# We should update the payment state accordingly.
def update_payment_status
payment = Spree::Payment.find_by_response_code(params[:id])
mollie = Spree::PaymentMethod.find_by_type('Spree::Gateway::MollieGateway')
mollie.update_payment_status(payment)

render json: 'OK'
end
end
end
5 changes: 5 additions & 0 deletions app/models/mollie/provider.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Mollie
class Provider < Client
# Mollie Provider base class.
end
end
144 changes: 144 additions & 0 deletions app/models/spree/gateway/mollie_gateway.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
module Spree
class Gateway::MollieGateway < PaymentMethod
preference :api_key, :string

has_many :spree_mollie_transactions, class_name: 'Spree::MollieTransaction'

GATEWAY_NAME = 'Mollie'

def payment_source_class
Spree::MollieTransaction
end

def provider_class
::Mollie::Provider
end

def source_required?
true
end

def available_for_order?(order)
true
end

def name
return GATEWAY_NAME if payments.none? || payments.last.source.nil?

case payments.last.source.payment_method_name
when ::Mollie::Method::IDEAL then
'iDEAL'
when ::Mollie::Method::CREDITCARD then
'Credit card'
when ::Mollie::Method::MISTERCASH then
'Bancontact'
when ::Mollie::Method::SOFORT then
'SOFORT Banking'
when ::Mollie::Method::BANKTRANSFER then
'Bank transfer'
when ::Mollie::Method::BITCOIN then
'Bitcoin'
when ::Mollie::Method::PAYPAL then
'PayPal'
when ::Mollie::Method::KBC then
'KBC/CBC Payment Button'
when ::Mollie::Method::BELFIUS then
'Belfius Pay Button'
when ::Mollie::Method::PAYSAFECARD then
'paysafecard'
when ::Mollie::Method::PODIUMCADEAUKAART then
'Podium Cadeaukaart'
when ::Mollie::Method::GIFTCARD then
'Giftcard'
when ::Mollie::Method::INGHOMEPAY then
'ING Home\'Pay'
else
'Mollie'
end
end

# Create a new transaction
def create_transaction(money, source, gateway_options)
payment = payments.last
transaction = ::Mollie::Payment.create(
prepare_transaction_params(payment.order, source)
)

invalidate_prev_transactions(payment.id)

payment.response_code = transaction.id
payment.save!

source.payment_id = transaction.id
source.payment_url = transaction.payment_url
source.save!

ActiveMerchant::Billing::Response.new(true, 'Transaction created')
end

def prepare_transaction_params(order, source)
order_number = order.number
order_params = {
amount: order.total.to_f,
description: "Spree Order ID: #{order_number}",
redirectUrl: "http://spree.vndg.com:3000/mollie/validate_payment/#{order_number}",
webhookUrl: "https://a775808b.ngrok.io/mollie/update_payment_status/#{order_number}",
method: source.payment_method_name,
metadata: {
order_id: order_number
},
api_key: get_preference(:api_key),
}

# Add additional information based on payment method.
if order.user_id.present?
if source.payment_method_name.match(Regexp.union([::Mollie::Method::BITCOIN, ::Mollie::Method::BANKTRANSFER, ::Mollie::Method::GIFTCARD]))
order_params.merge! ({
billingEmail: order.user.email
})
end
end

order_params
end

def available_payment_methods
::Mollie::Method.all(
api_key: get_preference(:api_key),
include: 'issuers'
)
end

def update_payment_status(payment)
mollie_transaction_id = payment.response_code
transaction = ::Mollie::Payment.get(
mollie_transaction_id,
api_key: get_preference(:api_key)
)

unless payment.completed?
case transaction.status
when 'paid'
payment.complete! unless payment.completed?
payment.order.finalize!
payment.order.update_attributes(:state => 'complete', :completed_at => Time.now)
when 'cancelled', 'expired', 'failed'
payment.failure! unless payment.failed?
else
logger.debug 'Unhandled Mollie payment state received. Therefore we did not update the payment state.'
end
end

payment.source.update(status: payment.state)
end

private
def invalidate_prev_transactions(current_payment_id)
# Cancel all previous payment which are pending or are still being processed
payments.with_state('processing').or(payments.with_state('pending')).where.not(id: current_payment_id).each do |payment|
# Set internal payment state to failed
payment.failure! unless payment.store_credit?
end
end
end
end
22 changes: 22 additions & 0 deletions app/models/spree/mollie_transaction.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Spree
class MollieTransaction < Spree::Base
belongs_to :payment_method
has_many :payment, as: :source

delegate :name, to: :payment_method

def actions
[]
end

def method_type
'mollie_transaction'
end

def details
api_key = payment_method.get_preference(:api_key)
mollie_payment = ::Mollie::Payment.get(payment_id, api_key: api_key)
mollie_payment.attributes
end
end
end
6 changes: 6 additions & 0 deletions app/models/spree/payment/processing_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Spree::Payment::Processing.module_eval do
def create_transaction!
started_processing!
gateway_action(source, :create_transaction, :pend)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- Mollie payments cannot be created manually -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<fieldset data-hook="mollie_payment_source">
<legend><%= payment.source.name %></legend>
<table class="table table-condensed table-bordered">
<% payment.source.details.each do |key, value| %>
<tr>
<th width="20%"><%= key %></th>
<td><%= value %></td>
</tr>
<% end %>
</table>
</fieldset>
14 changes: 14 additions & 0 deletions app/views/spree/checkout/payment/_molliegateway.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<% param_prefix = "payment_source[#{payment_method.id}]" %>

<ul class="list-group">
<% payment_method.available_payment_methods.each do |method| %>
<div class="radio list-group-item clearfix">

<label class="pull-left">
<%= radio_button(param_prefix, :payment_method_name, method.id) %>
<%= image_tag(method.image['normal']) %>
<%= method.description %>
</label>
</div>
<% end %>
</ul>
Loading

0 comments on commit cdf5fd8

Please sign in to comment.