Fold dues increase into portal
[bpt/portal.git] / remind / remind.sml
CommitLineData
dda99898
AC
1structure Remind :> REMIND =
2struct
3
4open Config
5
6structure C = PgClient
7
878a4e49
AC
8fun 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
8bc5f9f9 14val basePerMonth = 7.0
69ef6636 15val deposit = basePerMonth * 3.0
83e297c7 16
dda99898
AC
17fun main _ =
18 let
19 val db = C.conn dbstring
20
878a4e49
AC
21 val totalShares = case C.oneRow db "SELECT SUM(shares) FROM WebUserPaying" of
22 [total] => C.intFromSql total
23 | _ => raise Fail "Bad SUM(shares) row"
24
25 fun doOne [user, members, shares, amount] =
26 let
27 val user = C.stringFromSql user
28 val members = C.intFromSql members
29 val shares = C.intFromSql shares
30 val amount = C.realFromSql amount
31
83e297c7 32 val perMonth = basePerMonth * real shares
c8abf2d9 33 val headsUp = deposit + perMonth * 2.0
878a4e49 34 in
bb40c5c6 35 if amount >= headsUp then
878a4e49
AC
36 ()
37 else
38 let
39 val m = Mail.mopen ()
40 fun write msg = Mail.mwrite (m, msg)
41 in
bb40c5c6 42 if amount < deposit then
878a4e49
AC
43 write "Subject: Your NEGATIVE HCoop balance\n"
44 else
45 write "Subject: Your low HCoop balance\n";
46 write "From: HCoop Payment Reminder Robot <payment";
47 write emailSuffix;
48 write ">\n";
49 write "To: ";
50 write user;
51 write emailSuffix;
52 write "\nCc: payment@hcoop.net";
53 write "\n\n";
54
bb40c5c6 55 if amount < deposit then
878a4e49 56 (write "Your HCoop balance is negative. This means that you've paid less than you've\n";
bb40c5c6
AC
57 write "been charged to date, excluding your required deposit. If your account hasn't\n";
58 write "been frozen yet, expect that to happen very soon. Our bylaws allow our board\n";
59 write "of directors to vote you out of the co-op, without any obligation to contact\n";
60 write "you first, when your balance stays negative for three months. Please make a\n";
61 write "payment as soon as possible, so that we don't need to do this!\n\n")
878a4e49 62 else
bb40c5c6
AC
63 (write "With our current dues projections, you have less than two months left until\n";
64 write "your HCoop balance becomes negative, based on your sliding scale pledge amount.\n";
65 write "Please make a payment as soon as you can. We will freeze your account if your\n";
66 write "balance does become negative, and the board of directors will probably vote you\n";
67 write "out of the cooperative shortly thereafter if you don't make a payment.\n\n");
878a4e49
AC
68
69 write "Your balance: US$";
bb40c5c6 70 write (printReal (amount - deposit));
878a4e49
AC
71 write "\nTotal number of members linked to your balance: ";
72 write (Int.toString members);
73 write "\nTotal pledge amount: ";
74 write (Int.toString shares);
bb40c5c6
AC
75 write "\nDeposit: US$";
76 write (printReal deposit);
77 write "\nMinimum amount to pay to not see this message again for two months: US$";
78 write (printReal (headsUp - amount));
dda99898 79
8bc5f9f9 80 write "\n\nThe deposit requirement was calculated as three months of dues at $7/mo..\n\n";
dda99898 81
878a4e49 82 write "To make a payment, visit:\n";
4763cfb8 83 write " https://members.hcoop.net/\n";
878a4e49 84 write "and use the PayPal or Google Checkout link.\n";
9a4c122a 85
9a4c122a
AC
86 write "\nIf for whatever reason you don't plan to pay the amount suggested in this e-mail,\n";
87 write "_please_ don't stay silent. Reply to this message explaining your circumstances.\n";
9a4c122a 88
878a4e49
AC
89 ignore (Mail.mclose m)
90 end
91 end
92 | doOne _ = raise Fail "Bad SQL row"
dda99898 93 in
ea5c7ca1 94 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 < " ^ C.realToSql deposit ^ " + " ^ C.realToSql (basePerMonth * 2.0) ^ " * SUM(WebUserPaying.shares)");
dda99898
AC
95 C.close db;
96 OS.Process.success
878a4e49
AC
97 end handle C.Sql s => (print ("SQL failure: " ^ s ^ "\n");
98 OS.Process.failure)
dda99898
AC
99
100end