Skip to content

Instantly share code, notes, and snippets.

@forcethesales
Created December 28, 2022 22:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save forcethesales/aa0975f7fa2ac07762a834c22eb70b94 to your computer and use it in GitHub Desktop.
Save forcethesales/aa0975f7fa2ac07762a834c22eb70b94 to your computer and use it in GitHub Desktop.
bulk year end tax receipt
public class qGiftsLastYear implements Database.Batchable<sObject>
//,Database.Stateful
{
//ideally it could be invoked by a flow but that's not being used in this version
@InvocableMethod(description='Year End Tax Flow' )
public static void yearEndTaxMethod () {
database.executeBatch(new qGiftsLastYear(),10); }
public Database.QueryLocator start(Database.BatchableContext bc) {
//get "last year"
Integer year = Date.Today().year()-1;
//return contacts who gave more than one gift last year and their gifts
return Database.getQueryLocator([SELECT LastName, id,Gifts_Last_Year__c, (SELECT Id, CloseDate, Amount FROM Opportunities
WHERE CALENDAR_YEAR(CloseDate) =:year AND IsWon = True ORDER
BY CloseDate) FROM Contact WHERE npo02__OppAmountLastYear__c > 1 LIMIT 200000]);
}
public void execute(Database.BatchableContext bc, List<Contact> scope) {
//process each batch of records
//put the opportunities into a table
List<Contact> contactsForUpdate = new List<Contact>();
String loopString;
String longestString = '<table style="width:100%; border: 1px solid black;"><tr><th style="border: 1px solid black; padding: 15px;"> Date</th> <th style="border: 1px solid black;">Amount</th></tr>';
String dateFormatString = 'MMMM d, yyyy';
String finalString;
for (Contact con : scope) {
for (Opportunity opp : con.opportunities) {
Date d = opp.CloseDate;
Datetime dt = Datetime.newInstance(d.year(), d.month(),d.day());
String dateString = dt.format(dateFormatString);
String cleanAmt = String.valueOf(opp.Amount);
loopString =
'<tr> <td style="border: 1px solid black; padding: 15px;">' + dateString +
'</th> <td style="border: 1px solid black; padding: 15px;"> $' + cleanAmt + '</th> </tr>';
longestString = longestString + loopString;
}
finalstring = longestString + '</table>';
//put the table of gifts into a custom field
con.Gifts_Last_Year__c = String.escapeSingleQuotes(finalstring);
contactsForUpdate.add(con);
//reset the value of longestString to the start. otherwise it's going to add everyone's gifts to the list and keep growing.
longestString = '<table style="width:100%; border: 1px solid black;"><tr><th style="border: 1px solid black; padding: 15px;"> Date</th> <th style="border: 1px solid black;">Amount</th></tr>';
system.debug('Final String' + finalstring);
}
update contactsForUpdate;
}
public void finish(Database.BatchableContext bc){}
}
global class giftsLastYearSchedBatch implements Schedulable {
global void execute(SchedulableContext sc) {
qGiftsLastyear q = new qgiftsLastYear();
database.executebatch(q);
}
}
//Code by Jessie Rymph
//December 21, 2022
//Tests the Year End Gift Batch process using the YearEndtestDataFactory class
//https://wp.me/p9qPLI-1q8
@isTest
public class giftsLastYearSchedBatchTest {
@isTest static void positiveTest() {
// Test data setup
// test for Gifts Last Year
// Create contacts with opps through test utility
Integer testNumC= 2;
Integer testNumO = 2;
contact[] cons = YearEndTestDataFactory.giftsLastYear(testNumC,testNumO);
Test.startTest();
qGiftsLastYear yEGB = new qGiftsLastYear();
Id batchId = Database.executeBatch(yEGB);
Test.stopTest();
List<Contact> contacts = new List<Contact>();
for(Contact person : [SELECT Id, Gifts_Last_Year__c FROM Contact]) {
if(person.Gifts_Last_Year__c.contains('Date')) {
contacts.add(person);
}
}
System.assertEquals(testNumC,contacts.size(),testNumC +' ');
}
@isTest static void negativeTest() {
// Test data setup
// Test that this years gifts do not go into Gifts Last Year
// Create contacts with opps through test utility
Integer testNumC=10;
Integer testNumO = 12;
contact[] cons = YearEndTestDataFactory.GiftsThisYear(testNumC,testNumO);
Test.startTest();
qGiftsLastYear yEGB = new qGiftsLastYear();
Id batchId = Database.executeBatch(yEGB);
Test.stopTest();
List<Contact> contacts = new List<Contact>();
for(Contact person : [SELECT Id, Gifts_Last_Year__c FROM Contact]) {
IF(person.Gifts_Last_Year__c != null) {
contacts.add(person);
}
}
System.assertEquals(0,contacts.size(),'Expected none, got' + contacts.size());
}
@isTest static void schedTest() {
// This test runs a scheduled job at midnight Sept. 3rd. 2022
String CRON_EXP = '0 0 0 3 9 ? 2027';
// Schedule the test job
String jobId = System.schedule('giftsLastYearSchedBatchTest', CRON_EXP, new giftsLastYearSchedBatch());
// Get the information from the CronTrigger API object
CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE id = :jobId];
// Verify the expressions are the same System.assertEquals(CRON_EXP, ct.CronExpression);
// Verify the job has not run
System.assertEquals(0, ct.TimesTriggered);
// Verify the next time the job will run
System.assertEquals('2027-09-03 00:00:00', String.valueOf(ct.NextFireTime));
}
}
//Code by Jessie Rymph
//December 30, 2021
//https://wp.me/p9qPLI-1q8
@isTest
public class yearEndtestDataFactory {
public static Id devRecordTypeId = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('Donation').getRecordTypeId();
//gifts last year
public static List<Contact> giftsThisYear(Integer numCts, Integer numOppsPerCt){
List<Contact> cons = new List<Contact>();
for(Integer i=0;i<numCts;i++) {
Contact a = new Contact(LastName='Test'+i,Email='basket@gmail.com',npo02__OppsClosedThisYear__c =3);
Cons.add(a);
}
insert Cons;
system.debug('insert' + cons);
List<Opportunity> opps = new List<Opportunity>();
for (Integer j=0;j<numCts;j++) {
Contact connie = Cons[j];
//get today's date
Date myDate = system.today();
//get the year from the date
Integer thisYear = myDate.year();
//set a date variable for January 1 of this year. This will be the first gift date.
Date janDate = Date.newInstance(thisyear, 1, 1);
// For each contact just inserted, add opportunities
for (Integer k=0;k<numOppsPerCt;k++) {
opps.add(new Opportunity(Name=connie.Name + ' Opportunity ' + k,
recordTypeid=devRecordTypeId,
AccountId=connie.AccountId,
StageName='Closed Won',
CloseDate=janDate.addmonths(k),
Amount=k+990,
npsp__Primary_Contact__c=connie.Id));
}
}
// Insert all opportunities for all accounts.
insert opps;
system.debug('all Test Opps created');
return cons;
}
public static List<Contact> sendGiftReceiptCheckthisYear(Integer numCts, Integer numOppsPerCt){
List<Contact> cons = new List<Contact>();
for(Integer i=0;i<numCts;i++) {
Contact a = new Contact(LastName='Test'+i,Email='basket@gmail.com',End_of_Year_Gift_Receipt__c=True);
Cons.add(a);
}
insert Cons;
system.debug('insert' + cons);
List<Opportunity> opps = new List<Opportunity>();
for (Integer j=0;j<numCts;j++) {
Contact connie = Cons[j];
//get today's date
Date myDate = system.today();
//get the year from the date
Integer thisYear = myDate.year();
//set a date variable for January 1 of this year. This will be the first gift date.
Date janDate = Date.newInstance(thisyear, 1, 1);
// For each contact just inserted, add opportunities
for (Integer k=0;k<numOppsPerCt;k++) {
opps.add(new Opportunity(Name=connie.Name + ' Opportunity ' + k,
recordTypeid=devRecordTypeId,
AccountId=connie.AccountId,
StageName='Closed Won',
CloseDate=janDate.addyears(k),
Amount=k+990,
npsp__Primary_Contact__c=connie.Id));
}
}
// Insert all opportunities for all accounts.
insert opps;
system.debug('all Test Opps created');
return cons;
}
//gifts two years ago
public static List<Contact> gifts2YearsAgo(Integer numCts, Integer numOppsPerCt){
//create Test Data
Campaign camp = new Campaign (Name = 'Annual Fund');
insert camp;
List<Contact> cons = new List<Contact>();
for(Integer i=0;i<numCts;i++) {
Contact a = new Contact(LastName='Test'+i,Email='basket@gmail.com',npo02__OppAmountLastYear__c=40, npo02__OppAmountThisYear__c=60);
Cons.add(a);
}
insert Cons;
system.debug('insert' + cons);
List<Opportunity> opps = new List<Opportunity>();
for (Integer j=0;j<numCts;j++) {
Contact connie = Cons[j];
//get the year of last year. start by getting today's date.
Date myDate = system.today();
//get the year from the date
Integer thisYear = myDate.year();
//subtract one to make it last year
Integer twoYears = thisYear - 2;
//set a date variable for January 1 of last year. This will be the first gift date.
Date janDate = Date.newInstance(twoYears, 1, 1);
// For each contact just inserted, add opportunities
for (Integer k=0;k<numOppsPerCt;k++) {
opps.add(new Opportunity(Name=connie.Name + ' Opportunity ' + k,
recordTypeid= devRecordTypeId,
AccountId=connie.AccountId,
StageName='Closed Won',
CampaignId = camp.Id,
//for each opp created use the JanDate variable, one month later
CloseDate=janDate.addmonths(k),
Amount=k+990,
npsp__Primary_Contact__c=connie.Id));
}
}
// Insert all opportunities for all accounts.
insert opps;
system.debug('all Test Opps created');
return cons;
}
public static List<Contact> giftsLastYear(Integer numCts, Integer numOppsPerCt){
//create Test Data
Campaign camp = new Campaign (Name = 'Annual Fund');
insert camp;
List<Contact> cons = new List<Contact>();
for(Integer i=0;i<numCts;i++) {
Contact a = new Contact(LastName='Test'+i,Email='basket@gmail.com',npo02__OppAmountLastYear__c=40, npo02__OppAmountThisYear__c=60);
Cons.add(a);
}
insert Cons;
system.debug('insert' + cons);
List<Opportunity> opps = new List<Opportunity>();
for (Integer j=0;j<numCts;j++) {
Contact connie = Cons[j];
//get the year of last year. start by getting today's date.
Date myDate = system.today();
//get the year from the date
Integer thisYear = myDate.year();
//subtract one to make it last year
Integer twoYears = thisYear - 1;
//set a date variable for January 1 of last year. This will be the first gift date.
Date janDate = Date.newInstance(twoYears, 1, 1);
// For each contact just inserted, add opportunities
for (Integer k=0;k<numOppsPerCt;k++) {
opps.add(new Opportunity(Name=connie.Name + ' Opportunity ' + k,
recordTypeid= devRecordTypeId,
AccountId=connie.AccountId,
StageName='Closed Won',
CampaignId = camp.Id,
//for each opp created use the JanDate variable, one month later
CloseDate=janDate.addmonths(k),
Amount=k+990,
npsp__Primary_Contact__c=connie.Id));
}
}
// Insert all opportunities for all accounts.
insert opps;
system.debug('all Test Opps created');
return cons;
}
}
@forcethesales
Copy link
Author

Learn about this code here on the appExchange.
This gist is designed to work with millions of records but we're still getting an apex cpu timeout error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment