admin_command.rb

  1# frozen_string_literal: true
  2
  3require_relative "admin_action_repo"
  4require_relative "admin_actions/cancel"
  5require_relative "admin_actions/financial"
  6require_relative "bill_plan_command"
  7require_relative "customer_info_form"
  8require_relative "financial_info"
  9require_relative "form_template"
 10
 11class AdminCommand
 12	def self.for(
 13		target_customer,
 14		customer_repo,
 15		admin_action_repo=AdminActionRepo.new
 16	)
 17		if target_customer
 18			new(target_customer, customer_repo, admin_action_repo)
 19		else
 20			Command.reply { |reply|
 21				reply.allowed_actions = [:next, :complete]
 22				reply.note_type = :error
 23				reply.note_text = "Customer Not Found"
 24			}.then { NoUser.new(customer_repo, admin_action_repo) }
 25		end
 26	end
 27
 28	class NoUser
 29		def initialize(customer_repo, admin_action_repo=AdminActionRepo.new)
 30			@customer_repo = customer_repo
 31			@admin_action_repo = admin_action_repo
 32		end
 33
 34		def start
 35			Command.reply { |reply|
 36				reply.allowed_actions = [:next]
 37				reply.command << FormTemplate.render("customer_picker")
 38			}.then { |response|
 39				CustomerInfoForm.new(@customer_repo).find_customer(response)
 40			}.then { |customer|
 41				AdminCommand.for(customer, @customer_repo, @admin_action_repo)
 42					.then(&:start)
 43			}
 44		end
 45	end
 46
 47	def initialize(
 48		target_customer,
 49		customer_repo,
 50		admin_action_repo=AdminActionRepo.new
 51	)
 52		@target_customer = target_customer
 53		@customer_repo = customer_repo
 54		@admin_action_repo = admin_action_repo
 55	end
 56
 57	def start
 58		@target_customer.admin_info.then { |info|
 59			reply(info.form)
 60		}.then { menu_or_done }
 61	end
 62
 63	def reply(form)
 64		Command.reply { |reply|
 65			reply.allowed_actions = [:next, :complete]
 66			reply.command << form
 67		}
 68	end
 69
 70	def menu_or_done(command_action=:execute)
 71		return Command.finish("Done") if command_action == :complete
 72
 73		reply(FormTemplate.render("admin_menu")).then do |response|
 74			if response.form.field("action")
 75				handle(response.form.field("action").value, response.action)
 76			end
 77		end
 78	end
 79
 80	def handle(action, command_action)
 81		if respond_to?("action_#{action}")
 82			send("action_#{action}")
 83		else
 84			new_context(action)
 85		end.then { menu_or_done(command_action) }
 86	end
 87
 88	def new_context(q)
 89		CustomerInfoForm.new(@customer_repo)
 90			.parse_something(q).then do |new_customer|
 91				AdminCommand.for(new_customer, @customer_repo, @admin_action_repo)
 92					.then(&:start)
 93			end
 94	end
 95
 96	def action_info
 97		# Refresh the data
 98		new_context(@target_customer.customer_id)
 99	end
100
101	def action_bill_plan
102		BillPlanCommand.for(@target_customer).call
103	end
104
105	class Undoable
106		def initialize(klass)
107			@klass = klass
108		end
109
110		def call(customer, admin_action_repo:, **)
111			@klass.for(customer, reply: method(:reply)).then { |action|
112				Command.customer.then { |actor|
113					action.with(actor_id: actor.customer_id).perform.then do |performed|
114						admin_action_repo.create(performed)
115					end
116				}
117			}.then(method(:success), method(:failure))
118		end
119
120		def reply(form=nil, note_type: nil, note_text: nil)
121			Command.reply { |reply|
122				reply.allowed_actions = [:next, :complete]
123				reply.command << form if form
124				reply.note_type = note_type if note_type
125				reply.note_text = note_text if note_text
126			}
127		end
128
129		def success(action)
130			reply(note_type: :info, note_text: "Action #{action.id}: #{action}")
131		end
132
133		def failure(err)
134			LOG.error "Action Failure", err
135			reply(note_type: :error, note_text: "Action Failed: #{err}")
136		end
137	end
138
139	class Simple
140		def initialize(klass)
141			@klass = klass
142		end
143
144		def call(customer_id, customer_repo:, **)
145			@klass.call(
146				customer_id,
147				reply: method(:reply),
148				customer_repo: customer_repo
149			)
150		end
151
152		def reply(form=nil, note_type: nil, note_text: nil)
153			Command.reply { |reply|
154				reply.allowed_actions = [:next, :complete]
155				reply.command << form if form
156				reply.note_type = note_type if note_type
157				reply.note_text = note_text if note_text
158			}
159		end
160	end
161
162	class Undo
163		def self.for(target_customer, **)
164			AdminActionRepo.new
165				.find(1, customer_id: target_customer.customer_id)
166				.then { |actions|
167					raise "No actions found" if actions.empty?
168
169					actions.first.undo
170				}
171		end
172	end
173
174	[
175		[:cancel_account, Simple.new(AdminAction::CancelCustomer)],
176		[:financial, Simple.new(AdminAction::Financial)],
177		[:undo, Undoable.new(Undo)]
178	].each do |action, handler|
179		define_method("action_#{action}") do
180			handler.call(
181				@target_customer,
182				admin_action_repo: @admin_action_repo,
183				customer_repo: @customer_repo
184			)
185		end
186	end
187end