Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to ease production deployment #96

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion cumulusci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@ tasks:
robot_testdoc:
options:
path: robot/Membership-Management/tests
output: robot/Membership-Management/doc/Membership-Management_tests.html
output: robot/Membership-Management/doc/Membership-Management_tests.html

flows:
deploy_unmanaged:
steps:
4:
task: None
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,7 @@
</layoutSections>
<platformActionList>
<actionListContext>Record</actionListContext>
<platformActionListItems>
<actionName>FeedItem.TextPost</actionName>
<actionType>QuickAction</actionType>
<sortOrder>0</sortOrder>
</platformActionListItems>
<platformActionListItems>
<actionName>FeedItem.ContentPost</actionName>
<actionType>QuickAction</actionType>
<sortOrder>1</sortOrder>
</platformActionListItems>

<platformActionListItems>
<actionName>Membership__c.New_Membership_Contact_Role</actionName>
<actionType>QuickAction</actionType>
Expand Down
21 changes: 21 additions & 0 deletions src/applications/Membership.app
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomApplication xmlns="http://soap.sforce.com/2006/04/metadata">
<brand>
<headerColor>#0070D2</headerColor>
<shouldOverrideOrgTheme>false</shouldOverrideOrgTheme>
</brand>
<formFactors>Small</formFactors>
<formFactors>Large</formFactors>
<isNavAutoTempTabsDisabled>false</isNavAutoTempTabsDisabled>
<isNavPersonalizationDisabled>false</isNavPersonalizationDisabled>
<label>Membership</label>
<navType>Standard</navType>
<tabs>standard-home</tabs>
<tabs>standard-Account</tabs>
<tabs>standard-Contact</tabs>
<tabs>Membership__c</tabs>
<tabs>standard-report</tabs>
<tabs>standard-Dashboard</tabs>
<uiType>Lightning</uiType>
<utilityBar>Membership_UtilityBar</utilityBar>
</CustomApplication>
17 changes: 17 additions & 0 deletions src/classes/ConfigurationService.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
public without sharing class ConfigurationService {
public List<String> getIndividualMembershipTypes() {
return new List<String>{'Individual'};
}

public List<String> getHouseholdMembershipTypes() {
return new List<String>{'Household'};
}

public List<String> getCorporateMembershipTypes() {
return new List<String>{'Corporate'};
}

public List<String> getNonIndividualMembershipTypes() {
return new List<String>{'Household', 'Corporate'};
}
}
5 changes: 5 additions & 0 deletions src/classes/ConfigurationService.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>49.0</apiVersion>
<status>Active</status>
</ApexClass>
37 changes: 37 additions & 0 deletions src/classes/ContactHandler.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
public with sharing class ContactHandler extends TriggerHandler {
public override void afterInsert() {
Map<Id, Id> contactsEnteringAccountsMap = new Map<Id, Id>();

for (Contact c : (List<Contact>)Trigger.new) {
if (c.AccountId != null) {
contactsEnteringAccountsMap.put(c.Id, c.AccountId);
}
}

MembershipContactRoleService mcrs = new MembershipContactRoleService();

mcrs.addContactRolesForAddedContacts(contactsEnteringAccountsMap);
}

public override void afterUpdate() {
// Handle reparented Contacts
Map<Id, Id> contactsLeavingAccountsMap = new Map<Id, Id>();
Map<Id, Id> contactsEnteringAccountsMap = new Map<Id, Id>();

for (Contact c : (List<Contact>)Trigger.new) {
Contact old = ((Map<Id, Contact>)Trigger.oldMap).get(c.Id);
if (c.AccountId != old.AccountId && c.AccountId != null) {
contactsEnteringAccountsMap.put(c.Id, c.AccountId);
}
if (c.AccountId != old.AccountId && old.AccountId != null) {
contactsLeavingAccountsMap.put(c.Id, old.AccountId);
}
}

MembershipContactRoleService mcrs = new MembershipContactRoleService();

mcrs.deactivateContactRolesForMovedContacts(contactsLeavingAccountsMap);
mcrs.addContactRolesForAddedContacts(contactsEnteringAccountsMap);

}
}
5 changes: 5 additions & 0 deletions src/classes/ContactHandler.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>49.0</apiVersion>
<status>Active</status>
</ApexClass>
88 changes: 88 additions & 0 deletions src/classes/MembershipContactRoleService.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// This class is `without sharing` to ensure data integrity
public without sharing class MembershipContactRoleService {
@TestVisible private ConfigurationService cs;

public MembershipContactRoleService() {
cs = new ConfigurationService();
}

public void deactivateContactRolesForMovedContacts(
Map<Id, Id> movedContactsFromHouseholdsMap
) {
// Locate the Memberships associated with the former
// Households of these moved Contacts

List<String> applicableMembershipTypes = cs.getNonIndividualMembershipTypes();

List<Membership_Contact_Role__c> mcrs = [
SELECT Id, Contact__c, Membership__r.Account__c
FROM Membership_Contact_Role__c
WHERE Contact__c IN :movedContactsFromHouseholdsMap.keySet()
AND Membership__r.Account__c IN :movedContactsFromHouseholdsMap.values()
AND Membership__r.Type__c IN :applicableMembershipTypes
];
List<Membership_Contact_Role__c> toUpdate = new List<Membership_Contact_Role__c>();

// Update their End Dates to today.
for (Membership_Contact_Role__c mcr : mcrs) {
// Ensure this is an affected MCR - we over-select and may get cross-household MCRs.
if (movedContactsFromHouseholdsMap.get(mcr.Contact__c) == mcr.Membership__r.Account__c) {
mcr.End_Date__c = Date.today();
toUpdate.add(mcr);
}
}

update mcrs;
}

public void addContactRolesForAddedContacts(
Map<Id, Id> addedContactsToHouseholdsMap
) {
// Locate all Household-type memberships for the Households to which Contacts
// have been added.

List<String> applicableMembershipTypes = cs.getNonIndividualMembershipTypes();

List<Membership__c> memberships = [
SELECT Id, Name, Type__c, End_Date__c, Account__c
FROM Membership__c
WHERE Account__c IN :addedContactsToHouseholdsMap.values()
AND Type__c IN :applicableMembershipTypes
AND (Start_Date__c <= :Date.today() OR Start_Date__c = null)
AND (End_Date__c >= :Date.today() OR Does_Not_Expire__c = true)
];

// Process them into a Map<Id, List<Membership__c>> keyed on Account Id
Map<Id, List<Membership__c>> membershipMap = new Map<Id, List<Membership__c>>();
for (Membership__c m : memberships) {
if (!membershipMap.containsKey(m.Account__c)) {
membershipMap.put(m.Account__c, new List<Membership__c>());
}

membershipMap.get(m.Account__c).add(m);
}

// Iterate over Contacts and accumulate a list of new Membership Contact Roles.
List<Membership_Contact_Role__c> toInsert = new List<Membership_Contact_Role__c>();
for (Id contactId : addedContactsToHouseholdsMap.keySet()) {
if (!membershipMap.containsKey(addedContactsToHouseholdsMap.get(contactId))) {
continue;
}

for (Membership__c m : membershipMap.get(addedContactsToHouseholdsMap.get(contactId))) {
toInsert.add(
new Membership_Contact_Role__c(
Name = m.Name + ' ' + String.valueOf(Date.today().year()),
Contact__c = contactId,
Membership__c = m.Id,
Role__c = 'Household Member',
Start_Date__c = Date.today(),
End_Date__c = m.End_Date__c
)
);
}
}

insert toInsert;
}
}
5 changes: 5 additions & 0 deletions src/classes/MembershipContactRoleService.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>49.0</apiVersion>
<status>Active</status>
</ApexClass>
163 changes: 163 additions & 0 deletions src/classes/MembershipContactRoleService_TEST.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
@isTest
private without sharing class MembershipContactRoleService_TEST {
@testSetup
private static void testSetup() {
List<Account> accounts = new List<Account>{
new Account(Name = 'First Account'),
new Account(Name = 'Second Account'),
new Account(Name = 'Account Without Memberships')
};
insert accounts;

List<Membership__c> memberships = new List<Membership__c>{
new Membership__c(
Name = 'First Membership',
Account__c = accounts[0].Id,
Start_Date__c = Date.today(),
Does_Not_Expire__c = true,
Type__c = 'Corporate'
),
new Membership__c(
Name = 'Expired Membership',
Account__c = accounts[0].Id,
Start_Date__c = Date.today() - 10,
End_Date__c = Date.today() - 5,
Type__c = 'Corporate'
),
new Membership__c(
Name = 'Second Membership',
Account__c = accounts[1].Id,
Start_Date__c = Date.today(),
Does_Not_Expire__c = true,
Type__c = 'Household'
)
};
insert memberships;
}

@isTest
private static void testAddContactToAccountAddsMCRs() {
Test.startTest();
List<Contact> cs = new List<Contact>{
new Contact(
AccountId = [SELECT Id FROM Account WHERE Name = 'First Account'].Id,
FirstName = 'Molly',
LastName = 'Member'
),
new Contact(
AccountId = [SELECT Id FROM Account WHERE Name = 'First Account'].Id,
FirstName = 'Mikaela',
LastName = 'Member'
)
};
insert cs;

List<Membership_Contact_Role__c> mcrs = [
SELECT Id, Name, Start_Date__c, Role__c, Membership__c, Contact__c
FROM Membership_Contact_Role__c
WHERE Contact__c = :cs[0].Id
];
System.assertEquals(1, mcrs.size(), 'expected 1 Role');
System.assertEquals('First Membership ' + Date.today().year(), mcrs[0].Name);
System.assertEquals(Date.today(), mcrs[0].Start_Date__c);
System.assertEquals('Household Member', mcrs[0].Role__c);

mcrs = [
SELECT Id, Name, Start_Date__c, Role__c, Membership__c, Contact__c
FROM Membership_Contact_Role__c
WHERE Contact__c = :cs[1].Id
];
System.assertEquals(1, mcrs.size(), 'expected 1 Role');
System.assertEquals('First Membership ' + Date.today().year(), mcrs[0].Name);
System.assertEquals(Date.today(), mcrs[0].Start_Date__c);
System.assertEquals('Household Member', mcrs[0].Role__c);
}

@isTest
private static void testRemoveContactFromAccountDeactivatesMCRs() {
Test.startTest();
List<Contact> cs = new List<Contact>{
new Contact(
AccountId = [SELECT Id FROM Account WHERE Name = 'First Account'].Id,
FirstName = 'Molly',
LastName = 'Member'
),
new Contact(
AccountId = [SELECT Id FROM Account WHERE Name = 'First Account'].Id,
FirstName = 'Mikaela',
LastName = 'Member'
)
};
insert cs;

cs[0].AccountId = null;
cs[1].AccountId = null;
update cs;

List<Membership_Contact_Role__c> mcrs = [
SELECT Id, Name, Start_Date__c, End_Date__c, Role__c, Membership__c, Contact__c
FROM Membership_Contact_Role__c
WHERE Contact__c = :cs[0].Id
];
System.assertEquals(1, mcrs.size(), 'expected 1 Role');
System.assertEquals('First Membership ' + Date.today().year(), mcrs[0].Name);
System.assertEquals(Date.today(), mcrs[0].Start_Date__c);
System.assertEquals(Date.today(), mcrs[0].End_Date__c);
System.assertEquals('Household Member', mcrs[0].Role__c);

mcrs = [
SELECT Id, Name, Start_Date__c, End_Date__c, Role__c, Membership__c, Contact__c
FROM Membership_Contact_Role__c
WHERE Contact__c = :cs[1].Id
];
System.assertEquals(1, mcrs.size(), 'expected 1 Role');
System.assertEquals('First Membership ' + Date.today().year(), mcrs[0].Name);
System.assertEquals(Date.today(), mcrs[0].Start_Date__c);
System.assertEquals(Date.today(), mcrs[0].End_Date__c);
System.assertEquals('Household Member', mcrs[0].Role__c);
}

@isTest
private static void testAddContactToAccountWithoutMemberships() {
Test.startTest();
Contact c = new Contact(
AccountId = [SELECT Id FROM Account WHERE Name = 'Account Without Memberships'].Id,
LastName = 'Member'
);
insert c;

List<Membership_Contact_Role__c> mcrs = [
SELECT Id
FROM Membership_Contact_Role__c
WHERE Contact__c = :c.Id
];
System.assertEquals(0, mcrs.size(), 'expected no Roles');
}

@isTest
private static void testRemoveContactFromAccountWithoutMemberships() {
Test.startTest();
Contact c = new Contact(
AccountId = [SELECT Id FROM Account WHERE Name = 'Account Without Memberships'].Id,
LastName = 'Member'
);
insert c;

List<Membership_Contact_Role__c> mcrs = [
SELECT Id
FROM Membership_Contact_Role__c
WHERE Contact__c = :c.Id
];
System.assertEquals(0, mcrs.size(), 'expected no Roles');

c.AccountId = null;
update c;

mcrs = [
SELECT Id
FROM Membership_Contact_Role__c
WHERE Contact__c = :c.Id
];
System.assertEquals(0, mcrs.size(), 'expected no Roles');
}
}
5 changes: 5 additions & 0 deletions src/classes/MembershipContactRoleService_TEST.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>49.0</apiVersion>
<status>Active</status>
</ApexClass>
Loading