fun mkTransactionRow [id, descr, amount, d, stamp] =
{id = C.intFromSql id, descr = C.stringFromSql descr, amount = C.realFromSql amount,
d = C.stringFromSql d, stamp = C.timestampFromSql stamp}
- | mkTransactionRow row = raise Fail ("Bad transaction row : " ^ makeSet id row)
+ | mkTransactionRow row = Init.rowError ("transaction", row)
fun addTransaction (descr, amount, d) =
let
val id = nextSeq (db, "TransactionSeq")
in
C.dml db ($`INSERT INTO Transaction (id, descr, amount, d, stamp)
- VALUES (^id, ^(C.stringToSql descr), ^(C.realToSql amount), ^(C.stringToSql d), CURRENT_TIMESTAMP)`);
- C.intFromSql id
+ VALUES (^(C.intToSql id), ^(C.stringToSql descr), ^(C.realToSql amount), ^(C.stringToSql d), CURRENT_TIMESTAMP)`);
+ id
end
fun lookupTransaction id =
fn (trn :: rest) =>
(if C.isNull trn then false else true,
mkUserRow rest)
- | row => raise Fail ("Bad listUsers row: " ^ makeSet id row)
+ | row => Init.rowError ("listUsers", row)
fun listUsers trn =
- C.map (getDb ()) mkUserRow' ($`SELECT trn, id, name, rname, bal, joined
+ C.map (getDb ()) mkUserRow' ($`SELECT trn, id, name, rname, bal, joined, app, shares, paypal, checkout
FROM WebUser LEFT OUTER JOIN Charge ON usr = id AND trn = ^(C.intToSql trn)
ORDER BY name`)
fun mkChargeRow [trn, usr, amount] =
{trn = C.intFromSql trn, usr = C.intFromSql usr, amount = C.realFromSql amount}
- | mkChargeRow row = raise Fail ("Bad charge row : " ^ makeSet id row)
+ | mkChargeRow row = Init.rowError ("charge", row)
fun addCharge {trn, usr, amount} =
ignore (C.dml (getDb ()) ($`INSERT INTO Charge (trn, usr, amount)
val mkChargeRow' =
fn (name :: rest) => (C.stringFromSql name, mkChargeRow rest)
- | row => raise Fail ("Bad name+charge row: " ^ makeSet id row)
+ | row => Init.rowError ("name+charge", row)
fun listChargesWithNames trn =
C.map (getDb ()) mkChargeRow' ($`SELECT name, trn, usr, amount FROM Charge, WebUser
fun clearCharge [bal, amount] =
ignore (C.dml db ($`UPDATE Balance
- SET amount = amount - ^amount
- WHERE id = ^bal`))
- | clearCharge row = raise Fail ("Bad clearCharge row : " ^ makeSet id row)
+ SET amount = amount - ^(C.stringFromSql amount)
+ WHERE id = ^(C.stringFromSql bal)`))
+ | clearCharge row = Init.rowError ("clearCharge", row)
in
C.app db clearCharge ($`SELECT bal, SUM(amount) FROM Charge, WebUser
WHERE trn = ^(C.intToSql trn)
ignore (C.dml db ($`DELETE FROM Charge WHERE trn = ^(C.intToSql trn)`))
end
-fun applyCharges db trn =
+fun applyCharges trn =
let
+ val db = getDb ()
+
fun applyCharge [bal, amount] =
ignore (C.dml db ($`UPDATE Balance
- SET amount = amount + ^amount
- WHERE id = ^bal`))
- | applyCharge row = raise Fail ("Bad applyCharge row : " ^ makeSet id row)
+ SET amount = amount + ^(C.stringFromSql amount)
+ WHERE id = ^(C.stringFromSql bal)`))
+ | applyCharge row = Init.rowError ("applyCharge", row)
in
C.app db applyCharge ($`SELECT bal, SUM(amount) FROM Charge, WebUser
WHERE trn = ^(C.intToSql trn)
VALUES (^(C.intToSql trn), ^(C.intToSql usr), ^(C.realToSql split))`))
in
app addCharge usrs;
- applyCharges db trn
+ applyCharges trn
end
(* Automated hosting charges *)
in
walkNvs (rest,
SM.insert (umap, name, extra),
- amount - extra)
+ amount + extra)
end
else
walkNvs (rest, umap, amount)
val (umap, amount) = walkNvs (nvs, SM.empty, #amount tran)
- val payers = Group.groupMembers paying
- val even = amount / real (length payers)
+ val db = getDb ()
+
+ 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)
- fun doUser (usr : Init.user, umap) =
+ val even = amount / real shares
+
+ fun doUser ([uid, uname, shares], umap) =
let
+ val uid = C.intFromSql uid
+ val uname = C.stringFromSql uname
+ val shares = C.intFromSql shares
+
val (charge, umap) =
- case SM.find (umap, #name usr) of
- NONE => (even, umap)
- | SOME extra => (even + extra, #1 (SM.remove (umap, #name usr)))
+ case SM.find (umap, uname) of
+ NONE => (even * real shares, umap)
+ | SOME extra => (even * real shares - extra, #1 (SM.remove (umap, uname)))
in
- addCharge {trn = trn, usr = #id usr, amount = charge};
+ addCharge {trn = trn, usr = uid, amount = charge};
umap
end
+
+ val _ = if SM.numItems (C.fold db doUser umap
+ ($`SELECT id, name, shares
+ FROM WebUser JOIN Membership ON usr = WebUser.id AND grp = ^(C.intToSql paying)`))
+ = 0 then
+ applyCharges trn
+ else
+ raise Fail "Usage description contains an unknown username"
+
+ val usageFile = TextIO.openOut (Init.scratchDir ^ "/usage/" ^ Int.toString trn)
in
- if SM.numItems (foldl doUser umap payers) = 0 then
- ()
- else
- raise Fail "Usage description contains an unknown username"
+ TextIO.output (usageFile, usage);
+ TextIO.closeOut usageFile
end
-end
\ No newline at end of file
+
+fun equalizeBalances () =
+ ignore (C.dml (getDb ()) ($`UPDATE Balance SET amount = (SELECT SUM(amount) FROM Charge JOIN WebUser ON usr = WebUser.id WHERE bal = Balance.id)`))
+
+fun lookupHostingUsage trn =
+ let
+ val usageFile = TextIO.openIn (Init.scratchDir ^ "/usage/" ^ Int.toString trn)
+
+ fun loop acc =
+ case TextIO.inputLine usageFile of
+ NONE => String.concat (List.rev acc)
+ | SOME line => loop (line :: acc)
+ in
+ SOME (loop [])
+ before TextIO.closeIn usageFile
+ end handle _ => NONE
+
+fun costBase amt =
+ case C.oneRow (getDb ()) ($`SELECT ^(C.realToSql amt) / SUM(shares) FROM WebUserPaying`) of
+ [share] => C.realFromSql share
+ | row => Init.rowError ("Bad costBase result", row)
+
+end