Skip to content

Commit

Permalink
fetch payment fees from mollie api
Browse files Browse the repository at this point in the history
  • Loading branch information
yksflip committed Oct 23, 2023
1 parent bb4d9b8 commit d7e164a
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 117 deletions.
10 changes: 2 additions & 8 deletions plugins/mollie/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,8 @@ This project adds support for various online payment methods using Mollie to Foo
mollie:
# API key for account: 1234567, website profile: FooInc
api_key: test_1234567890abcdef1234567890abcd
# Transaction fee per payment method, fixed rate and/or percentage.
# This is substracted from the amount actually credited to the ordergroup's account balance.
fee:
# example fees from May 2014 incl. 21% VAT (verify before using!)
ideal: 1.20
banktransfer: 0.30
creditcard: 3.39% + 0.05
paypal: 0.18 + 0.35 + 3.4%
# Transaction fee as provided by mollie api
charge_fees: true
```
The transaction fee is sub will be added on each payment when set; it is not set by default,
Expand Down
32 changes: 22 additions & 10 deletions plugins/mollie/app/controllers/payments/mollie_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Payments::MollieController < ApplicationController
before_action :ordergroup, only: [:new, :create, :result]
before_action :transaction, only: [:result]
before_action :configure_api_key
before_action :payment_methods, only: [:new, :create]

def new
params.permit(:amount, :min)
Expand All @@ -19,28 +20,33 @@ def create

amount = params[:amount].to_f
amount = [params[:min].to_f, amount].max if params[:min]
amount += params[:payment_fee].to_f if params[:payment_fee]

redirect_to new_payments_mollie_path(session[:mollie_params]), alert: t('.invalid_amount') and return if amount <= 0

ft_type = FinancialTransactionType.find_by_id(FoodsoftConfig[:mollie][:financial_transaction_type]) || FinancialTransactionType.first

method = Mollie::Method.all(include: 'pricing,issuers').find { |m| m.id == params[:payment_method] }

@transaction = FinancialTransaction.create!(
amount: nil,
ordergroup: @ordergroup,
user: @current_user,
payment_plugin: 'mollie',
payment_amount: amount,
payment_fee: params[:payment_fee],
# @todo payment_currency
payment_state: 'open',
payment_method: method.id,
financial_transaction_type: ft_type,
note: t('.controller.transaction_note', method: nil)
)

payment = Mollie::Payment.create(
amount: {
value: format('%.2f', amount),
currency: 'EUR' # @todo payment_currency
},
method: method.id,
description: "#{@transaction.id}, #{@ordergroup.id}, #{FoodsoftConfig[:name]}",
redirectUrl: result_payments_mollie_url(id: @transaction.id),
webhookUrl: request.local? ? 'https://example.com' : check_payments_mollie_url, # Mollie doesn't accept localhost here
Expand Down Expand Up @@ -107,7 +113,7 @@ def transaction
# Query Mollie status and update financial transaction
def update_transaction(transaction)
payment = Mollie::Payment.get transaction.payment_id
logger.debug "Mollie update_transaction: #{payment.inspect}"
logger.debug "Mollie update_transaction: #{transaction.inspect} with payment: #{payment.inspect}"
update_transaction_details(transaction, payment)
update_transaction_amount(transaction, payment)
payment.status
Expand All @@ -116,21 +122,27 @@ def update_transaction(transaction)
def update_transaction_amount(transaction, payment)
# payment.status could be open, paid, expired, failed, canceled
if payment.status == 'paid'
payment_fee = FoodsoftMollie.payment_fee payment.amount.value, transaction.payment_method
amount = payment.amount.value.to_f - payment_fee.to_f
amount = payment.amount.value.to_f
amount -= transaction.payment_fee if FoodsoftConfig[:mollie][:charge_fees]
transaction.update payment_state: payment.status, amount: amount
else
transaction.update payment_state: payment.status
end
transaction.update payment_state: payment.status, amount: amount || 0, payment_fee: payment_fee || nil
end

def update_transaction_details(transaction, payment)
if payment.details
transaction.payment_acct_number = payment.details.consumerAccount
transaction.payment_acct_name = payment.details.consumerName
end
transaction.payment_method = payment.method
transaction.payment_acct_number = payment.details.consumerAccount if payment.details
transaction.payment_acct_name = payment.details.consumerName if payment.details
transaction.note = t('.controller.transaction_note', method: payment.method)
end

def payment_methods
@payment_methods = Mollie::Method.all(include: 'pricing,issuers')
@payment_methods_fees = @payment_methods.to_h do |m|
[m.id, m.pricing.map { |pricing| [pricing.description, pricing.fixed.value.to_f, pricing.variable.to_f] }]
end
end

private

def configure_api_key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@
%h4= 'Mollie'
= config_input form, :use_mollie, as: :boolean
= form.fields_for :mollie do |fields|
= config_input fields, :api_key, input_html: {class: 'input-xlarge'}
= 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 ] }
%h5= 'Fee'
= fields.fields_for :fee do |fields|
= config_input fields, :ideal, input_html: {class: 'input-xlarge'}
= config_input fields, :banktransfer, input_html: {class: 'input-xlarge'}
= config_input fields, :creditcard, input_html: {class: 'input-xlarge'}
= config_input fields, :paypal, input_html: {class: 'input-xlarge'}
= config_input fields, :charge_fees, as: :boolean
52 changes: 24 additions & 28 deletions plugins/mollie/app/views/payments/mollie/_form.html.haml
Original file line number Diff line number Diff line change
@@ -1,42 +1,26 @@
- content_for :javascript do
:javascript
// @todo code duplication of foodsoft_mollie.rb
function paymentFee(amount, feeSpec) {
if (typeof feeSpec === 'number') {
return feeSpec;
}

return feeSpec.split('+').reduce((sum, c) => {
const parsed = c.trim().match(/^(.*)\s*%\s*$/);
if (parsed) {
return sum + (parseFloat(parsed[1]) / 100 * parseFloat(amount));
} else {
return sum + parseFloat(c);
}
}, 0).toFixed(2);
function paymentFee(amount, fixed, variable) {
return fixed + (amount * (variable/100));
}

function handleInputAmount(){
var amount = parseFloat($('#amount').val());
var isError = false;
$('#fee_list').children('#fee').each(function(){
var fee = $(this).data('fee');
if (amount){
$(this).text(I18n.l("currency", paymentFee(amount, fee)));
} else {
$(this).text(fee);
}
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[1], fee[2]).toFixed(2);
$('#payment_fee')
.append($("<option></option>")
.attr("value", calculatedFee)
.text(`${I18n.l("currency", calculatedFee)} (${fee[0]})`));
});
}

$('#amount').on('keyup', handleInputAmount);
$('#payment_method').on('change', handleInputAmount);
$(document).ready(handleInputAmount);

%h5= t '.fee'
%dl.dl-horizontal#fee_list
- FoodsoftConfig[:mollie][:fee].each do |k, v|
%dt= k
%dd{id: "fee", data: { fee: v}}"
= form_tag payments_mollie_path, method: :post do
- if params[:text]
.well= params[:text]
Expand All @@ -50,6 +34,18 @@
- if params[:min]
.help-inline{style: 'margin-bottom: 10px'}
= "(min #{number_to_currency params[:min], precision: 0})"
.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 FoodsoftConfig[:mollie]['charge_fees']
.control-group
.control-label
= label_tag 'payment_method', t('.fee')
.controls
#fee_list{data: @payment_methods_fees}= select_tag 'payment_fee'

.control-group
.controls
= submit_tag t('.submit')
Expand Down
46 changes: 26 additions & 20 deletions plugins/mollie/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,40 @@ en:
activerecord:
attributes:
home:
credit_your_account: 'Credit your Account'
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'
title: Credit your account
no_ordergroup: You need to be member of an ordergroup
create:
invalid_amount: 'Invalid amount'
invalid_amount: Invalid amount
form:
amount_pay: 'Amount to pay'
method: 'Pay using'
submit: 'Pay at your bank'
financial_transaction_type: 'Financial Transaction Type'
fee: 'The transaction fee depends on your payment method'
amount_pay: Amount to pay
method: Pay using
submit: Pay at your bank
financial_transaction_type: Financial Transaction Type
fee: Select the appropriate transaction costs
controller:
result:
notice: 'Your account was credited %{amount} (transaction fee of %{fee}).'
failed: 'Payment failed.'
wait: 'Your account will be credited when the payment is received.'
notice: Your account was credited %{amount} (transaction fee of %{fee}).
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.
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.
keys:
use_mollie: 'Use Mollie'
use_mollie: Use Mollie
mollie:
api_key: 'API key'
financial_transaction_type: 'Transaction type'
fee:
ideal: 'Ideal'
banktransfer: 'banktransfer'
creditcard: 'creditcard'
paypal: 'paypal'
api_key: API key
financial_transaction_type: Transaction type
charge_fees: Charge transaction fees
45 changes: 26 additions & 19 deletions plugins/mollie/config/locales/nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,39 @@ nl:
activerecord:
attributes:
home:
credit_your_account: 'Crediteer uw account'
credit_your_account: Geld storten
home:
index:
credit_your_account: Geld storten
ordergroup:
credit_your_account: Geld storten
payments:
mollie:
new:
title: 'Betalen'
no_ordergroup: 'U dient lid te zijn van een ordergroep'
title: Stort geld op je account
no_ordergroup: U dient lid te zijn van een huishouden
create:
invalid_amount: 'Ongeldig bedrag'
invalid_amount: Ongeldig bedrag
form:
amount_pay: 'Te betalen bedrag'
method: 'Hoe te betalen'
submit: 'Betalen'
financial_transaction_type: 'Financiële-transactietype'
fee: 'De transactiekosten van uw betalingsmiddel zijn'
amount_pay: Te betalen bedrag
method: Hoe te betalen
submit: Betaal online
financial_transaction_type: Financiële-transactietype
fee: Selecteer de juiste transactiekosten
controller:
result:
notice: ' Er is %{amount} bijgeschreven op uw account (transactiekosten van ${fee}).'
failed: 'Betaling mislukt.'
notice: Er is %{amount} bijgeschreven op uw account (transactiekosten van ${fee}).
failed: Betaling mislukt.
config:
hints:
use_mollie: Laat gebruikers zelf geld op de rekening van hun Foodsoft huishouden zetten met online betalingen via Mollie.
mollie:
api_key: Vul hier de Live API-Key in, te vinden in het Mollie Dashboard (of de Test API-Key voor een Foodsoft demo).
financial_transaction_type: Kies het transactietype waaraan Mollie Payments moeten worden toegewezen
charge_fees: Breng ordergroepen de door Mollie gehanteerde transactiekosten in rekening.
keys:
use_mollie: 'Gebruik Mollie'
use_mollie: Accepteer online betalingen via Mollie
mollie:
api_key: 'API key'
financial_transaction_type: 'Transactie type'
fee:
ideal: 'Ideal'
banktransfer: 'banktransfer'
creditcard: 'creditcard'
paypal: 'paypal'
api_key: Mollie API-Key
financial_transaction_type: Transactietype
charge_fees: Transactiekosten in rekening brengen
25 changes: 0 additions & 25 deletions plugins/mollie/lib/foodsoft_mollie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,4 @@ module FoodsoftMollie
def self.enabled?
FoodsoftConfig[:use_mollie] != false and FoodsoftConfig[:mollie]
end

# Compute payment transaction fee.
#
# Transaction fee is specified in foodcoop config under +mollie+, +fee+ as a
# hash of fee per payment method, e.g. as "0.30" for a fixed flat fee, "5%"
# for a percentage, or "0.30 + 5%" for both. Multiple flat fees and percentages
# can appear in a single line, so "0.12 + 2% + 0.56 + 3% + 1%" is valid, e.g.
# when multiple payment providers add different fees.
#
# @param amount [Number] Amount payed
# @param method [String] Payment method used
# @return [Number] Transaction fee for payment, or +nil+ if no fee details known.
def self.payment_fee(amount, method)
spec = FoodsoftConfig[:mollie]['fee'] or return
unless spec = spec[method]
Rails.logger.warn "Mollie: transaction fee for method #{method} not configured."
return
end
# parse
return spec if spec.is_a? Numeric

spec.split('+').inject(0) do |sum, c|
sum + (c =~ /^(.*)\s*%\s*$/ ? (::Regexp.last_match(1).to_f / 100 * amount.to_f) : c.to_f)
end
end
end

0 comments on commit d7e164a

Please sign in to comment.