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
81 def settled_after
82 @created_at + (90 * 24 * 60 * 60)
83 end
84
85protected
86
87 def insert_tx
88 params = [
89 @customer_id, @transaction_id, @created_at, settled_after, @amount
90 ]
91 DB.exec(<<~SQL, params)
92 INSERT INTO transactions
93 (customer_id, transaction_id, created_at, settled_after, amount, note)
94 VALUES
95 ($1, $2, $3, $4, $5, 'Credit card payment')
96 SQL
97 end
98
99 def insert_bonus
100 return if bonus <= 0
101
102 params = [
103 @customer_id, "bonus_for_#{@transaction_id}", @created_at,
104 settled_after, bonus
105 ]
106 DB.exec(<<~SQL, params)
107 INSERT INTO transactions
108 (customer_id, transaction_id, created_at, settled_after, amount, note)
109 VALUES
110 ($1, $2, $3, $4, $5, 'Credit card payment bonus')
111 SQL
112 end
113end