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