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