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