diff --git a/TuitionAutomation/TuitionAutomation.py b/TuitionAutomation/TuitionAutomation.py
index 0720b2a..052bfe2 100644
--- a/TuitionAutomation/TuitionAutomation.py
+++ b/TuitionAutomation/TuitionAutomation.py
@@ -3,8 +3,8 @@
from datetime import timedelta
import urllib
-paymentOrgId = 51
-minTransactionId = 17000
+# model.TestEmail = True
+model.Transactional = True
orgs = [
{
@@ -12,7 +12,7 @@
'name': "Kindergarten",
'base': 837
},
-
+
{
'id': 212,
'name': "Pre-K",
@@ -23,7 +23,7 @@
'name': "Pre-K",
'base': 837
},
-
+
{
'id': 210,
'name': "3-Year-Old",
@@ -34,7 +34,7 @@
'name': "3-Year-Old",
'base': 497
},
-
+
{
'id': 207,
'name': "2-Year-Old",
@@ -48,14 +48,14 @@
{
'id': 215,
'name': "Afternoon - Mon",
- 'base': 40,
+ 'base': 45,
'payPer': "meeting",
'discounts': False
},
{
'id': 253,
'name': "Afternoon - Thu",
- 'base': 40,
+ 'base': 45,
'payPer': "meeting",
'discounts': False
},
@@ -66,20 +66,20 @@
# }
]
-# ################# Basic configuration ends here. #########################
+paymentOrgId = 206
+minTransactionId = 1 #28100
+retroactive = True
+now = datetime.now() - timedelta(days=9)
+# ################# Basic configuration ends here. #########################
print "Assess Next Due Amount
"
print "Generate Email Previews
"
print "View Balances
"
print "Program Totals
"
-# model.TestEmail = True
-model.Transactional = True
-isDeposit = False
-
model.CurrentOrgId = paymentOrgId
-
+
# this is a container for collecting the "first child" of a given family, used to determine when a second child comes along.
firstChildren = {}
familyData = {}
@@ -91,8 +91,8 @@
model.Title = "Preschool Tuition Automation Tools"
-monthToUse = datetime.now() + timedelta(days=28)
-monthToUseR = datetime.now()
+monthToUse = now + timedelta(days=28)
+monthToUseR = now
monthName = monthToUse.strftime('%B')
monthNameR = monthToUseR.strftime('%B')
@@ -101,204 +101,261 @@
for cls in orgs:
meetingCntSql = """SELECT COUNT(*) as mtgCnt FROM Meetings WHERE OrganizationId = {} AND YEAR(MeetingDate) = {} AND MONTH(MeetingDate) = {}""".format(cls['id'], monthToUse.year, monthToUse.month)
meetingCnt = q.QuerySqlTop1(meetingCntSql).mtgCnt
-
+
if showTuitionAssessment:
print "
Tuition per Meeting - {} meetings in {}
".format(meetingCnt, monthName) else: print "Tuition per Month
" - + for student in q.QueryList("MemberTypeCodes( Org={} ) = 220[Member]".format(cls['id'])): - + enrollmentDateSql = "SELECT EnrollmentDate FROM OrganizationMembers WHERE OrganizationId = {} AND PeopleId = {}".format(cls['id'], student.PeopleId) enrollmentDate = q.QuerySqlTop1(enrollmentDateSql).EnrollmentDate - + lastChargeSql = """SELECT MAX(TransactionDate) as date FROM [Transaction] t LEFT JOIN [TransactionPeople] tp ON t.OriginalId = tp.Id WHERE t.OrgId = {} AND t.AdjustFee = 1 AND tp.PeopleId = {} AND Message LIKE '{}%'""".format(paymentOrgId, student.PeopleId, cls['name']) lastChargeDate = q.QuerySqlTop1(lastChargeSql) lastChargeDate = lastChargeDate if lastChargeDate is None else lastChargeDate.date - + isFirstChild = True if firstChildren.has_key("{}".format(student.FamilyId)): isFirstChild = (firstChildren["{}".format(student.FamilyId)].PeopleId == student.PeopleId) - + else: firstChildren["{}".format(student.FamilyId)] = student - - tuitionOverrideSql = """SELECT ome.IntValue as Tuition FROM OrgMemberExtra ome + + tuitionOverrideSql = """SELECT ome.IntValue as Tuition FROM OrgMemberExtra ome WHERE UPPER(ome.Field) = 'Tuition' AND ome.OrganizationId = {} AND ome.PeopleId = {}""".format(cls['id'], student.PeopleId) - + tuitionOverride = q.QuerySqlTop1(tuitionOverrideSql) - + meetingCntRSql = """SELECT COUNT(*) as mtgCnt FROM Meetings WHERE OrganizationId = {} AND YEAR(MeetingDate) = {} AND MONTH(MeetingDate) = {} AND MeetingDate > '{}'""".format(cls['id'], monthToUseR.year, monthToUseR.month, enrollmentDate) meetingCntR = q.QuerySqlTop1(meetingCntRSql).mtgCnt - + tuitionLine = cls['name'] depositLine = cls['name'] + " Deposit" - + if tuitionOverride is None: - + tuitionCharge = 1.0 * cls['base'] depositCharge = 1.0 * cls['base'] tuitionChargeR = 1.0 * cls['base'] * (meetingCntR > 0) - + if cls.has_key('payPer') and cls['payPer'] == "meeting": tuitionCharge *= meetingCnt tuitionChargeR *= meetingCntR - + if cls.has_key('discounts') and cls['discounts'] == False: pass # no discounts else: - if not isDeposit and q.QueryCount("FamHasPrimAdultChurchMemb = 1[True] AND PeopleId = {}".format(student.PeopleId)) > 0: + if q.QueryCount("FamHasPrimAdultChurchMemb = 1[True] AND PeopleId = {}".format(student.PeopleId)) > 0: tuitionCharge = tuitionCharge * (5.0/6.0) tuitionChargeR = tuitionChargeR * (5.0/6.0) tuitionLine = tuitionLine + " (Tenth Member Rate)" - depositLine = depositLine + " (Tenth Member Rate)" - - elif not isDeposit and not isFirstChild: + # depositLine = depositLine + " (Tenth Member Rate)" Do not apply discounts to Deposits. + + elif not isFirstChild: tuitionCharge = tuitionCharge * (8.0/9.0) tuitionChargeR = tuitionChargeR * (8.0/9.0) tuitionLine = tuitionLine + " (Sibling Rate)" - depositLine = depositLine + " (Sibling Rate)" - - else: + # depositLine = depositLine + " (Sibling Rate)" Do not apply discounts to Deposits. + + else: tuitionCharge = tuitionOverride.Tuition * 1.0 tuitionChargeR = tuitionOverride.Tuition * 1.0 depositCharge = tuitionOverride.Tuition * 1.0 tuitionLine = tuitionLine + " (Special Rate)" depositLine = depositLine + " (Special Rate)" - + if cls.has_key('payPer') and cls['payPer'] == "meeting": tuitionCharge *= meetingCnt tuitionChargeR *= meetingCntR - + tuitionLineR = tuitionLine + " - " + monthNameR tuitionLine += " - " + monthName - - # Rounding, because the preschool wants that. + + # Rounding, because the preschool wants that. tuitionCharge = round(tuitionCharge, 0) tuitionChargeR = round(tuitionChargeR, 0) depositCharge = round(depositCharge, 0) - - if enrollmentDate < lastChargeDate: + + if enrollmentDate < lastChargeDate: # and not cls.has_key('payPer'): tuitionChargeR = 0.0 - + if showTuitionAssessment: - if isDeposit: - print "{} {} ${:,.2f} {}
".format(student.PreferredName, student.LastName, depositCharge, depositLine) - else: - if tuitionChargeR > 0: - print "{} {} ${:,.2f} {}
".format(student.PreferredName, student.LastName, tuitionChargeR, tuitionLineR) - print "{} {} ${:,.2f} {}
".format(student.PreferredName, student.LastName, tuitionCharge, tuitionLine) - - + # print "{} {} ${:,.2f} {}
".format(student.PreferredName, student.LastName, depositCharge, depositLine) + if tuitionChargeR > 0 and retroactive: + print "{} {} ${:,.2f} {} (retro)
".format(student.PreferredName, student.LastName, tuitionChargeR, tuitionLineR) + print "{} {} ${:,.2f} {}
".format(student.PreferredName, student.LastName, tuitionCharge, tuitionLine) + + # Add to org, and add deposit if new to the org to account if not model.InOrg(student.PeopleId, paymentOrgId): model.JoinOrg(paymentOrgId, student.PeopleId) + + # Add deposit if needed if monthToUse.month > 6: model.AdjustFee(student.PeopleId, paymentOrgId, -depositCharge, depositLine) - - + + # TODO: Automatically add fee adjustments. - # TODO: Calculate proration of tuition. - if applyTuitionAssessment and not isDeposit: - if tuitionChargeR > 0: + # TODO: Calculate proration of tuition. + if applyTuitionAssessment: + if tuitionChargeR > 0 and tuitionLineR != tuitionLine: model.AdjustFee(student.PeopleId, paymentOrgId, -tuitionChargeR, tuitionLineR) model.AdjustFee(student.PeopleId, paymentOrgId, -tuitionCharge, tuitionLine) - - + + # Initialize FamilyData dict for emails if not familyData.has_key("{}".format(student.FamilyId)): fd = { 'recipients': [], 'participants': [], + 'participantPids': [], + 'paylinks': [], + 'totalDue': 0.0, 'print': '', - 'hasBalanceDue': False + 'table': '', + 'hasBalanceDue': False, + 'otherParent': None } else: fd = familyData["{}".format(student.FamilyId)] - + needsToAppend = True for part in fd['participants']: if part.PeopleId == student.PeopleId: needsToAppend = False break - + if not needsToAppend: continue - + fd['participants'].append(student) - - fd['print'] += "Date | Amount | Description |
---|
Date | Amount | Person | Description |
---|---|---|---|
{} | {} | {} | |
{} | {} | {} | {} |
Balance: ${:,.2f}
Balance: ${:,.2f}
This credit of ${:,.2f} will be applied to future monthly billing cycles. You do not need to do anything now.
".format(amtOwed * -0.01) - elif amtOwed > 0: - if paylink is None: - fd['print'] += "Please make a payment of ${:,.2f} for {} by sending in a check, or paying online here.
".format(amtOwed * 0.01, student.PreferredName, paylink) - else: - fd['print'] += "Since there is no outstanding balance, you don't need to do anything.
".format(student.PreferredName) - - fd['print'] += "Sends to: {} {} Send Individually
".format(p1Name, p2Name, ",".join(pPids)) + print "Sends to: {} {} {} Send Individually
".format(p1Name, p2Name, p3Name, ",".join(pPids)) else: - print "Does NOT Send to: {} {} Send Individually
".format(p1Name, p2Name, ",".join(pPids)) - - if len(familyData[fi]['participants']) > 1: - familyData[fi]['print'] = "Each child's balance and payments are listed below. Please note that each child's account must be payed separately if paying online.
Does NOT Send to: {} {} {} Send Individually
".format(p1Name, p2Name, p3Name, ",".join(pPids)) + + # if len(familyData[fi]['participants']) > 1: + familyData[fi]['print'] = familyData[fi]['table'] + + amtOwed = familyData[fi]['totalDue'] + if amtOwed < 0: + familyData[fi]['print'] += "This credit of ${:,.2f} will be applied to future monthly billing cycles. You do not need to do anything now.
".format(amtOwed * -0.01) + elif amtOwed > 0: + if paylink is None: + familyData[fi]['print'] += "Please make a payment of ${:,.2f} by sending in a check, or {}.
".format(amtOwed * 0.01, " AND ".join(familyData[fi]['paylinks'])) + else: + familyData[fi]['print'] += "Since there is no outstanding balance, you don't need to do anything.
".format(student.PreferredName) + + if not sendEmails: print familyData[fi]['print'] - + if sendEmails and familyData[fi]['hasBalanceDue']: if p1 is not None: emailPids.append(p1.PeopleId) @@ -328,14 +399,21 @@ recipientData.PeopleId = p1.PeopleId recipientData.Summary = familyData[fi]['print'] emailData.append(recipientData) - + if p2 is not None: emailPids.append(p2.PeopleId) recipientData = model.DynamicData() recipientData.PeopleId = p2.PeopleId recipientData.Summary = familyData[fi]['print'] emailData.append(recipientData) - + + if p3 is not None: + emailPids.append(p3.PeopleId) + recipientData = model.DynamicData() + recipientData.PeopleId = p3.PeopleId + recipientData.Summary = familyData[fi]['print'] + emailData.append(recipientData) + if sendEmails: if Data.to == "all": @@ -343,8 +421,8 @@ emailPids = ",".join(emailPids) else: emailPids = Data.to - + print "Emails have been sent to:
" - + print "PeopleIds = '{}'".format(emailPids) - model.EmailContentWithPythonData("PeopleIds = '{}'".format(emailPids), 27796, "preschooltuition@tenth.org", "Tenth Preschool", "Preschool Tuition", emailData) \ No newline at end of file + model.EmailContentWithPythonData("PeopleIds = '{}'".format(emailPids), 27796, "preschooltuition@tenth.org", "Tenth Preschool", "Preschool Tuition", emailData)