1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-18 07:52:23 +01:00

improves how pay_zen transactions are matched with payment_schedule_items, improves rrule of pay_zen subscriptions

This commit is contained in:
Nicolas Florentin 2023-12-01 16:07:07 +01:00
parent a946399ec5
commit f77ba72758
3 changed files with 110 additions and 22 deletions

View File

@ -4,6 +4,8 @@
- fix a bug: user was not able to reserve at the same time of an event with pre-registration invalidated
- fix a bug: avoids crash if invoicing_profile has no address associated to it
- improvement: improves how pay_zen transactions are matched with payment_schedule_items
- improvement: improves rrule of pay_zen subscriptions
## v6.3.4 2023 November 23

View File

@ -21,14 +21,15 @@ class PayZen::Service < Payment::Service
amount: payzen_amount(first_item.details['recurring'].to_i),
effect_date: first_item.due_date.iso8601,
payment_method_token: token_id,
rrule: rrule(payment_schedule),
rrule: rrule(payment_schedule, first_item.due_date),
order_id: order_id
}
initial_amount = first_item.amount
initial_amount -= payment_schedule.wallet_amount if payment_schedule.wallet_amount
if initial_amount.zero?
params[:effect_date] = (first_item.due_date + 1.month).iso8601
params[:rrule] = rrule(payment_schedule, -1)
effect_date = first_item.due_date + 1.month
params[:effect_date] = effect_date.iso8601
params[:rrule] = rrule(payment_schedule, effect_date, -1)
else
params[:initial_amount] = payzen_amount(initial_amount)
params[:initial_amount_number] = 1
@ -92,8 +93,8 @@ class PayZen::Service < Payment::Service
return
end
pz_order = payment_schedule_item.payment_schedule.gateway_order.retrieve
transaction = pz_order['answer']['transactions'].last
return unless transaction_matches?(transaction, payment_schedule_item)
transaction = find_transaction_by_payment_schedule_item(pz_order['answer']['transactions'], payment_schedule_item)
return unless transaction
case transaction['status']
when 'PAID'
@ -127,28 +128,35 @@ class PayZen::Service < Payment::Service
amount
end
private
def rrule(payment_schedule, first_date, offset = 0)
count = payment_schedule.payment_schedule_items.count + offset
def rrule(payment_schedule, offset = 0)
count = payment_schedule.payment_schedule_items.count
"RRULE:FREQ=MONTHLY;COUNT=#{count + offset}"
end
# check if the given transaction matches the given PaymentScheduleItem
def transaction_matches?(transaction, payment_schedule_item)
transaction_date = Time.zone.parse(transaction['creationDate']).to_date
amount = payment_schedule_item.amount
if payment_schedule_item == payment_schedule_item.payment_schedule.ordered_items.first &&
payment_schedule_item.payment_schedule.wallet_amount
amount -= payment_schedule_item.payment_schedule.wallet_amount
by_month_day_part = case first_date.day
when 31
"BYMONTHDAY=28,29,30,31;BYSETPOS=-1"
when 30
"BYMONTHDAY=28,29,30;BYSETPOS=-1"
when 29
"BYMONTHDAY=28,29;BYSETPOS=-1"
else
"BYMONTHDAY=#{first_date.day}"
end
transaction['amount'] == amount &&
transaction_date >= payment_schedule_item.due_date.to_date &&
transaction_date <= payment_schedule_item.due_date.to_date + 7.days
"RRULE:FREQ=MONTHLY;#{by_month_day_part};COUNT=#{count}"
end
def find_transaction_by_payment_schedule_item(transactions, payment_schedule_item)
due_date = payment_schedule_item.due_date.to_date
transactions.find do |tr|
expected_capture_date = Time.zone.parse(tr["transactionDetails"]["paymentMethodDetails"]["expectedCaptureDate"]).to_date
(tr["operationType"] == "DEBIT") && (expected_capture_date.between?(due_date - 1.day, due_date + 1.day))
end
end
private
# @see https://payzen.io/en-EN/payment-file/ips/list-of-supported-currencies.html
def zero_decimal_currencies
%w[KHR JPY KRW XOF XPF]

View File

@ -0,0 +1,78 @@
# frozen_string_literal: true
require 'test_helper'
require 'pay_zen/service'
class PayZen::ServiceTest < ActiveSupport::TestCase
setup do
@service = PayZen::Service.new
end
test '#rrule' do
ps = payment_schedules(:payment_schedule_12)
first_due_date = ps.ordered_items.first.due_date
first_date = first_due_date
assert_equal "RRULE:FREQ=MONTHLY;BYMONTHDAY=14;COUNT=12", @service.rrule(ps, first_date)
assert_equal "RRULE:FREQ=MONTHLY;BYMONTHDAY=14;COUNT=11", @service.rrule(ps, first_date, -1)
first_date = first_due_date + 3.days
assert_equal "RRULE:FREQ=MONTHLY;BYMONTHDAY=17;COUNT=12", @service.rrule(ps, first_date)
first_due_date = first_due_date.change(month: 7)
first_date = first_due_date.change(day: 28)
assert_equal "RRULE:FREQ=MONTHLY;BYMONTHDAY=28;COUNT=12", @service.rrule(ps, first_date)
first_date = first_due_date.change(day: 29)
assert_equal "RRULE:FREQ=MONTHLY;BYMONTHDAY=28,29;BYSETPOS=-1;COUNT=12", @service.rrule(ps, first_date)
first_date = first_due_date.change(day: 30)
assert_equal "RRULE:FREQ=MONTHLY;BYMONTHDAY=28,29,30;BYSETPOS=-1;COUNT=12", @service.rrule(ps, first_date)
first_date = first_due_date.change(day: 31)
assert_equal "RRULE:FREQ=MONTHLY;BYMONTHDAY=28,29,30,31;BYSETPOS=-1;COUNT=12", @service.rrule(ps, first_date)
end
def format_transaction(operation_type:, expected_capture_date:)
{ "operationType" => operation_type, "transactionDetails" => { "paymentMethodDetails" => { "expectedCaptureDate" => expected_capture_date } } }
end
test "#find_transaction_by_payment_schedule_item" do
ps = payment_schedules(:payment_schedule_12)
payment_schedule_item = ps.ordered_items.first
expected_capture_date = payment_schedule_item.due_date.iso8601
transactions = [format_transaction(operation_type: "DEBIT", expected_capture_date: expected_capture_date)]
assert @service.find_transaction_by_payment_schedule_item(transactions, payment_schedule_item)
expected_capture_date = (payment_schedule_item.due_date - 1.day).iso8601
transactions = [format_transaction(operation_type: "DEBIT", expected_capture_date: expected_capture_date)]
assert @service.find_transaction_by_payment_schedule_item(transactions, payment_schedule_item)
expected_capture_date = (payment_schedule_item.due_date + 1.day).iso8601
transactions = [format_transaction(operation_type: "DEBIT", expected_capture_date: expected_capture_date)]
assert @service.find_transaction_by_payment_schedule_item(transactions, payment_schedule_item)
expected_capture_date = (payment_schedule_item.due_date + 2.days).iso8601
transactions = [format_transaction(operation_type: "DEBIT", expected_capture_date: expected_capture_date)]
assert_nil @service.find_transaction_by_payment_schedule_item(transactions, payment_schedule_item)
expected_capture_date = (payment_schedule_item.due_date - 2.days).iso8601
transactions = [format_transaction(operation_type: "DEBIT", expected_capture_date: expected_capture_date)]
assert_nil @service.find_transaction_by_payment_schedule_item(transactions, payment_schedule_item)
expected_capture_date = payment_schedule_item.due_date.iso8601
transactions = [format_transaction(operation_type: "CREDIT", expected_capture_date: expected_capture_date)]
assert_nil @service.find_transaction_by_payment_schedule_item(transactions, payment_schedule_item)
end
end