1# frozen_string_literal: true
  2
  3require "bigdecimal/util"
  4require "securerandom"
  5require "time"
  6require "value_semantics/monkey_patched"
  7
  8require_relative "../admin_action"
  9require_relative "../form_to_h"
 10
 11class AdminAction
 12	class AddTransaction < AdminAction
 13		class Command
 14			using FormToH
 15
 16			def self.for(target_customer, reply:)
 17				time = DateTime.now.iso8601
 18				EMPromise.resolve(
 19					new(
 20						customer_id: target_customer.customer_id,
 21						created_at: time, settled_after: time
 22					)
 23				).then { |x|
 24					reply.call(x.form).then(&x.method(:create))
 25				}
 26			end
 27
 28			def initialize(**bag)
 29				@bag = bag
 30			end
 31
 32			def form
 33				FormTemplate.render("admin_add_transaction")
 34			end
 35
 36			def create(result)
 37				hash = result.form.to_h
 38					.reject { |_k, v| v == "nil" }.transform_keys(&:to_sym)
 39				hash[:transaction_id] = hash[:transaction_id]
 40					.sub("%", SecureRandom.uuid)
 41
 42				AdminAction::AddTransaction.for(
 43					**@bag,
 44					**hash
 45				)
 46			end
 47		end
 48
 49		TransactionExists = Struct.new(:transaction_id) do
 50			def to_s
 51				"The transaction #{transaction_id} already exists"
 52			end
 53		end
 54
 55		TransactionDoesNotExist = Struct.new(:transaction_id) do
 56			def to_s
 57				"The transaction #{transaction_id} doesn't exist"
 58			end
 59		end
 60
 61		def customer_id
 62			@attributes[:customer_id]
 63		end
 64
 65		def amount
 66			@attributes[:amount].to_d
 67		end
 68
 69		def transaction_id
 70			@attributes[:transaction_id]
 71		end
 72
 73		def created_at
 74			@attributes[:created_at]
 75		end
 76
 77		def settled_after
 78			@attributes[:settled_after]
 79		end
 80
 81		def note
 82			@attributes[:note]
 83		end
 84
 85		def bonus_eligible?
 86			["1", "true"].include?(@attributes[:bonus_eligible?])
 87		end
 88
 89		def transaction
 90			@transaction ||= Transaction.new(
 91				**@attributes.slice(:customer_id, :transaction_id, :amount, :note),
 92				created_at: created_at, settled_after: settled_after,
 93				bonus_eligible?: bonus_eligible?
 94			)
 95		end
 96
 97		def check_forward
 98			EMPromise.resolve(nil)
 99				.then { check_noop }
100				.then { transaction.exists? }
101				.then { |e|
102					EMPromise.reject(TransactionExists.new(transaction_id)) if e
103				}
104		end
105
106		def check_reverse
107			EMPromise.resolve(nil)
108				.then { check_noop }
109				.then { transaction.exists? }
110				.then { |e|
111					EMPromise.reject(TransactionDoesNotExist.new(transaction_id)) unless e
112				}
113		end
114
115		def to_s
116			"add_transaction(#{customer_id}): #{note} (#{transaction_id}) "\
117			"#{transaction}"
118		end
119
120		def forward
121			transaction.insert.then {
122				self
123			}
124		end
125
126		def reverse
127			transaction.delete.then {
128				self
129			}
130		end
131
132	protected
133
134		def check_noop
135			EMPromise.reject(NoOp.new) if amount.zero?
136		end
137	end
138end