9d313c5f |
1 | structure Remind :> REMIND = |
2 | struct |
3 | |
4 | open Config |
5 | |
6 | structure C = PgClient |
7 | |
a47ac708 |
8 | fun printReal n = |
9 | if n < 0.0 then |
10 | "-" ^ Real.fmt (StringCvt.FIX (SOME 2)) (~n) |
11 | else |
12 | Real.fmt (StringCvt.FIX (SOME 2)) n |
13 | |
9d313c5f |
14 | fun main _ = |
15 | let |
16 | val db = C.conn dbstring |
17 | |
a47ac708 |
18 | val totalShares = case C.oneRow db "SELECT SUM(shares) FROM WebUserPaying" of |
19 | [total] => C.intFromSql total |
20 | | _ => raise Fail "Bad SUM(shares) row" |
21 | |
22 | fun doOne [user, members, shares, amount] = |
23 | let |
24 | val user = C.stringFromSql user |
25 | val members = C.intFromSql members |
26 | val shares = C.intFromSql shares |
27 | val amount = C.realFromSql amount |
28 | |
29 | val minimum = 900.0 * real shares / real totalShares * 2.0 |
30 | in |
31 | if amount >= minimum then |
32 | () |
33 | else |
34 | let |
35 | val m = Mail.mopen () |
36 | fun write msg = Mail.mwrite (m, msg) |
37 | in |
38 | if amount < 0.0 then |
39 | write "Subject: Your NEGATIVE HCoop balance\n" |
40 | else |
41 | write "Subject: Your low HCoop balance\n"; |
42 | write "From: HCoop Payment Reminder Robot <payment"; |
43 | write emailSuffix; |
44 | write ">\n"; |
45 | write "To: "; |
46 | write user; |
47 | write emailSuffix; |
48 | write "\nCc: payment@hcoop.net"; |
49 | write "\n\n"; |
50 | |
51 | if amount < 0.0 then |
52 | (write "Your HCoop balance is negative. This means that you've paid less than you've\n"; |
53 | write "been charged to date. Our bylaws allow our board of directors to vote you out\n"; |
54 | write "of the co-op, without any obligation to contact you first, when your balance\n"; |
55 | write "stays negative for three months. Please make a payment as soon as possible, so\n"; |
56 | write "that we don't need to do this!\n\n") |
57 | else |
58 | (write "Your HCoop balance has dropped below your requested minimum, based on your\n"; |
59 | write "sliding scale pledge amount. Please make a payment as soon as you can.\n\n"); |
60 | |
61 | write "Your balance: US$"; |
62 | write (printReal amount); |
63 | write "\nTotal number of members linked to your balance: "; |
64 | write (Int.toString members); |
65 | write "\nTotal pledge amount: "; |
66 | write (Int.toString shares); |
67 | write "\nRequested minimum: US$"; |
68 | write (printReal (900.0 * real shares / real totalShares * 2.0)); |
9d313c5f |
69 | |
a47ac708 |
70 | write "\n\nYour minimum was calculated by dividing our total monthly expenses ($900) by the\n"; |
71 | write "sum of all members' pledge amounts, multiplying by your pledge amount, and then\n"; |
72 | write "multiplying by 2. That is, the amount covers your share of two months' expenses.\n\n"; |
9d313c5f |
73 | |
a47ac708 |
74 | write "To make a payment, visit:\n"; |
75 | write " https://members2.hcoop.net/\n"; |
76 | write "and use the PayPal or Google Checkout link.\n"; |
047812d5 |
77 | |
78 | write "\nIf you don't know how to get a username and password for members2.hcoop.net, visit:\n"; |
79 | write " http://wiki2.hcoop.net/MemberManual/MigrationGuide\n"; |
80 | write "for a reminder. (\"Step 1\" is all you need to read.)\n"; |
81 | |
82 | write "\nIf for whatever reason you don't plan to pay the amount suggested in this e-mail,\n"; |
83 | write "_please_ don't stay silent. Reply to this message explaining your circumstances.\n"; |
84 | write "We are doing limited-time monetary grants on request, due to the extra costs\n"; |
85 | write "associated with setting up our new servers.\n"; |
86 | |
a47ac708 |
87 | ignore (Mail.mclose m) |
88 | end |
89 | end |
90 | | doOne _ = raise Fail "Bad SQL row" |
9d313c5f |
91 | in |
a47ac708 |
92 | C.app db doOne "SELECT Balance.name, COUNT(*), SUM(WebUserPaying.shares) AS shrs, Balance.amount FROM WebUserPaying JOIN Balance ON WebUserPaying.bal = Balance.id GROUP BY Balance.name, Balance.amount HAVING amount < 10"; |
9d313c5f |
93 | C.close db; |
94 | OS.Process.success |
a47ac708 |
95 | end handle C.Sql s => (print ("SQL failure: " ^ s ^ "\n"); |
96 | OS.Process.failure) |
9d313c5f |
97 | |
98 | end |