Finish changes to follow dues policy changes
authorAdam Chlipala <adamc@hcoop.net>
Sat, 26 Apr 2008 16:21:59 +0000 (16:21 +0000)
committerAdam Chlipala <adamc@hcoop.net>
Sat, 26 Apr 2008 16:21:59 +0000 (16:21 +0000)
balance.sml
money.mlt
money.sig
money.sml
pledge.mlt

index 05f6c3d..e400709 100644 (file)
@@ -105,7 +105,8 @@ fun sumOwnedBalances () =
 
 fun isNegative (bal : balance) = #amount bal < 0.0
 
-fun depositAmount bal =
+fun depositAmount _ = 5.0 * 3.0
+(*fun depositAmount bal =
     let
        val db = getDb ()
 
@@ -114,6 +115,6 @@ fun depositAmount bal =
                            | row => Init.rowError ("Bad depositAmount share count result", row)
     in
        3.0 * 900.0 / real totalShares
-    end
+    end*)
 
 end
index 0ac1b3b..7026421 100644 (file)
--- a/money.mlt
+++ b/money.mlt
@@ -339,6 +339,27 @@ end %></textarea></td> </tr>
 </table>
 </form>
 
+<% elseif $"cmd" = "dues" then
+       Group.requireGroupName "money";
+       showNormal := false %>
+
+<h3>Monthly dues</h3>
+
+<form action="money" method="post">
+<input type="hidden" name="cmd" value="dues2">
+<table class="blanks">
+<tr> <td>Description:</td> <td><input name="descr"></td> </tr>
+<tr> <td>Date:</td> <td><input name="d"></td> </tr>
+<tr> <td>Amount/pledge:</td> <td><input name="base"></td> </tr>
+<tr> <td><input type="submit" value="Add"></td> </tr>
+</table>
+
+<% elseif $"cmd" = "dues2" then
+       Group.requireGroupName "money";
+       Money.billDues {descr = $"descr", base = Web.stor ($"base"), date = $"d"};
+
+       %><h3>Dues debits added.</h3>
+
 <% elseif $"cmd" = "even" then
        Group.requireGroupName "money";
        val id = Money.addTransaction ($"descr", Web.stor ($"amount"), $"d");
@@ -600,8 +621,9 @@ Co-op balance: $<% #amount (Balance.lookupBalance (valOf (Balance.balanceNameToI
 
 <br><b><u>New transaction:</u></b><br>
 <a href="money?cmd=bill">Bill for the co-op</a><br>
-<a href="money?cmd=hosting">New hosting bill (old style)</a><br>
 <a href="money?cmd=pay">Payment from member</a><br>
+<a href="money?cmd=dues">Monthly dues</a><br>
+<a href="money?cmd=hosting">New hosting bill (old style)</a><br>
 <a href="money?cmd=evenForm">Generic/even</a><br>
 <br>
 <a href="money?cmd=equalize">Equalize balances</a><br>
index 1abf0fa..d54ba3f 100644 (file)
--- a/money.sig
+++ b/money.sig
@@ -39,4 +39,6 @@ sig
 
     val freezeworthyPledgers : unit -> { id : int, name : string, balance : real } list
     val bootworthyPledgers : unit -> { id : int, name : string, balance : real } list
+
+    val billDues : {descr : string, base : real, date : string} -> unit
 end
index e077fcc..d0668a4 100644 (file)
--- a/money.sml
+++ b/money.sml
@@ -276,17 +276,17 @@ fun costBase amt =
 val monthlyCost = 900.0
 val graceMonths = 1
 
+val baseDues = 5.0
+
 fun delinquentPledgers () =
     let
-       val costBase = costBase monthlyCost
-
        fun makeRow [id, name, shares, amount] = {id = C.intFromSql id, name = C.stringFromSql name,
                                                  shares = C.intFromSql shares, balance = C.realFromSql amount}
          | makeRow row = Init.rowError ("Bad delinquentPledgers", row)
     in
        C.map (getDb ()) makeRow ($`SELECT WebUserPaying.id, WebUserPaying.name, shares, amount
                                    FROM WebUserPaying JOIN Balance ON Balance.id = bal
-                                   WHERE amount < shares * ^(C.realToSql costBase) * ^(C.intToSql graceMonths)
+                                   WHERE amount < shares * ^(C.realToSql baseDues) * ^(C.intToSql graceMonths)
                                      AND shares > 1
                                    ORDER BY name`)
     end
@@ -296,7 +296,7 @@ fun resetPledges ids =
 
 fun freezeworthyPledgers () =
     let
-       val costBase = costBase monthlyCost
+       val baseDues = 5.0
 
        fun makeRow [id, name, amount] = {id = C.intFromSql id, name = C.stringFromSql name,
                                          balance = C.realFromSql amount}
@@ -304,14 +304,14 @@ fun freezeworthyPledgers () =
     in
        C.map (getDb ()) makeRow ($`SELECT WebUserPaying.id, WebUserPaying.name, amount
                                    FROM WebUserPaying JOIN Balance ON Balance.id = bal
-                                   WHERE amount >= ^(C.realToSql costBase) * ^(C.intToSql graceMonths)
-                                     AND amount < ^(C.realToSql costBase) * ^(C.intToSql (graceMonths + 1))
+                                   WHERE amount >= ^(C.realToSql baseDues) * ^(C.intToSql graceMonths)
+                                     AND amount < ^(C.realToSql baseDues) * ^(C.intToSql (graceMonths + 1))
                                    ORDER BY name`)
     end
 
 fun bootworthyPledgers () =
     let
-       val costBase = costBase monthlyCost
+       val baseDues = 5.0
 
        fun makeRow [id, name, amount] = {id = C.intFromSql id, name = C.stringFromSql name,
                                          balance = C.realFromSql amount}
@@ -319,8 +319,47 @@ fun bootworthyPledgers () =
     in
        C.map (getDb ()) makeRow ($`SELECT WebUserPaying.id, WebUserPaying.name, amount
                                    FROM WebUserPaying JOIN Balance ON Balance.id = bal
-                                   WHERE amount < ^(C.realToSql costBase) * ^(C.intToSql graceMonths)
+                                   WHERE amount < ^(C.realToSql baseDues) * ^(C.intToSql graceMonths)
                                    ORDER BY name`)
     end
 
+fun billDues {descr, base, date} =
+    let
+       val db = getDb ()
+       val paying =
+           case Group.groupNameToId "paying" of
+               NONE => raise Fail "No 'paying' group"
+             | SOME id => id
+
+       val shares =
+           case C.oneRow db ($`SELECT SUM(shares)
+                                 FROM WebUser JOIN Membership ON usr = WebUser.id AND grp = ^(C.intToSql paying)`) of
+               [n] => C.intFromSql n
+             | row => Init.rowError ("Bad addHostingCharges share count result", row)
+
+       val total = real shares * base
+
+       val give = addTransaction (descr, ~total, date)
+
+       fun doUser [uid, shares]  =
+           let
+               val uid = C.intFromSql uid
+               val shares = C.intFromSql shares
+           in
+               addCharge {trn = give, usr = uid, amount = ~(base * real shares)}
+           end
+         | doUser r = Init.rowError ("Bad billDues/doUser row", r)
+
+       val receive = addTransaction (descr, total, date)
+
+       val hcoop = valOf (Init.userNameToId "hcoop")
+    in
+       C.app db doUser ($`SELECT id, shares
+                          FROM WebUser JOIN Membership ON usr = WebUser.id AND grp = ^(C.intToSql paying)`);
+       applyCharges give;
+       
+       addCharge {trn = receive, usr = hcoop, amount = total};
+       applyCharges receive
+    end
+
 end
index 13ca3dd..1668123 100644 (file)
@@ -18,7 +18,9 @@ end
 
 val user = Init.getUser () %>
 
-<p>HCoop divides expenses among members based on a "sliding scale"-style scheme. We charge you only for our concrete expenses, not adding any expenses beyond what we pay to service providers and vendors. Whenever a concrete expense needs to be paid for, we divide it among the members based on how much each of you has pledged on this web page. Your pledge is a whole number 1 or higher which you can think of as indicating how many times the amount paid by the lowest-contributing members you are willing to pay. Concretely, every expense is divided by the sum of all members' pledges, and each member is charged an amount equal to the result of that division times his pledge number. This way <i>everyone's</i> monthly costs go down automatically as we gain new members.</p>
+<p>Base HCoop membership dues are set at $5/mo.. On this page, you can set a <i>pledge amount</i> above one, so that you pay 5<i>N</i> dollars a month, where <i>N</i> is your pledge amount, to help offset costs for members with more stringent budgets.  If the members listed below weren't making extra pledges, we would need to increase the base dues amount of $5 to cover our costs.</p>
+
+<!--p>HCoop divides expenses among members based on a "sliding scale"-style scheme. We charge you only for our concrete expenses, not adding any expenses beyond what we pay to service providers and vendors. Whenever a concrete expense needs to be paid for, we divide it among the members based on how much each of you has pledged on this web page. Your pledge is a whole number 1 or higher which you can think of as indicating how many times the amount paid by the lowest-contributing members you are willing to pay. Concretely, every expense is divided by the sum of all members' pledges, and each member is charged an amount equal to the result of that division times his pledge number. This way <i>everyone's</i> monthly costs go down automatically as we gain new members.</p-->
 
 <h2>Set your pledge number</h2>
 <form method="post">
@@ -28,6 +30,9 @@ val user = Init.getUser () %>
 </form>
 
 <h2>Calculate your share of an expense</h2>
+
+<p>This form is mostly of historical interest, since we've switched to a flat dues scheme.</p>
+
 <form method="post">
 <input type="hidden" name="cmd" value="calc">
 $<input name="amt" size="7" value="750">