-
Notifications
You must be signed in to change notification settings - Fork 147
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Co-authored-by: wvengen <[email protected]>
- Loading branch information
Showing
20 changed files
with
1,090 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.bundle/ | ||
log/*.log | ||
pkg/ | ||
test/dummy/db/*.sqlite3 | ||
test/dummy/log/*.log | ||
test/dummy/tmp/ | ||
test/dummy/.sass-cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
source 'http://rubygems.org' | ||
|
||
# Declare your gem's dependencies in foodsoft_mollie.gemspec. | ||
# Bundler will treat runtime dependencies like base dependencies, and | ||
# development dependencies will be added by default to the :development group. | ||
gemspec |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
FoodsoftMollie | ||
============== | ||
|
||
This project adds support for various online payment methods using Mollie to Foodsoft. | ||
|
||
* Make sure the gem is uncommented in foodsoft's `Gemfile` | ||
* Enter your Mollie account details in `config/app_config.yml` | ||
|
||
```yaml | ||
use_mollie: true | ||
# Mollie payment settings | ||
mollie: | ||
# API key for account: 1234567, website profile: FooInc | ||
api_key: test_1234567890abcdef1234567890abcd | ||
# Transaction fee as provided by mollie api (only EUR supported) | ||
charge_fees: true | ||
currency: EUR # should match the foodcoop's currency | ||
``` | ||
When charge_fees is set true, the transaction fee will be added on each payment. At the moment fees are only supported with EUR. | ||
It is disabled by default, meaning that the foodcoop will pay any transaction costs (out of the margin). | ||
To initiate a payment, redirect to `new_payments_mollie_path` at `/:foodcoop/payments/mollie/new`. | ||
The following url parameters are recognised: | ||
* ''amount'' - default amount to charge (optional) | ||
* ''fixed'' - when "true", the amount cannot be changed (optional) | ||
* ''title'' - page title (optional) | ||
* ''label'' - label for amount (optional) | ||
* ''min'' - minimum amount accepted (optional) | ||
|
||
This plugin also introduces the foodcoop config option `use_mollie`, which can | ||
be set to `false` to disable this plugin's functionality. May be useful in | ||
multicoop deployments. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#!/usr/bin/env rake | ||
begin | ||
require 'bundler/setup' | ||
rescue LoadError | ||
puts 'You must `gem install bundler` and `bundle install` to run rake tasks' | ||
end | ||
begin | ||
require 'rdoc/task' | ||
rescue LoadError | ||
require 'rdoc/rdoc' | ||
require 'rake/rdoctask' | ||
RDoc::Task = Rake::RDocTask | ||
end | ||
|
||
RDoc::Task.new(:rdoc) do |rdoc| | ||
rdoc.rdoc_dir = 'rdoc' | ||
rdoc.title = 'FoodsoftMollie' | ||
rdoc.options << '--line-numbers' | ||
rdoc.rdoc_files.include('README.rdoc') | ||
rdoc.rdoc_files.include('lib/**/*.rb') | ||
end | ||
|
||
# APP_RAKEFILE = File.expand_path("../../../Rakefile", __FILE__) | ||
# load 'rails/tasks/engine.rake' | ||
|
||
Bundler::GemHelper.install_tasks |
144 changes: 144 additions & 0 deletions
144
plugins/mollie/app/controllers/payments/mollie_controller.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
# Mollie payment page | ||
class Payments::MollieController < ApplicationController | ||
before_action -> { require_plugin_enabled FoodsoftMollie } | ||
skip_before_action :authenticate, only: [:check] | ||
skip_before_action :verify_authenticity_token, only: [:check] | ||
before_action :validate_ordergroup_presence, only: %i[new create result] | ||
before_action :payment_methods, only: %i[new create] | ||
|
||
def new | ||
params.permit(:amount, :min) | ||
# if amount or minimum is given use that, otherwise use a default based on the ordergroups funds or 10 | ||
@amount = [params[:min], params[:amount]].compact.max || [FoodsoftMollie.default_amount, @ordergroup.get_available_funds * -1].max # @todo extract | ||
end | ||
|
||
def create | ||
# store parameters so we can redirect to original form on problems | ||
session[:mollie_params] = params.permit(:amount, :payment_method, :label, :title, :fixed, :min, :text, :payment_fee) | ||
|
||
amount = [params[:min].to_f, params[:amount].to_f].compact.max | ||
payment_fee = params[:payment_fee].to_f | ||
amount += payment_fee | ||
|
||
redirect_on_error(t('.invalid_amount')) and return if amount <= 0 | ||
|
||
method = fetch_mollie_methods.find { |m| m.id == params[:payment_method] } | ||
transaction = create_transaction(amount, payment_fee, method) | ||
payment = create_payment(transaction, amount, method) | ||
transaction.update payment_id: payment.id | ||
logger.info "Mollie start: #{amount} for ##{@current_user.id} (#{@current_user.display})" | ||
redirect_to payment.checkout_url, allow_other_host: true | ||
rescue Mollie::Exception => e | ||
Rails.logger.info "Mollie create warning: #{e}" | ||
redirect_on_error t('errors.general_msg', msg: e.message) | ||
end | ||
|
||
# Endpoint that Mollie calls when a payment status changes. | ||
# See: https://docs.mollie.com/overview/webhooks | ||
def check | ||
transaction = FinancialTransaction.find_by_payment_plugin_and_payment_id!('mollie', params.require(:id)) | ||
render plain: update_transaction(transaction) | ||
rescue StandardError => e | ||
Rails.logger.error "Mollie check error: #{e}" | ||
render plain: "Error: #{e.message}" | ||
end | ||
|
||
# User is redirect here after payment | ||
def result | ||
transaction = @ordergroup.financial_transactions.find(params.require(:id)) | ||
update_transaction transaction | ||
case transaction.payment_state | ||
when 'paid' | ||
redirect_to root_path, notice: t('.controller.result.notice', amount: "#{transaction.payment_currency} #{transaction.amount}") | ||
when 'open', 'pending' | ||
redirect_to root_path, notice: t('.controller.result.wait') | ||
else | ||
redirect_on_error t('.controller.result.failed') | ||
end | ||
end | ||
|
||
def cancel | ||
redirect_to root_path | ||
end | ||
|
||
private | ||
|
||
# Query Mollie status and update financial transaction | ||
def update_transaction(transaction) | ||
payment = Mollie::Payment.get(transaction.payment_id, api_key: FoodsoftMollie.api_key) | ||
logger.debug "Mollie update_transaction: #{transaction.inspect} with payment: #{payment.inspect}" | ||
if payment.paid? | ||
amount = payment.amount.value.to_f | ||
amount -= transaction.payment_fee if FoodsoftMollie.charge_fees? | ||
transaction.update! amount: amount | ||
end | ||
transaction.update! payment_state: payment.status | ||
end | ||
|
||
def payment_methods | ||
@payment_methods = fetch_mollie_methods | ||
@payment_methods_fees = @payment_methods.to_h do |method| | ||
[method.id, method.pricing.map do |pricing| | ||
{ | ||
description: pricing.description, | ||
fixed: { currency: pricing.fixed.currency, value: pricing.fixed.value.to_f }, | ||
variable: pricing.variable.to_f | ||
} | ||
end.to_json] | ||
end | ||
end | ||
|
||
def validate_ordergroup_presence | ||
@ordergroup = current_user.ordergroup.presence | ||
redirect_to root_path, alert: t('.no_ordergroup') and return if @ordergroup.nil? | ||
end | ||
|
||
def create_transaction(amount, payment_fee, method) | ||
financial_transaction_type = FinancialTransactionType.find_by_id(FoodsoftConfig[:mollie][:financial_transaction_type]) || FinancialTransactionType.first | ||
note = t('.controller.transaction_note', method: method.description) | ||
|
||
FinancialTransaction.create!( | ||
amount: nil, | ||
ordergroup: @ordergroup, | ||
user: @current_user, | ||
payment_plugin: 'mollie', | ||
payment_amount: amount, | ||
payment_fee: payment_fee, | ||
payment_currency: FoodsoftMollie.currency, | ||
payment_state: 'open', | ||
payment_method: method.id, | ||
financial_transaction_type: financial_transaction_type, | ||
note: note | ||
) | ||
end | ||
|
||
def create_payment(transaction, amount, method) | ||
Mollie::Payment.create( | ||
amount: { | ||
value: format('%.2f', amount), | ||
currency: FoodsoftMollie.currency | ||
}, | ||
method: method.id, | ||
description: "#{FoodsoftConfig[:name]}: Continue to add credit to #{@ordergroup.name}", | ||
redirectUrl: result_payments_mollie_url(id: transaction.id), | ||
webhookUrl: request.local? ? 'https://localhost.com' : check_payments_mollie_url, # Workaround for local development | ||
metadata: { | ||
scope: FoodsoftConfig.scope, | ||
transaction_id: transaction.id, | ||
user: @current_user.id, | ||
ordergroup: @ordergroup.id | ||
}, | ||
api_key: FoodsoftMollie.api_key | ||
) | ||
end | ||
|
||
def redirect_on_error(alert_message) | ||
pms = { foodcoop: FoodsoftConfig.scope }.merge((session[:mollie_params] || {})) | ||
session[:mollie_params] = nil | ||
redirect_to new_payments_mollie_path(pms), alert: alert_message | ||
end | ||
|
||
def fetch_mollie_methods | ||
Mollie::Method.all(include: 'pricing,issuers', amount: { currency: FoodsoftMollie.currency, value: format('%.2f', FoodsoftMollie.default_amount) }, api_key: FoodsoftMollie.api_key) | ||
end | ||
end |
9 changes: 9 additions & 0 deletions
9
plugins/mollie/app/overrides/admin/configs/_tab_others/add_config.html.haml.deface
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/ insert_after 'erb:contains(":webstats_tracking_code")' | ||
%h4= 'Mollie' | ||
= config_input form, :use_mollie, as: :boolean | ||
= form.fields_for :mollie do |fields| | ||
= config_input fields, :api_key, as: :string, input_html: {class: 'input-xlarge'} | ||
= config_input fields, :financial_transaction_type, :as => :select, :collection => FinancialTransactionType.order(:name).map { |t| [ t.name, t.id ] } | ||
= config_input fields, :charge_fees, as: :boolean | ||
= config_input fields, :currency, as: :string, input_html: {class: 'input-xlarge'} | ||
= config_input fields, :default_amount, as: :float |
4 changes: 4 additions & 0 deletions
4
plugins/mollie/app/overrides/home/index/new_payment_link.html.haml.deface
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/ insert_after 'erb[silent]:contains("<dashboard_ordergroup_mark>")' | ||
= link_to new_payments_mollie_path do | ||
= t '.credit_your_account' | ||
%i.icon.icon-chevron-right |
2 changes: 2 additions & 0 deletions
2
plugins/mollie/app/overrides/home/ordergroup/new_payment_button.html.haml.deface
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/ insert_after 'erb[silent]:contains("<home_ordergroup_well_mark>")' | ||
= link_to t('.credit_your_account'), new_payments_mollie_path, class: 'btn btn-secondary' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
- content_for :javascript do | ||
- if FoodsoftMollie.charge_fees? | ||
:javascript | ||
function paymentFee(amount, fixed, variable) { | ||
return fixed + (amount * (variable/100)); | ||
} | ||
|
||
function handleInputAmount(){ | ||
const payment_method = $('#payment_method').val(); | ||
const amount = parseFloat($('#amount').val()); | ||
$('#payment_fee').empty(); | ||
$('#fee_list').data(payment_method).forEach (fee => { | ||
const calculatedFee = paymentFee(amount, fee.fixed.value, fee.variable).toFixed(2); | ||
const currency = fee.fixed.currency; | ||
$('#payment_fee') | ||
.append($("<option></option>") | ||
.attr("value", calculatedFee) | ||
.text(`${currency} ${calculatedFee} (${fee.description})`)); | ||
}); | ||
} | ||
$('#amount').on('keyup', handleInputAmount); | ||
$('#payment_method').on('change', handleInputAmount); | ||
$(document).ready(handleInputAmount); | ||
|
||
= form_tag payments_mollie_path, method: :post do | ||
- if params[:text] | ||
.well= params[:text] | ||
.control-group | ||
.control-label | ||
= label_tag 'amount', ((params[:label] or t('.amount_pay'))) | ||
.controls | ||
.input-prepend | ||
%span.add-on= t 'number.currency.format.unit' | ||
= text_field_tag 'amount', @amount, readonly: (params[:fixed]=='true'), class: 'input-mini' | ||
- if params[:min] | ||
.help-inline{style: 'margin-bottom: 10px'} | ||
= "(min #{number_to_currency params[:min], precision: 0})" | ||
= hidden_field_tag 'min', params[:min] | ||
.control-group | ||
.control-label | ||
= label_tag 'payment_method', t('.payment_method') | ||
.controls | ||
= select_tag 'payment_method', options_for_select(@payment_methods.map { |p| [p.description, p.id] }, params[:payment_method]), class: 'input-large' | ||
- if FoodsoftMollie.charge_fees? | ||
.control-group | ||
.control-label | ||
= label_tag 'payment_fee', t('.fee') | ||
.controls | ||
#fee_list{data: @payment_methods_fees }= select_tag 'payment_fee' | ||
.control-group | ||
.controls | ||
= submit_tag t('.submit') | ||
= link_to t('ui.or_cancel'), cancel_payments_mollie_path | ||
|
||
-# pass through options to allow reusing on error | ||
- %w(label title fixed min text).each do |k| | ||
= hidden_field_tag k, params[k] if params[k] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
- title (params[:title] or t('.title')) | ||
= render :partial => 'form' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
en: | ||
activerecord: | ||
attributes: | ||
home: | ||
credit_your_account: Credit your Account | ||
home: | ||
index: | ||
credit_your_account: Credit your Account | ||
ordergroup: | ||
credit_your_account: Credit your Account | ||
payments: | ||
mollie: | ||
new: | ||
title: Credit your account | ||
no_ordergroup: You need to be member of an ordergroup | ||
create: | ||
invalid_amount: Invalid amount | ||
form: | ||
amount_pay: Amount to pay | ||
method: Pay using | ||
submit: Pay online | ||
financial_transaction_type: Financial Transaction Type | ||
fee: Select the appropriate transaction costs | ||
controller: | ||
result: | ||
notice: Your account was credited %{amount}. | ||
failed: Payment failed. | ||
wait: Your account will be credited when the payment is received. | ||
transaction_note: '%{method} payment' | ||
config: | ||
hints: | ||
use_mollie: Let members credit their own Foodsoft ordergroup account with online payments using Mollie. | ||
mollie: | ||
api_key: You find the API-Key in the Mollie Dashboard. Use the Live API-Key here (or the Test API-Key for a demo instance). | ||
financial_transaction_type: Choose the transaction type mollie payments should be assigned. | ||
charge_fees: Charge ordergroups the transaction fees applied by mollie. This is currently only available for EUR. | ||
currency: Choose the currency mollie should use (ISO code) | ||
default_amount: The default amount to credit the ordergroup with. | ||
keys: | ||
use_mollie: Use Mollie | ||
mollie: | ||
api_key: API key | ||
financial_transaction_type: Transaction type | ||
charge_fees: Charge transaction fees | ||
currency: Currency | ||
default_amount: Default amount |
Oops, something went wrong.