sim_order.rb

  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