# frozen_string_literal: true
require "bigdecimal"
class Transaction
def self.sale(customer, amount:, payment_method: nil)
REDIS.get("jmp_pay_decline-#{customer.customer_id}").then do |declines|
raise "too many declines" if declines.to_i >= 2
BRAINTREE.transaction.sale(
amount: amount,
**sale_args_for(customer, payment_method)
).then do |response|
decline_guard(customer, response)
new(response.transaction)
end
end
end
def self.decline_guard(customer, response)
return if response.success?
REDIS.incr("jmp_pay_decline-#{customer.customer_id}").then do
REDIS.expire("jmp_pay_decline-#{customer.customer_id}", 60 * 60 * 24)
end
raise response.message
end
def self.sale_args_for(customer, payment_method=nil)
{
merchant_account_id: customer.merchant_account,
options: { submit_for_settlement: true }
}.merge(
if payment_method
{ payment_method_token: payment_method.token }
else
{ customer_id: customer.customer_id }
end
)
end
attr_reader :amount
def initialize(braintree_transaction)
@customer_id = braintree_transaction.customer_details.id
@transaction_id = braintree_transaction.id
@created_at = braintree_transaction.created_at
@amount = BigDecimal(braintree_transaction.amount, 4)
end
def insert
EM.promise_fiber do
DB.transaction do
insert_tx
insert_bonus
end
end
end
def bonus
return BigDecimal(0) if amount <= 15
amount *
case amount
when (15..29.99)
0.01
when (30..139.99)
0.03
else
0.05
end
end
def to_s
plus = " + #{'%.4f' % bonus} bonus"
"$#{'%.2f' % amount}#{plus if bonus.positive?}"
end
protected
def insert_tx
params = [@customer_id, @transaction_id, @created_at, @amount]
DB.exec(<<~SQL, params)
INSERT INTO transactions
(customer_id, transaction_id, created_at, amount, note)
VALUES
($1, $2, $3, $4, 'Credit card payment')
SQL
end
def insert_bonus
return if bonus <= 0
params = [@customer_id, "bonus_for_#{@transaction_id}", @created_at, bonus]
DB.exec(<<~SQL, params)
INSERT INTO transactions
(customer_id, transaction_id, created_at, amount, note)
VALUES
($1, $2, $3, $4, 'Credit card payment bonus')
SQL
end
end