# frozen_string_literal: true require_relative "./oob" class Registration def self.for(iq, customer, web_register_manager) EMPromise.resolve(customer&.registered?).then do |registered| if registered Registered.new(iq, registered.phone) else web_register_manager.choose_tel(iq).then do |(riq, tel)| Activation.for(riq, customer, tel) end end end end class Registered def initialize(iq, tel) @reply = iq.reply @reply.status = :completed @tel = tel end def write @reply.note_type = :error @reply.note_text = <<~NOTE You are already registered with JMP number #{@tel} NOTE BLATHER << @reply nil end end class Activation def self.for(iq, customer, tel) if customer&.active? Finish.new(iq, customer, tel) elsif customer EMPromise.resolve(new(iq, customer, tel)) else # Create customer_id raise "TODO" end end def initialize(iq, customer, tel) @reply = iq.reply reply.allowed_actions = [:next] @customer = customer @tel = tel end attr_reader :reply, :customer, :tel FORM_FIELDS = [ { var: "activation_method", type: "list-single", label: "Activate using", required: true, options: [ { value: "bitcoin", label: "Bitcoin" }, { value: "credit_card", label: "Credit Card ($#{CONFIG[:activation_amount]})" }, { value: "code", label: "Referral or Activation Code" } ] }, { var: "plan_name", type: "list-single", label: "What currency should your account balance be in?", required: true, options: [ { value: "cad_beta_unlimited-v20210223", label: "Canadian Dollars" }, { value: "usd_beta_unlimited-v20210223", label: "United States Dollars" } ] } ].freeze def write form = reply.form form.type = :form form.title = "Activate JMP" form.instructions = "Going to activate #{tel} (TODO RATE CTR)" form.fields = FORM_FIELDS COMMAND_MANAGER.write(reply).then { |iq| Payment.for(iq, customer, tel) }.then(&:write) end end module Payment def self.kinds @kinds ||= {} end def self.for(iq, customer, tel) plan_name = iq.form.field("plan_name").value.to_s customer = customer.with_plan(plan_name) kinds.fetch(iq.form.field("activation_method")&.value&.to_s&.to_sym) { raise "Invalid activation method" }.call(iq, customer, tel) end class Bitcoin Payment.kinds[:bitcoin] = method(:new) def initialize(iq, customer, tel) @reply = iq.reply reply.note_type = :info reply.status = :completed @customer = customer @customer_id = customer.customer_id @tel = tel @addr = ELECTRUM.createnewaddress end attr_reader :reply, :customer_id, :tel def save EMPromise.all([ REDIS.mset( "pending_tel_for-#{customer_id}", tel, "pending_plan_for-#{customer_id}", @customer.plan_name ), @addr.then do |addr| REDIS.sadd("jmp_customer_btc_addresses-#{customer_id}", addr) end ]) end def note_text(amount, addr) <<~NOTE Activate your account by sending at least #{'%.6f' % amount} BTC to #{addr} You will receive a notification when your payment is complete. NOTE end def write EMPromise.all([ @addr, save, BTC_SELL_PRICES.public_send(@customer.currency.to_s.downcase) ]).then do |(addr, _, rate)| min = CONFIG[:activation_amount] / rate reply.note_text = note_text(min, addr) BLATHER << reply nil end end end class CreditCard Payment.kinds[:credit_card] = ->(*args) { self.for(*args) } def self.for(iq, customer, tel) customer.payment_methods.then do |payment_methods| if (method = payment_methods.default_payment_method) Activate.new(iq, customer, method, tel) else new(iq, customer, tel) end end end def initialize(iq, customer, tel) @customer = customer @tel = tel @reply = iq.reply @reply.allowed_actions = [:next] @reply.note_type = :info @reply.note_text = "#{oob.desc}: #{oob.url}" end attr_reader :reply def oob oob = OOB.find_or_create(@reply.command) oob.url = CONFIG[:credit_card_url].call( @reply.to.stripped.to_s, @customer.customer_id ) oob.desc = "Add credit card, then return here and choose next" oob end def write COMMAND_MANAGER.write(@reply).then do |riq| CreditCard.for(riq, @customer, @tel) end end class Activate def initialize(iq, customer, payment_method, tel) @iq = iq @customer = customer @payment_method = payment_method @tel = tel end def write Transaction.sale( @customer, CONFIG[:activation_amount], @payment_method ).then( method(:sold), ->(_) { declined } ) end protected def sold(tx) tx.insert.then { @customer.bill_plan }.then do Finish.new(@iq, @customer, @tel).write end end DECLINE_MESSAGE = "Your bank declined the transaction. " \ "Often this happens when a person's credit card " \ "is a US card that does not support international " \ "transactions, as JMP is not based in the USA, though " \ "we do support transactions in USD.\n\n" \ "If you were trying a prepaid card, you may wish to use "\ "Privacy.com instead, as they do support international " \ "transactions.\n\n " \ "You may add another card and then choose next" def decline_oob(reply) oob = OOB.find_or_create(reply.command) oob.url = CONFIG[:credit_card_url].call( reply.to.stripped.to_s, @customer.customer_id ) oob.desc = DECLINE_MESSAGE oob end def declined reply = @iq.reply reply_oob = decline_oob(reply) reply.allowed_actions = [:next] reply.note_type = :error reply.note_text = "#{reply_oob.desc}: #{reply_oob.url}" COMMAND_MANAGER.write(reply).then do |riq| CreditCard.for(riq, @customer, @tel) end end end end end class Finish def initialize(iq, customer, tel) @reply = iq.reply @reply.status = :completed @reply.note_type = :info @reply.note_text = "Your JMP account has been activated as #{tel}" @customer = customer @tel = tel end def write BandwidthTNOrder.create(@tel).then(&:poll).then( ->(_) { @customer.register!(@tel).then { BLATHER << @reply } }, lambda do |_| @reply.note_type = :error @reply.note_text = "The JMP number #{@tel} is no longer available, " \ "please visit https://jmp.chat and choose another." BLATHER << @reply end ) end end end