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