invoice to the last second of the previous day
smbaker [Tue, 23 Oct 2012 01:30:22 +0000 (18:30 -0700)]
apps/gacks/gacksbilling.py
apps/gacks/gackscentral.cron
apps/gacks/gacksinvoice.py

index 0954ddb..30901d2 100644 (file)
@@ -144,7 +144,7 @@ class GacksBilling:
         text += "This email confirms that your latest billing statement for the account %s is now available on Vicci.org. " % account.name
         text += "This statement covers the period from %s to %s.\n\n" % (start_date_str, end_date_str)
         text += "Unique best effort machines used: %d\n" % summary["be_machines"]
-        text += "Total est effort core-hours used: %0.2f\n" % summary["be_core_hours"]
+        text += "Total best effort core-hours used: %0.2f\n" % summary["be_core_hours"]
         text += "Unique reservation machines used: %d\n" % summary["resv_machines"]
         text += "Total charges: $ %0.2f\n" % summary["charges"]
         text += "Total credits: $ %0.2f\n\n" % summary["credits"]
@@ -184,7 +184,7 @@ class GacksBilling:
 
        if name in ["blankgroup",
                    "pl_sirius",
-                   "princeton_codnsdemux", "princeton_comon", "princeton_coredirect", "princeton_slicestat", "princeton_vcoblitz"]:
+                   "princeton_codnsdemux", "princeton_comon", "princeton_slicestat"]:
            return False
 
        return True
@@ -225,8 +225,11 @@ class GacksBilling:
         # throw away any STATE_AGGREGATED charges older than 48 hours
         self.invoices.prune_charges(STATE_AGGREGATED, 48*60*60)
 
+        # only invoice until the last second of yesterday
+        time_limit = GacksTime.end_of_day(day_delta = -1)
+
         # apply pending charges to nightly invoices
-        self.invoices.apply_invoices()
+        self.invoices.apply_invoices(time_limit)
 
         # auto-renew slices
         self.auto_renew()
index 8019629..02c9fb3 100644 (file)
@@ -2,5 +2,5 @@
 */5 * * * * root /usr/local/gackscentral/bin/localhost-gacks-garbagecollect.sh
 */15 * * * * root /usr/local/gackscentral/bin/localhost-gacks-defragment.sh
 */5 * * * * root /usr/local/gackscentral/bin/localhost-gacks-runasap.sh
-0 0 * * * root /usr/local/gackscentral/bin/localhost-gacks-applyinvoices.sh
-0 3 * * 1 root /usr/local/gackscentral/bin/localhost-gacks-mailinvoices.sh
+0 2 * * * root /usr/local/gackscentral/bin/localhost-gacks-applyinvoices.sh
+0 4 * * 1 root /usr/local/gackscentral/bin/localhost-gacks-mailinvoices.sh
index 446f5cc..2e748f2 100644 (file)
@@ -450,12 +450,12 @@ class GacksInvoiceManager(GacksDB):
          except MySQLdb.IntegrityError:
              raise GacksInvoiceDuplicate("duplicate invoice account=%s kind=%d object=%s date=%d" % (account, kind_id, object, date))
 
-    def aggregate_charges(self, account_id, from_kind, from_state, agg_kind, orphan_state):
+    def aggregate_charges(self, account_id, from_kind, from_state, agg_kind, orphan_state, time_limit):
         self.execute("BEGIN;")
         try:
             # get the totals, grouped by object_id
-            recs = self.execute_dict("SELECT SUM(amount) as total,SUM(core_hours) as total_hours,object_id,MAX(UNIX_TIMESTAMP(date)) as max_date,DATE(date) as agg_date FROM `" + self.tablename + "` WHERE account_id=%s AND kind_id=%s AND state=%s GROUP BY object_id, DATE(date);" %
-                                       (str(account_id), str(from_kind), str(from_state)))
+            recs = self.execute_dict("SELECT SUM(amount) as total,SUM(core_hours) as total_hours,object_id,MAX(UNIX_TIMESTAMP(date)) as max_date,DATE(date) as agg_date FROM `" + self.tablename + "` WHERE account_id='%s' AND kind_id='%s' AND state='%s' AND date<='%s' GROUP BY object_id, DATE(date);" %
+                                       (str(account_id), str(from_kind), str(from_state), GacksTime.timestamp_to_string(time_limit)))
 
             for rec in recs:
                 total = float(rec["total"])
@@ -595,14 +595,15 @@ class GacksInvoiceManager(GacksDB):
             # bill the next month
             date = GacksTime.month_delta(date, policy.membershipFeeMonths)
 
-    def apply_invoices(self):
+    def apply_invoices(self, time_limit):
         # get a list of (account_id, date) pairs for which there are pending charges.
-        records = self.execute_dict("SELECT account_id,MAX(UNIX_TIMESTAMP(date)) as max_date,DATE(date) as invoice_date FROM `" + self.tablename + "` WHERE state=" + str(STATE_PENDING) + " GROUP BY account_id, DATE(date) ")
+        records = self.execute_dict("SELECT account_id,MAX(UNIX_TIMESTAMP(date)) as max_date,DATE(date) as invoice_date FROM `" + self.tablename + "` WHERE state='%s' AND date<='%s' GROUP BY account_id, DATE(date) " %
+                                    (str(STATE_PENDING), GacksTime.timestamp_to_string(time_limit)))
 
         # aggregate the charges into dailies grouped by object to conserve space
         for account_id in self.get_accounts_with_invoices():
-            self.aggregate_charges(account_id, KIND_CYCLE_CHARGE, STATE_PENDING, KIND_CYCLE_AGGREGATE, STATE_AGGREGATED)
-            self.aggregate_charges(account_id, KIND_SLOT_CHARGE, STATE_PENDING, KIND_SLOT_AGGREGATE, STATE_AGGREGATED)
+            self.aggregate_charges(account_id, KIND_CYCLE_CHARGE, STATE_PENDING, KIND_CYCLE_AGGREGATE, STATE_AGGREGATED, time_limit)
+            self.aggregate_charges(account_id, KIND_SLOT_CHARGE, STATE_PENDING, KIND_SLOT_AGGREGATE, STATE_AGGREGATED, time_limit)
 
         for record in records:
             account_id = int(record["account_id"])