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)