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