1# frozen_string_literal: true
2
3require "bigdecimal"
4require "time"
5require "value_semantics/monkey_patched"
6
7class Transaction
8 value_semantics do
9 customer_id String
10 transaction_id String
11 created_at Time, coerce: ->(x) { Time.parse(x.to_s) }
12 settled_after Time, coerce: ->(x) { Time.parse(x.to_s) }
13 amount BigDecimal, coerce: ->(x) { BigDecimal(x, 4) }
14 note String
15 end
16
17 def insert
18 EM.promise_fiber do
19 DB.transaction do
20 insert_tx
21 insert_bonus
22 end
23 end
24 end
25
26 def total
27 amount + bonus
28 end
29
30 def bonus
31 return BigDecimal(0) if amount <= 15
32
33 amount *
34 case amount
35 when (15..29.99)
36 0.01
37 when (30..139.99)
38 0.03
39 else
40 0.05
41 end
42 end
43
44 def to_s
45 plus = " + #{'%.4f' % bonus} bonus"
46 "$#{'%.2f' % amount}#{plus if bonus.positive?}"
47 end
48
49protected
50
51 def insert_tx
52 params = [
53 @customer_id, @transaction_id, @created_at, @settled_after, @amount, @note
54 ]
55 DB.exec(<<~SQL, params)
56 INSERT INTO transactions
57 (customer_id, transaction_id, created_at, settled_after, amount, note)
58 VALUES
59 ($1, $2, $3, $4, $5, $6)
60 SQL
61 end
62
63 def insert_bonus
64 return if bonus <= 0
65
66 params = [
67 @customer_id, "bonus_for_#{@transaction_id}", @created_at,
68 @settled_after, bonus, "#{@note} bonus"
69 ]
70 DB.exec(<<~SQL, params)
71 INSERT INTO transactions
72 (customer_id, transaction_id, created_at, settled_after, amount, note)
73 VALUES
74 ($1, $2, $3, $4, $5, $6)
75 SQL
76 end
77end