1# frozen_string_literal: true
2
3require "bigdecimal/util"
4
5require_relative "low_balance"
6require_relative "transaction"
7
8class SIMOrder
9 def self.for(customer, price:, **kwargs)
10 price = price.to_i / 100.to_d
11 return new(customer, price: price, **kwargs) if customer.balance >= price
12
13 LowBalance::AutoTopUp.for(customer, price).then do |top_up|
14 if top_up.can_top_up?
15 WithTopUp.new(customer, self, price: price, top_up: top_up, **kwargs)
16 else
17 PleaseTopUp.new(price: price, **kwargs)
18 end
19 end
20 end
21
22 def self.label
23 "SIM"
24 end
25
26 def self.fillable_fields
27 [
28 {
29 type: "text-multi",
30 label: "Shipping Address",
31 var: "addr",
32 required: true
33 }
34 ]
35 end
36
37 def initialize(customer, price:, plan:)
38 @customer = customer
39 @price = price
40 @plan = plan
41 @sim_repo = SIMRepo.new(db: DB)
42 end
43
44 def form
45 FormTemplate.render(
46 "order_sim/with_balance",
47 price: @price,
48 plan: @plan,
49 label: self.class.label,
50 fillable_fields: self.class.fillable_fields
51 )
52 end
53
54 def complete(iq)
55 addr = Array(iq.form.field("addr").value).join("\n")
56 EMPromise.resolve(nil).then { commit }.then do |sim|
57 @customer.stanza_from(Blather::Stanza::Message.new(
58 Blather::JID.new(""), # Doesn't matter, sgx is set to direct target
59 "SIM ORDER: #{sim.iccid}\n#{addr}"
60 ))
61 Command.finish(
62 "You will receive an notice from support when your SIM ships."
63 )
64 end
65 end
66
67protected
68
69 def commit
70 DB.transaction do
71 sim = @sim_repo.available.sync
72 @sim_repo.put_owner(sim, @customer, self.class.label).sync
73 keepgo_tx = @sim_repo.refill(sim, amount_mb: 1024).sync
74 raise "SIM activation failed" unless keepgo_tx["ack"] == "success"
75
76 transaction(sim, keepgo_tx).insert_tx
77 sim
78 end
79 end
80
81 def transaction(sim, keepgo_tx)
82 Transaction.new(
83 customer_id: @customer.customer_id,
84 transaction_id: keepgo_tx["transaction_id"],
85 amount: -@price,
86 note: "#{self.class.label} Activation #{sim.iccid}"
87 )
88 end
89
90 class ESIM < SIMOrder
91 def self.label
92 "eSIM"
93 end
94
95 def self.fillable_fields
96 []
97 end
98
99 def complete(_)
100 EMPromise.resolve(nil).then { commit }.then do |sim|
101 Command.finish do |reply|
102 oob = OOB.find_or_create(reply.command)
103 oob.url = sim.lpa_code
104 oob.desc = "LPA Activation Code"
105 reply.command << FormTemplate.render(
106 "order_sim/esim_complete", sim: sim
107 )
108 end
109 end
110 end
111 end
112
113 class WithTopUp
114 def initialize(customer, continue, price:, plan:, top_up:)
115 @customer = customer
116 @price = price
117 @plan = plan
118 @top_up = top_up
119 @continue = continue
120 end
121
122 def form
123 FormTemplate.render(
124 "order_sim/with_top_up",
125 price: @price,
126 plan: @plan,
127 top_up_amount: @top_up.top_up_amount,
128 label: @continue.label,
129 fillable_fields: @continue.fillable_fields
130 )
131 end
132
133 def complete(iq)
134 @top_up.notify!.then do |amount|
135 if amount.positive?
136 @continue.new(@customer, price: @price, plan: @plan).complete(iq)
137 else
138 Command.finish("Could not top up", type: :error)
139 end
140 end
141 end
142 end
143
144 class PleaseTopUp
145 def initialize(price:, plan:)
146 @price = price
147 @plan = plan
148 end
149
150 def form
151 FormTemplate.render(
152 "order_sim/please_top_up",
153 price: @price,
154 plan: @plan
155 )
156 end
157
158 def complete(_)
159 Command.finish
160 end
161 end
162end