1# frozen_string_literal: true
2
3require "bigdecimal"
4
5class Transaction
6 def self.sale(customer, amount:, payment_method: nil)
7 REDIS.get("jmp_pay_decline-#{customer.customer_id}").then do |declines|
8 raise "too many declines" if declines.to_i >= 2
9
10 BRAINTREE.transaction.sale(
11 amount: amount,
12 **sale_args_for(customer, payment_method)
13 ).then do |response|
14 decline_guard(customer, response)
15 new(response.transaction)
16 end
17 end
18 end
19
20 def self.decline_guard(customer, response)
21 return if response.success?
22
23 REDIS.incr("jmp_pay_decline-#{customer.customer_id}").then do
24 REDIS.expire("jmp_pay_decline-#{customer.customer_id}", 60 * 60 * 24)
25 end
26 raise response.message
27 end
28
29 def self.sale_args_for(customer, payment_method=nil)
30 {
31 merchant_account_id: customer.merchant_account,
32 options: { submit_for_settlement: true }
33 }.merge(
34 if payment_method
35 { payment_method_token: payment_method.token }
36 else
37 { customer_id: customer.customer_id }
38 end
39 )
40 end
41
42 attr_reader :amount
43
44 def initialize(braintree_transaction)
45 @customer_id = braintree_transaction.customer_details.id
46 @transaction_id = braintree_transaction.id
47 @created_at = braintree_transaction.created_at
48 @amount = BigDecimal(braintree_transaction.amount, 4)
49 end
50
51 def insert
52 EM.promise_fiber do
53 DB.transaction do
54 insert_tx
55 insert_bonus
56 end
57 end
58 end
59
60 def bonus
61 return BigDecimal(0) if amount <= 15
62
63 amount *
64 case amount
65 when (15..29.99)
66 0.01
67 when (30..139.99)
68 0.03
69 else
70 0.05
71 end
72 end
73
74 def to_s
75 plus = " + #{'%.4f' % bonus} bonus"
76 "$#{'%.2f' % amount}#{plus if bonus.positive?}"
77 end
78
79protected
80
81 def insert_tx
82 params = [@customer_id, @transaction_id, @created_at, @amount]
83 DB.exec(<<~SQL, params)
84 INSERT INTO transactions
85 (customer_id, transaction_id, created_at, amount, note)
86 VALUES
87 ($1, $2, $3, $4, 'Credit card payment')
88 SQL
89 end
90
91 def insert_bonus
92 return if bonus <= 0
93
94 params = [@customer_id, "bonus_for_#{@transaction_id}", @created_at, bonus]
95 DB.exec(<<~SQL, params)
96 INSERT INTO transactions
97 (customer_id, transaction_id, created_at, amount, note)
98 VALUES
99 ($1, $2, $3, $4, 'Credit card payment bonus')
100 SQL
101 end
102end