GivingTypesData Python Script
Automate this Script
To get this script to run every morning automatically, you can put it into the MorningBatch Python script.
Open the existing or create a new Python script called MorningBatch.
Add the following line of code.
model.CallScript("GivingTypesData")
Save the script. It will run the next morning between 4:30 AM and 5:30 AM.
Of course, you can always manually run this script whenever you want.
Explanation of the Code
The goal of this code is to create ContributionTags that categorize contributions into various Type categories such as:
Online, Recurring, Mobile, Offering plate, Mission Trips, Bank Drafts, Stock, and Non-Tax Deductible.
These categories should not overlap; a Priority scheme is used to decide the single category for a contribution that may fit into more than one Type.
This way, the total of Types should reconcile with the sum of contributions.
The code further divides each category into three different date ranges and three different fund sets.
The final report contains three tables for the three date ranges.
Each row in a table represents a summary of a different Type of contributions with three columns for different fund sets.
These Contribution Tags become a snapshot, produced at least once a day during the morning batch,
allowing the final report to render swiftly.
| #Roles=Finance
from System import DateTime
|
Line 1
limits only those users with the role Finance to run this script.
Line 3
allows the code to use .NET DateTime functionality
Initialize
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | # Initialize global data
MaxDate = DateTime.Today
NameOfChurch = model.Setting("NameOfChurch")
GivingTypesData = model.DynamicData()
GivingTypesData.Created = DateTime.Now
ValidationReportList = []
Priority = 0
Base = model.DynamicData()
Base.MinDate = MaxDate.AddDays(-365).ToString("d")
Base.MaxDate = MaxDate
if NameOfChurch == "Mount Pisgah UMC":
pass # negative amounts are OK
else:
Base.FromAmount = 0 # no negative amounts
|
This code initializes global variables:
- MaxDate
The the last date for any contribution to be reported on.
The current date is used.
- NameOfChurch
Used later to execute particular, church specific lines of code.
- GivingTypesData
A DynamicData object which will contain all of the SearchParameters and store them in a file with the run date.
- ValidationReportList
An array (list) of lines of HTML used to display a validation report at the end of the script.
- Priority
Priority tracks the creation order as the various SearchParameters build ContributionTags.
- Base
A DynamicData object which will hold the common SearchParameters for every Contribution Type,
including the date range.
Lines 13-15
set the date range used for the Base to the Last 365 days.
This range is inclusive of any contribution in the other date ranges since they are shorter.
Lines 16-19
sets the Base.FromAmount
to 0 to exclude negative contributions.
If your church needs negative contributions because of historical data that used negative contributions for reversals,
then change the name of the church to your church (found in the Settings on the Admin menu).
NextPriority
| def NextPriority():
global Priority
Priority += 1
return Priority
|
Lines 35-38
define a function called NextPriority which increments a global variable named Priority in the function call.
Priority prevents a single contribution from falling into more than one contribution Type category on the final report.
Lower numbers take priority over higher numbers within a fund set column.
Line 36
allows the global variable Priority to be assigned to within the function.
Normally in Python functions all variables are local to the function
and although global variables can be read and used within a function, they cannot be assigned to.
CreateTag
40
41
42
43
44
45
46
47
48 | def CreateTag(fundSet, typeCategory, searchParameters):
TagName = 'Gt{}-{}'.format(fundSet, typeCategory)
NamePriority = '{}-{}'.format(TagName, Priority)
dd = model.DynamicData()
dd.parms = searchParameters
dd.link = '/ContributionsJsonSearch/{}/{}'.format('GivingTypesData', NamePriority)
GivingTypesData.AddValue(NamePriority, dd)
ValidationReportList.append('<h4><a href="{}" target="validate">{}</a></h4>'.format(dd.link, NamePriority))
ValidationReportList.append('<pre>{}</pre>'.format(model.CreateContributionTag(TagName, searchParameters)))
|
Lines 40-48
define a function called CreateTag which creates a ContributionTag
controlled by the searchParameters passed into the function.
Line 41
constructs TagName using the prefix Gt
, the fundSet, and the typeCategory.
The fundSet is one of: AllFunds
, MainFund
, and Other
defining the three main columns of the report.
Line 42
constructs NamePriority from TagName and Priority uniquely identifying a unique set of SearchParameters.
When adding to the same tag with a different search,
the TagName stays the same, but the NamePriority is unique because Priority is unique for each search section.
So a single TypeCategory can contain more than one Priority
when multiple searches are used to construct and then add to the RowType tag.
The last two lines of the function save information to the ValidationReportList
which is displayed on-screen when a manual run is complete.
CreateTags
Lines 50-173
define a function called CreateTags.
Plural because this function creates all of the tags needed for a given fundSet
which defines a column in the report. The singular function CreateTag is called in multipe sections.
Before we move on to the various sections,
the following will help you understand what what we mean by section in this function.
Within the CreateTags function, there are multiple sections separated by blank lines.
Each section will either create a new tag or add to an existing tag.
A section starts with an assignment to RowType which is associated with a row in the final report.
Then the SearchParameters for the RowType are built.
Finally, the section ends with a call to CreateTag.
Some sections are preceded with the comment, # church specific
.
If this comment is present, then there may not be any results for this RowType for your church.
As such, the section can be deleted or modified for your church.
The order of execution of the various sections is significant.
Some contributions can fit into the SearchParameters for different sections.
However, it is important, in the final report, that a given contribution appear in only one row.
The lower priority numbers take precedence over higher numbers for a given column’s FundSet.
For example, if a contribution matches the SearchParameters in both priority 103 and 104 for two different RowTypes,
then in the final report, the gift will only show up in Priority 103 for the first RowType and not in 104 the latter RowType.
This way, the sum of the individual lines will match the Total line.
You should take care to decide which RowType is more important to associate
with a contribution and place the section for the more important RowType ahead of another possible RowType.
The row order for dispay on the final report is controlled independantly from this priority ordering scheme.
| RowType = 'Mobile'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.Source = 1
CreateTag(fundSet, RowType, SearchParameters)
|
Mobile
Lines 51-55
create a tag called Mobile
which includes contributions coming from the TouchPoint Mobile app (SearchParameters.Source = 1
).
Note Line 52
which is used at the begining of each search section.
The call to model.DynamicData(Base)
creates a new set of search parameters using Base
as the starting point.
Note the call to NextPriority on Line 53
.
Each search section calls this function to increment the Priority which is what makes it unique to each search.
MissionTrip
57
58
59
60
61
62
63
64
65
66
67
68
69 | RowType = 'MissionTrip'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.ContributionDesc = '%MissionTrip: org%'
CreateTag(fundSet, RowType, SearchParameters)
# church specific
RowType = 'MissionTrip'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.AddToTag = 1
SearchParameters.BundleTypes = ['Mission Trip Transaction']
CreateTag(fundSet, RowType, SearchParameters)
|
Lines 57-61
create a tag called MissionTrip.
It uses the contribution description starting with MissionTrip: org%
.
The %
at the end matches anything that follows.
Touchpoint’s built-in Mission Trip support does this so that this will work for any church.
Lines 63-69
add to the tag called MissionTrip. Note the AddToTag on Line 67
.
It uses a church specific BundleType called Mission Trip Transaction
,
which requires you to create this BundleType for entering Mission Trip gifts.
This section of code is only needed if you enter Mission Trip support gifts
without using TouchPoint’s support for Mission Trip Giving exclusively.
Online
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 | RowType = 'Online'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.Source = 1
SearchParameters.TransactionDesc = 'Online Giving'
CreateTag(fundSet, RowType, SearchParameters)
RowType = 'Online'
SearchParameters = model.DynamicData(Base)
SearchParameters.AddToTag = 1
SearchParameters.Priority = NextPriority()
SearchParameters.Source = 0
SearchParameters.BundleTypes = ['Online']
SearchParameters.TransactionDesc = '<>Recurring Giving'
CreateTag(fundSet, RowType, SearchParameters)
# church specific
RowType = 'Online'
SearchParameters = model.DynamicData(Base)
SearchParameters.AddToTag = 1
SearchParameters.Priority = NextPriority()
SearchParameters.BundleTypes = ['Manual Credit Cards','Payroll Deductions']
CreateTag(fundSet, RowType, SearchParameters)
|
Lines 71-76
create a tag called Online.
These come from the TouchPoint Mobile App (Source = 1
) and have a Transaction Description of Online Giving
.
However, The Mobile
tag already contains these.
Lines 78-85
add to the tag called Online.
These do not come from the Touchpoint Mobile App (Source = 0
).
And The BundleType is Online
. When a gift occurs online, Online Bundles are created automatically by Touchpoint.
But those gifts with a TransactionDesc of Recurring Giving
are excluded as they need to be categorized separately.
Lines 87-93
add to the tag called Online with a church specific search.
This search finds contributions in either of the two bundle types Manual Credit Cards
or Payroll Deductions
.
For this code to produce results,
you are required to create new BundleTypes and enter the appropriate contributions into those bundle types.
Recurring
| RowType = 'Recurring'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.TransactionDesc = ['Recurring Giving']
CreateTag(fundSet, RowType, SearchParameters)
|
Lines 95-99
create a tag called Recurring.
All recurring gifts will have a Transaction table row with Recurring Giving
in the TransactionDesc column.
SundayMainWorship
| RowType = 'SundayMainWorship'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.BundleTypes = ['Generic Envelopes','Loose Checks and Cash','Preprinted Envelopes']
CreateTag(fundSet, RowType, SearchParameters)
|
Lines 101-105
create a tag called SundayMainWorship.
The three standard BundleTypes used for offering plate donations are
Generic Envelopes
, Loose Checks and Cash
, and Preprinted Envelopes
Church Specific BundleType Tags
The following sections through Line 155
are all church specific.
All of these sections work by using a custom BundleType which is used to identify the contribution RowTypes for this report.
You can either create these new BundleTypes and start posting contributions to that Bundle
or you can delete these sections for your church.
107
108
109
110
111
112
113 | # church specific
RowType = 'SundayMainWorship'
SearchParameters = model.DynamicData(Base)
SearchParameters.AddToTag = 1
SearchParameters.Priority = NextPriority()
SearchParameters.BundleTypes = ['Sunday Main Worship']
CreateTag(fundSet, RowType, SearchParameters)
|
Lines 108-113
add to the tag called SundayMainWorship with a church specific search.
And requires a BundleType called Sunday Main Worship
.
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 | # church specific
RowType = 'MailedChecksAndCash'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.BundleTypes = ['Mailed Checks & Cash']
CreateTag(fundSet, RowType, SearchParameters)
# church specific
RowType = 'BankDrafts'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.BundleTypes = ['Bank Draft','Bank Drafts']
CreateTag(fundSet, RowType, SearchParameters)
# church specific
RowType = 'SecureGive'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.BundleTypes = ['SecureGive']
CreateTag(fundSet, RowType, SearchParameters)
# church specific
RowType = 'Stock'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.BundleTypes = ['Stock']
CreateTag(fundSet, RowType, SearchParameters)
# church specific
RowType = 'Students'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.BundleTypes = ['Students']
CreateTag(fundSet, RowType, SearchParameters)
# church specific
RowType = 'Hispanic'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.BundleTypes = ['Hispanic']
CreateTag(fundSet, RowType, SearchParameters)
|
The different sections above all require creating BundleTypes of the name referred to in the SearchParameters.BundleTypes assignment.
The exception is Line 126
which contains two possibilities, create a BundleType for just one of these.
NonTaxDeductible
| RowType = 'NonTaxDeductible'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.NonTaxDed = 1
CreateTag(fundSet, RowType, SearchParameters)
|
Lines 157-161
create a tag called NonTaxDeductible.
The SearchParameters.NonTaxDed = 1
does the trick here.
The Unknown Tag
| RowType = 'Unknown'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = NextPriority()
SearchParameters.NonTaxDed = -1
SearchParameters.ContributionTags = "<>Gt{}-%".format(fundSet)
CreateTag(fundSet, RowType, SearchParameters)
|
Lines 163-168
create a tag called Unknown.
This search should not contain any contributions and is meant to catch anything that slips through the cracks.
The search does this with the line SearchParameters.ContributionTags = "<>Gt{}-%".format(fundSet)
.
In other words, it finds contributions that do not already have a contribution tag for the appropriate fundSet.
If the tag is not empty, then those contributions have not been considered in the previous sections
and you need to look closely at them to figure where they should go and what search parameters will work.
Or you may need to create one or more new tags to hold these in logical groupings.
The Total Tag
| RowType = 'Total'
SearchParameters = model.DynamicData(Base)
SearchParameters.Priority = Priority / 100 * 100 + 99 # 199, 299, 399, etc.
SearchParameters.NonTaxDed = -1 # either tax or non-tax
CreateTag(fundSet, RowType, SearchParameters)
|
Lines 170-174
create a tag called Total.
This tag should contain the total of all the previous tags since it does not have any search parameters except for the FundIds for the particular column.
This ends the explanation of the CreateTags function.
Build the Three Columns for the Report
The next lines of code define a function called CreateFundSetColumns
which makes three calls to the CreateTags function, one call for each FundSet/column.
Generally speaking, the first column is intended to be for giving to any of the church’s Funds.
The second column is intended to be for the
single default and main giving fund, such as General Tithe, or whatever you call it at your church.
Then the third column is all the funds other than the main giving fund.
This function has two paths of execution: one for a specific church,
and one for a generic churches which may fit for your church.
You may need to customize one of these two paths for your church based on your fund structure.
You will notice that there are three different sets of Priority numbers
starting with either: 100, 200, or 300.
These numbers correspond to the three FundSets AllFunds
, MainFund
, and Other
which also correspond to the three columns of the report.
The first column’s amounts for AllFunds
should add to the sum of the second two columns.
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 | def CreateFundSetColumns():
global Priority
nc = NameOfChurch
if NameOfChurch == 'Mount Pisgah UMC':
Priority = 100
allFunds = model.CustomStatementsFundIdList('Mount Pisgah Church') # all funds for church
Base.FundIds = allFunds
CreateTags('AllFunds')
Priority=200
Base.FundIds = '180' # Main Giving Fund
CreateTags('MainFund')
# Fund Others, all funds except the main giving fund
Priority=300
Base.FundIds = allFunds.replace('180,', '') #remove fund 180
CreateTags('Other')
else:
Priority = 100 # fundSet1
# All funds included in first fundSet
CreateTags('AllFunds')
# Fund 1 (General Tithe), this highlights the main giving fund in a fundSet
Priority=200 # fundSet2
Base.FundIds = '1'
CreateTags('MainFund')
# Fund Others, all funds except the main giving fund in a fundSet
Priority=300 # fundSet3
Base.FundIds = '<>1'
CreateTags('Other')
|
Lines 176-192
This code path works for the named church only after it has been modified to fit your church.
The FundIds are what are necessary.
See also
If you are using custom Statements and CustomFundSets at your church:
/CustomProgramming/TextScripts/CustomFundSets
Line 177
allows the global variable Priority to be assigned to within the function.
Normally in Python functions all variables are local to the function
and although global variables can be read and used within a function, they cannot be assigned to.
Lines 193-206
This section works for the Generic funds which may or may not work for your church
but is a good starting point.
Wrapping it All Up
Now that all the global data is set and all the functions are defined,
the real work starts here.
All that remains to be done is to call the previously defined functions, and then display the validation report.
208
209
210
211
212
213
214
215
216
217 | model.DeleteContributionTags('Gt%')
CreateDateRangeTags()
CreateFundSetColumns()
json = model.FormatJson(GivingTypesData)
model.WriteContentText('GivingTypesData', json)
html = '\n'.join(ValidationReportList)
print html
|
Line 208
removes the existing set of ContributionTags to make way for this new set.
The tags to be removed start with Gt
using the %
wild card to match anything to the right of Gt.
Lines 210-211
call the two main functions, one to create the date range tags
and the other to create all the tags for the three fund sets.
Lines 213-214
save the GivingTypesData DynamicData object to a text file called GivingTypesData
.
This file contains a record of all the SearchParameters that were used to create the ContributionTags.
The links in the displayed validation report use this file on the screen for each column/row/priority combination.
Lines 216-217
The last two lines display the validation report on the screen
after joining the entire list of lines in ValidationReportList into a single string called html.
The last thing is to view the Validation Report which should display on the screen if you have manually run this script.
Each heading is a link that save the contributions found by each set of SearchParameters to an Excel file.
This should be helpful when customizing and validating your report.