billing_monthly_cronjob

  1#!/usr/bin/ruby
  2# frozen_string_literal: true
  3
  4require "dhall"
  5require "pg"
  6
  7require_relative "../lib/blather_notify"
  8require_relative "../lib/to_form"
  9
 10CONFIG = Dhall.load(<<-DHALL).sync
 11	(#{ARGV[0]}) : {
 12		sgx_jmp: Text,
 13		notify_using: {
 14			jid: Text,
 15			password: Text,
 16			target: Text -> Text,
 17			body: Text -> Text -> Text
 18		}
 19	}
 20DHALL
 21
 22using ToForm
 23
 24db = PG.connect(dbname: "jmp")
 25db.type_map_for_results = PG::BasicTypeMapForResults.new(db)
 26db.type_map_for_queries = PG::BasicTypeMapForQueries.new(db)
 27
 28BlatherNotify.start(
 29	CONFIG[:notify_using][:jid],
 30	CONFIG[:notify_using][:password]
 31)
 32
 33def format(item)
 34	if item.respond_to?(:note) && item.note && item.note.text != ""
 35		item.note.text
 36	elsif item.respond_to?(:to_xml)
 37		item.to_xml
 38	else
 39		item.inspect
 40	end
 41end
 42
 43class ExpiringCustomer
 44	def initialize(customer_id)
 45		@customer_id = customer_id
 46	end
 47
 48	def info
 49		BlatherNotify.execute(
 50			"customer info",
 51			{ q: @customer_id }.to_form(:submit)
 52		).then do |iq|
 53			@sessionid = iq.sessionid
 54			unless iq.form.field("customer_id")
 55				raise "#{@customer_id} not found"
 56			end
 57
 58			iq
 59		end
 60	end
 61
 62	def next
 63		raise "Call info first" unless @sessionid
 64
 65		BlatherNotify.write_with_promise(BlatherNotify.command(
 66			"customer info",
 67			@sessionid
 68		))
 69	end
 70
 71	def bill_plan
 72		raise "Call info first" unless @sessionid
 73
 74		BlatherNotify.write_with_promise(BlatherNotify.command(
 75			"customer info",
 76			@sessionid,
 77			action: :complete,
 78			form: { action: "bill_plan" }.to_form(:submit)
 79		))
 80	end
 81end
 82
 83one = Queue.new
 84
 85EM::Iterator.new(db.exec(
 86	<<-SQL
 87	SELECT customer_id
 88	FROM customer_plans
 89	WHERE
 90		expires_at <= LOCALTIMESTAMP + '4 days' AND
 91		expires_at > LOCALTIMESTAMP - INTERVAL '1 month' AND (
 92			SELECT COUNT(*)
 93			FROM plan_log
 94			WHERE
 95				customer_id=customer_plans.customer_id AND
 96				UPPER(date_range) > LOCALTIMESTAMP + '4 days'
 97		) < 1;
 98	SQL
 99), 3).each(nil, -> { one << :done }) do |row, iter|
100	customer = ExpiringCustomer.new(row["customer_id"])
101	customer.info.then {
102		customer.next
103	}.then {
104		customer.bill_plan
105	}.then { |result|
106		puts format(result)
107		iter.next
108	}.catch do |err|
109		one << (err.is_a?(Exception) ? err : RuntimeError.new(format(err)))
110	end
111end
112
113result = one.pop
114raise result if result.is_a?(Exception)