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