registration.rb

  1# frozen_string_literal: true
  2
  3require "erb"
  4require "ruby-bandwidth-iris"
  5require "securerandom"
  6
  7require_relative "./alt_top_up_form"
  8require_relative "./bandwidth_tn_order"
  9require_relative "./bandwidth_tn_reservation_repo"
 10require_relative "./command"
 11require_relative "./em"
 12require_relative "./invites_repo"
 13require_relative "./oob"
 14require_relative "./parent_code_repo"
 15require_relative "./proxied_jid"
 16require_relative "./tel_selections"
 17require_relative "./welcome_message"
 18
 19class Registration
 20	def self.for(customer, google_play_userid, tel_selections)
 21		if (reg = customer.registered?)
 22			Registered.for(customer, reg.phone)
 23		else
 24			tel_selections[customer.jid].then(&:choose_tel).then do |tel|
 25				reserve_and_continue(tel_selections, customer, tel).then do
 26					FinishOrStartActivation.for(customer, google_play_userid, tel)
 27				end
 28			end
 29		end
 30	end
 31
 32	def self.reserve_and_continue(tel_selections, customer, tel)
 33		tel.reserve(customer).catch do
 34			tel_selections.delete(customer.jid).then {
 35				tel_selections[customer.jid]
 36			}.then { |choose|
 37				choose.choose_tel(
 38					error: "The JMP number #{tel} is no longer available."
 39				)
 40			}.then { |n_tel| reserve_and_continue(tel_selections, customer, n_tel) }
 41		end
 42	end
 43
 44	class Registered
 45		def self.for(customer, tel)
 46			jid = ProxiedJID.new(customer.jid).unproxied
 47			if jid.domain == CONFIG[:onboarding_domain]
 48				FinishOnboarding.for(customer, tel)
 49			else
 50				new(tel)
 51			end
 52		end
 53
 54		def initialize(tel)
 55			@tel = tel
 56		end
 57
 58		def write
 59			Command.finish("You are already registered with JMP number #{@tel}")
 60		end
 61	end
 62
 63	class FinishOrStartActivation
 64		def self.for(customer, google_play_userid, tel)
 65			if customer.active?
 66				Finish.new(customer, tel)
 67			elsif customer.balance >= CONFIG[:activation_amount_accept]
 68				BillPlan.new(customer, tel)
 69			else
 70				new(customer, google_play_userid, tel)
 71			end
 72		end
 73
 74		def initialize(customer, google_play_userid, tel)
 75			@customer = customer
 76			@tel = tel
 77			@google_play_userid = google_play_userid
 78		end
 79
 80		def write
 81			Command.reply { |reply|
 82				reply.allowed_actions = [:next]
 83				reply.note_type = :info
 84				reply.note_text = File.read("#{__dir__}/../fup.txt")
 85			}.then { Activation.for(@customer, @google_play_userid, @tel).write }
 86		end
 87	end
 88
 89	class Activation
 90		def self.for(customer, google_play_userid, tel)
 91			jid = ProxiedJID.new(customer.jid).unproxied
 92			if CONFIG[:approved_domains].key?(jid.domain.to_sym)
 93				Allow.for(customer, tel, jid)
 94			elsif google_play_userid
 95				GooglePlay.new(customer, google_play_userid, tel)
 96			else
 97				new(customer, tel)
 98			end
 99		end
100
101		def initialize(customer, tel)
102			@customer = customer
103			@tel = tel
104			@invites = InvitesRepo.new(DB, REDIS)
105		end
106
107		attr_reader :customer, :tel
108
109		def form
110			FormTemplate.render("registration/activate", tel: tel)
111		end
112
113		def write
114			Command.reply { |reply|
115				reply.allowed_actions = [:next]
116				reply.command << form
117			}.then(&method(:next_step))
118		end
119
120		def next_step(iq)
121			code = iq.form.field("code")&.value&.to_s
122			save_customer_plan(iq, code).then {
123				finish_if_valid_invite(code)
124			}.catch_only(InvitesRepo::Invalid) do
125				@invites.stash_code(customer.customer_id, code).then do
126					Payment.for(iq, @customer, @tel).then(&:write)
127				end
128			end
129		end
130
131	protected
132
133		def finish_if_valid_invite(code)
134			@invites.claim_code(@customer.customer_id, code) {
135				@customer.activate_plan_starting_now
136			}.then do
137				Finish.new(@customer, @tel).write
138			end
139		end
140
141		def save_customer_plan(iq, code)
142			ParentCodeRepo.new(redis: REDIS, db: DB).find(code).then do |parent|
143				plan = Plan.for_registration(iq.form.field("plan_name").value.to_s)
144				@customer = @customer.with_plan(plan.name, parent_customer_id: parent)
145				@customer.save_plan!
146			end
147		end
148
149		class GooglePlay
150			def initialize(customer, google_play_userid, tel)
151				@customer = customer
152				@google_play_userid = google_play_userid
153				@tel = tel
154				@invites = InvitesRepo.new(DB, REDIS)
155				@parent_code_repo = ParentCodeRepo.new(redis: REDIS, db: DB)
156			end
157
158			def used
159				REDIS.sismember("google_play_userids", @google_play_userid)
160			end
161
162			def form
163				FormTemplate.render(
164					"registration/google_play",
165					tel: @tel
166				)
167			end
168
169			def write
170				used.then do |u|
171					next Activation.for(@customer, nil, @tel).write if u.to_s == "1"
172
173					Command.reply { |reply|
174						reply.allowed_actions = [:next]
175						reply.command << form
176					}.then(&method(:activate)).then do
177						Finish.new(@customer, @tel).write
178					end
179				end
180			end
181
182			def activate(iq)
183				plan = Plan.for_registration(iq.form.field("plan_name").value)
184				code = iq.form.field("code")&.value
185				EMPromise.all([
186					@parent_code_repo.find(code),
187					REDIS.sadd("google_play_userids", @google_play_userid)
188				]).then { |(parent, _)|
189					save_active_plan(plan, parent)
190				}.then do
191					use_referral_code(code)
192				end
193			end
194
195		protected
196
197			def save_bogus_transaction
198				Transaction.new(
199					customer_id: @customer.customer_id,
200					transaction_id: "google_play_#{@customer.customer_id}",
201					amount: 0,
202					note: "Activated via Google Play",
203					bonus_eligible?: false
204				).insert
205			end
206
207			def save_active_plan(plan, parent)
208				@customer = @customer.with_plan(plan.name, parent_customer_id: parent)
209				save_bogus_transaction.then do
210					@customer.activate_plan_starting_now
211				end
212			end
213
214			def use_referral_code(code)
215				EMPromise.resolve(nil).then {
216					@invites.claim_code(@customer.customer_id, code) {
217						@customer.extend_plan
218					}
219				}.catch_only(InvitesRepo::Invalid) do
220					@invites.stash_code(@customer.customer_id, code)
221				end
222			end
223		end
224
225		class Allow < Activation
226			def self.for(customer, tel, jid)
227				credit_to = CONFIG[:approved_domains][jid.domain.to_sym]
228				new(customer, tel, credit_to)
229			end
230
231			def initialize(customer, tel, credit_to)
232				super(customer, tel)
233				@credit_to = credit_to
234			end
235
236			def form
237				FormTemplate.render(
238					"registration/allow",
239					tel: tel,
240					domain: customer.jid.domain
241				)
242			end
243
244			def next_step(iq)
245				plan = Plan.for_registration(iq.form.field("plan_name").value.to_s)
246				@customer = customer.with_plan(plan.name)
247				EMPromise.resolve(nil).then { activate }.then do
248					Finish.new(customer, tel).write
249				end
250			end
251
252		protected
253
254			def activate
255				DB.transaction do
256					if @credit_to
257						InvitesRepo.new(DB, REDIS).create_claimed_code(
258							@credit_to,
259							customer.customer_id
260						)
261					end
262					@customer.activate_plan_starting_now
263				end
264			end
265		end
266	end
267
268	module Payment
269		def self.kinds
270			@kinds ||= {}
271		end
272
273		def self.for(iq, customer, tel, final_message: nil, finish: Finish)
274			kinds.fetch(iq.form.field("activation_method")&.value&.to_s&.to_sym) {
275				raise "Invalid activation method"
276			}.call(customer, tel, final_message: final_message, finish: finish)
277		end
278
279		class CryptoPaymentMethod
280			def crypto_addrs
281				raise NotImplementedError, "Subclass must implement"
282			end
283
284			def reg_form_name
285				raise NotImplementedError, "Subclass must implement"
286			end
287
288			def sell_prices
289				raise NotImplementedError, "Subclass must implement"
290			end
291
292			def initialize(customer, tel, final_message: nil, **)
293				@customer = customer
294				@customer_id = customer.customer_id
295				@tel = tel
296				@final_message = final_message
297			end
298
299			def save
300				TEL_SELECTIONS.set(@customer.jid, @tel)
301			end
302
303			attr_reader :customer_id, :tel
304
305			def form(rate, addr)
306				amount = CONFIG[:activation_amount] / rate
307
308				FormTemplate.render(
309					reg_form_name,
310					amount: amount,
311					addr: addr,
312					final_message: @final_message
313				)
314			end
315
316			def write
317				EMPromise.all([addr_and_rate, save]).then do |((addr, rate), _)|
318					Command.reply { |reply|
319						reply.allowed_actions = [:prev]
320						reply.status = :canceled
321						reply.command << form(rate, addr)
322					}.then(&method(:handle_possible_prev))
323				end
324			end
325		protected
326			def handle_possible_prev(iq)
327				raise "Action not allowed" unless iq.prev?
328
329				Activation.for(@customer, nil, @tel).then(&:write)
330			end
331
332			def addr_and_rate
333				EMPromise.all([
334					self.crypto_addrs.then { |addrs|
335						addrs.first || self.add_crypto_addr
336					},
337
338					sell_prices.public_send(@customer.currency.to_s.downcase)
339				])
340			end
341		end
342
343		class Bitcoin < CryptoPaymentMethod
344			Payment.kinds[:bitcoin] = method(:new)
345
346			def reg_form_name
347				"registration/btc"
348			end
349
350			def sell_prices
351				BTC_SELL_PRICES
352			end
353
354			def crypto_addrs
355				@customer.btc_addresses
356			end
357
358			def add_crypto_addr
359				@customer.add_btc_address
360			end
361		end
362
363		## Like Bitcoin
364		class BCH < CryptoPaymentMethod
365			Payment.kinds[:bch] = method(:new)
366
367			def reg_form_name
368				"registration/bch"
369			end
370
371			def sell_prices
372				BCH_SELL_PRICES
373			end
374
375			def crypto_addrs
376				@customer.bch_addresses
377			end
378
379			def add_crypto_addr
380				@customer.add_bch_address
381			end
382		end
383
384
385		class CreditCard
386			Payment.kinds[:credit_card] = ->(*args, **kw) { self.for(*args, **kw) }
387
388			def self.for(in_customer, tel, finish: Finish, **)
389				reload_customer(in_customer).then do |(customer, payment_methods)|
390					if customer.balance >= CONFIG[:activation_amount_accept]
391						next BillPlan.new(customer, tel, finish: finish)
392					end
393
394					if (method = payment_methods.default_payment_method)
395						next Activate.new(customer, method, tel, finish: finish)
396					end
397
398					new(customer, tel, finish: finish)
399				end
400			end
401
402			def self.reload_customer(customer)
403				EMPromise.all([
404					Command.execution.customer_repo.find(customer.customer_id),
405					customer.payment_methods
406				])
407			end
408
409			def initialize(customer, tel, finish: Finish)
410				@customer = customer
411				@tel = tel
412				@finish = finish
413			end
414
415			def oob(reply)
416				oob = OOB.find_or_create(reply.command)
417				oob.url = CONFIG[:credit_card_url].call(
418					reply.to.stripped.to_s.gsub("\\", "%5C"),
419					@customer.customer_id
420				) + "&amount=#{CONFIG[:activation_amount]}"
421				oob.desc = "Add credit card, save, then next here to continue"
422				oob
423			end
424
425			def write
426				Command.reply { |reply|
427					reply.allowed_actions = [:next, :prev]
428					toob = oob(reply)
429					reply.note_type = :info
430					reply.note_text = "#{toob.desc}: #{toob.url}"
431				}.then do |iq|
432					next Activation.for(@customer, nil, @tel).then(&:write) if iq.prev?
433
434					CreditCard.for(@customer, @tel, finish: @finish).then(&:write)
435				end
436			end
437
438			class Activate
439				def initialize(customer, payment_method, tel, finish: Finish)
440					@customer = customer
441					@payment_method = payment_method
442					@tel = tel
443					@finish = finish
444				end
445
446				def write
447					CreditCardSale.create(
448						@customer,
449						amount: CONFIG[:activation_amount],
450						payment_method: @payment_method
451					).then(
452						->(_) { sold },
453						->(_) { declined }
454					)
455				end
456
457			protected
458
459				def sold
460					BillPlan.new(@customer, @tel, finish: @finish).write
461				end
462
463				DECLINE_MESSAGE =
464					"Your bank declined the transaction. " \
465					"Often this happens when a person's credit card " \
466					"is a US card that does not support international " \
467					"transactions, as JMP is not based in the USA, though " \
468					"we do support transactions in USD.\n\n" \
469					"You may add another card"
470
471				def decline_oob(reply)
472					oob = OOB.find_or_create(reply.command)
473					oob.url = CONFIG[:credit_card_url].call(
474						reply.to.stripped.to_s.gsub("\\", "%5C"),
475						@customer.customer_id
476					) + "&amount=#{CONFIG[:activation_amount]}"
477					oob.desc = DECLINE_MESSAGE
478					oob
479				end
480
481				def declined
482					Command.reply { |reply|
483						reply_oob = decline_oob(reply)
484						reply.allowed_actions = [:next]
485						reply.note_type = :error
486						reply.note_text = "#{reply_oob.desc}: #{reply_oob.url}"
487					}.then do
488						CreditCard.for(@customer, @tel, finish: @finish).then(&:write)
489					end
490				end
491			end
492		end
493
494		class InviteCode
495			Payment.kinds[:code] = ->(*args, **kw) { self.for(*args, **kw) }
496
497			def self.for(in_customer, tel, finish: Finish, **)
498				reload_customer(in_customer).then do |customer|
499					if customer.balance >= CONFIG[:activation_amount_accept]
500						next BillPlan.new(customer, tel, finish: finish)
501					end
502
503					msg = if customer.balance.positive?
504						"Account balance not enough to cover the activation"
505					end
506					new(customer, tel, error: msg, finish: Finish)
507				end
508			end
509
510			def self.reload_customer(customer)
511				Command.execution.customer_repo.find(customer.customer_id)
512			end
513
514			FIELDS = [{
515				var: "code",
516				type: "text-single",
517				label: "Your referral code",
518				required: true
519			}].freeze
520
521			def initialize(customer, tel, error: nil, finish: Finish, **)
522				@customer = customer
523				@tel = tel
524				@error = error
525				@finish = finish
526				@parent_code_repo = ParentCodeRepo.new(redis: REDIS, db: DB)
527			end
528
529			def add_form(reply)
530				form = reply.form
531				form.type = :form
532				form.title = "Enter Referral Code"
533				form.instructions = @error if @error
534				form.fields = FIELDS
535			end
536
537			def write
538				Command.reply { |reply|
539					reply.allowed_actions = [:next, :prev]
540					add_form(reply)
541				}.then(&method(:parse))
542			end
543
544			def parse(iq)
545				return Activation.for(@customer, nil, @tel).then(&:write) if iq.prev?
546
547				verify(iq.form.field("code")&.value&.to_s)
548					.catch_only(InvitesRepo::Invalid, &method(:invalid_code))
549					.then(&:write)
550			end
551
552		protected
553
554			def invalid_code(e)
555				InviteCode.new(@customer, @tel, error: e.message)
556			end
557
558			def customer_id
559				@customer.customer_id
560			end
561
562			def verify(code)
563				@parent_code_repo.find(code).then do |parent_customer_id|
564					if parent_customer_id
565						set_parent(parent_customer_id)
566					else
567						InvitesRepo.new(DB, REDIS).claim_code(customer_id, code) {
568							@customer.activate_plan_starting_now
569						}.then { Finish.new(@customer, @tel) }
570					end
571				end
572			end
573
574			def set_parent(parent_customer_id)
575				@customer = @customer.with_plan(
576					@customer.plan_name,
577					parent_customer_id: parent_customer_id
578				)
579				@customer.save_plan!.then do
580					self.class.for(@customer, @tel, finish: @finish)
581				end
582			end
583		end
584
585		class Mail
586			Payment.kinds[:mail] = method(:new)
587
588			def initialize(customer, tel, final_message: nil, **)
589				@customer = customer
590				@tel = tel
591				@final_message = final_message
592			end
593
594			def form
595				FormTemplate.render(
596					"registration/mail",
597					currency: @customer.currency,
598					final_message: @final_message,
599					**onboarding_extras
600				)
601			end
602
603			def onboarding_extras
604				jid = ProxiedJID.new(@customer.jid).unproxied
605				return {} unless jid.domain == CONFIG[:onboarding_domain]
606
607				{
608					customer_id: @customer.customer_id,
609					in_note: "Customer ID"
610				}
611			end
612
613			def write
614				Command.reply { |reply|
615					reply.allowed_actions = [:prev]
616					reply.status = :canceled
617					reply.command << form
618				}.then { |iq|
619					raise "Action not allowed" unless iq.prev?
620
621					Activation.for(@customer, nil, @tel).then(&:write)
622				}
623			end
624		end
625	end
626
627	class BillPlan
628		def initialize(customer, tel, finish: Finish)
629			@customer = customer
630			@tel = tel
631			@finish = finish
632		end
633
634		def write
635			@customer.bill_plan(note: "Bill #{@tel} for first month").then do
636				@finish.new(@customer, @tel).write
637			end
638		end
639	end
640
641	class Finish
642		def initialize(customer, tel)
643			@customer = customer
644			@tel = tel
645			@invites = InvitesRepo.new(DB, REDIS)
646		end
647
648		def write
649			@tel.order(DB, @customer).then(
650				->(_) { customer_active_tel_purchased },
651				method(:number_purchase_error)
652			)
653		end
654
655	protected
656
657		def number_purchase_error(e)
658			Command.log.error "number_purchase_error", e
659			TEL_SELECTIONS.delete(@customer.jid).then {
660				TEL_SELECTIONS[@customer.jid]
661			}.then { |choose|
662				choose.choose_tel(
663					error: "The JMP number #{@tel} is no longer available."
664				)
665			}.then { |tel| Finish.new(@customer, tel).write }
666		end
667
668		def raise_setup_error(e)
669			Command.log.error "@customer.register! failed", e
670			Command.finish(
671				"There was an error setting up your number, " \
672				"please contact JMP support.",
673				type: :error
674			)
675		end
676
677		def put_default_fwd
678			Bwmsgsv2Repo.new.put_fwd(@customer.customer_id, @tel.tel, CustomerFwd.for(
679				uri: "xmpp:#{@customer.jid}",
680				voicemail_enabled: true
681			))
682		end
683
684		def use_referral_code
685			@invites.use_pending_group_code(@customer.customer_id).then do |credit_to|
686				next unless credit_to
687
688				Transaction.new(
689					customer_id: @customer.customer_id,
690					transaction_id: "referral_#{@customer.customer_id}_#{credit_to}",
691					amount: @customer.monthly_price,
692					note: "Referral Bonus",
693					bonus_eligible?: false
694				).insert
695			end
696		end
697
698		def customer_active_tel_purchased
699			@customer.register!(@tel.tel).catch(&method(:raise_setup_error)).then {
700				EMPromise.all([
701					TEL_SELECTIONS.delete(@customer.jid),
702					put_default_fwd,
703					use_referral_code
704				])
705			}.then do
706				FinishOnboarding.for(@customer, @tel).then(&:write)
707			end
708		end
709	end
710
711	module FinishOnboarding
712		def self.for(customer, tel, db: LazyObject.new { DB })
713			jid = ProxiedJID.new(customer.jid).unproxied
714			if jid.domain == CONFIG[:onboarding_domain]
715				Snikket.for(customer, tel, db: db)
716			else
717				NotOnboarding.new(customer, tel)
718			end
719		end
720
721		class Snikket
722			def self.for(customer, tel, db:)
723				::Snikket::Repo.new(db: db).find_by_customer(customer).then do |is|
724					if is.empty?
725						new(customer, tel, db: db)
726					elsif is[0].bootstrap_token.empty?
727						# This is a need_dns one, try the launch again
728						new(customer, tel, db: db).launch(is[0].domain)
729					else
730						GetInvite.for(customer, is[0], tel, db: db)
731					end
732				end
733			end
734
735			def initialize(customer, tel, error: nil, old: nil, db:)
736				@customer = customer
737				@tel = tel
738				@error = error
739				@db = db
740				@old = old
741			end
742
743			ACTION_VAR = "http://jabber.org/protocol/commands#actions"
744
745			def form
746				FormTemplate.render(
747					"registration/snikket",
748					tel: @tel,
749					error: @error
750				)
751			end
752
753			def write
754				Command.reply { |reply|
755					reply.allowed_actions = [:next]
756					reply.command << form
757				}.then(&method(:next_step))
758			end
759
760			def next_step(iq)
761				subdomain = empty_nil(iq.form.field("subdomain")&.value)
762				domain = "#{subdomain}.snikket.chat"
763				if iq.form.field(ACTION_VAR)&.value == "custom_domain"
764					CustomDomain.new(@customer, @tel, old: @old).write
765				elsif @old && (!subdomain || domain == @old.domain)
766					GetInvite.for(@customer, @old, @tel, db: @db).then(&:write)
767				else
768					launch(domain)
769				end
770			end
771
772			def launch(domain)
773				IQ_MANAGER.write(::Snikket::Launch.new(
774					nil, CONFIG[:snikket_hosting_api], domain: domain
775				)).then { |launched|
776					save_instance_and_wait(domain, launched)
777				}.catch { |e|
778					next EMPromise.reject(e) unless e.respond_to?(:text)
779
780					Snikket.new(@customer, @tel, old: @old, error: e.text, db: @db).write
781				}
782			end
783
784			def save_instance_and_wait(domain, launched)
785				instance = ::Snikket::CustomerInstance.for(@customer, domain, launched)
786				repo = ::Snikket::Repo.new(db: @db)
787				(@old&.domain == domain ? EMPromise.resolve(nil) : repo.del(@old))
788					.then { repo.put(instance) }.then do
789						if launched.status == :needs_dns
790							NeedsDNS.new(@customer, instance, @tel, launched.records).write
791						else
792							GetInvite.for(@customer, instance, @tel, db: @db).then(&:write)
793						end
794					end
795			end
796
797			def empty_nil(s)
798				s.nil? || s.empty? ? nil : s
799			end
800
801			class NeedsDNS < Snikket
802				def initialize(customer, instance, tel, records, db: DB)
803					@customer = customer
804					@instance = instance
805					@tel = tel
806					@records = records
807					@db = db
808				end
809
810				def form
811					FormTemplate.render(
812						"registration/snikket_needs_dns",
813						records: @records
814					)
815				end
816
817				def write
818					Command.reply { |reply|
819						reply.allowed_actions = [:prev, :next]
820						reply.command << form
821					}.then do |iq|
822						if iq.prev?
823							CustomDomain.new(@customer, @tel, old: @instance).write
824						else
825							launch(@instance.domain)
826						end
827					end
828				end
829			end
830
831			class GetInvite
832				def self.for(customer, instance, tel, db: DB)
833					instance.fetch_invite.then do |xmpp_uri|
834						if xmpp_uri
835							GoToInvite.new(xmpp_uri)
836						else
837							new(customer, instance, tel, db: db)
838						end
839					end
840				end
841
842				def initialize(customer, instance, tel, db: DB)
843					@customer = customer
844					@instance = instance
845					@tel = tel
846					@db = db
847				end
848
849				def form
850					FormTemplate.render(
851						"registration/snikket_wait",
852						domain: @instance.domain
853					)
854				end
855
856				def write
857					Command.reply { |reply|
858						reply.allowed_actions = [:prev, :next]
859						reply.command << form
860					}.then do |iq|
861						if iq.prev?
862							Snikket.new(@customer, @tel, old: @instance, db: @db).write
863						else
864							GetInvite.for(@customer, @instance, @tel, db: @db).then(&:write)
865						end
866					end
867				end
868			end
869
870			class GoToInvite
871				def initialize(xmpp_uri)
872					@xmpp_uri = xmpp_uri
873				end
874
875				def write
876					Command.finish do |reply|
877						oob = OOB.find_or_create(reply.command)
878						oob.url = @xmpp_uri
879					end
880				end
881			end
882		end
883
884		class CustomDomain < Snikket
885			def initialize(customer, tel, old: nil, error: nil, db: DB)
886				@customer = customer
887				@tel = tel
888				@error = error
889				@old = old
890				@db = db
891			end
892
893			def form
894				FormTemplate.render(
895					"registration/snikket_custom",
896					tel: @tel,
897					error: @error
898				)
899			end
900
901			def write
902				Command.reply { |reply|
903					reply.allowed_actions = [:prev, :next]
904					reply.command << form
905				}.then do |iq|
906					if iq.prev?
907						Snikket.new(@customer, @tel, db: @db, old: @old).write
908					else
909						launch(empty_nil(iq.form.field("domain")&.value) || @old&.domain)
910					end
911				end
912			end
913		end
914
915		class NotOnboarding
916			def initialize(customer, tel)
917				@customer = customer
918				@tel = tel
919			end
920
921			def write
922				WelcomeMessage.new(@customer, @tel).welcome
923				Command.finish("Your JMP account has been activated as #{@tel}")
924			end
925		end
926	end
927end