From 1402d0464ed3ce80202dfc0f0d2923b14288276c Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Tue, 7 Nov 2023 11:54:41 -0300 Subject: [PATCH] tweaks for close ticket contact campaign deletion behaviour --- core/models/campaigns.go | 27 +++++++++++++++++++++++++ core/models/campaigns_test.go | 37 +++++++++++++++++++++++++++++++++++ core/models/contacts.go | 10 +++++++--- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/core/models/campaigns.go b/core/models/campaigns.go index 46c050da7..de1f964fd 100644 --- a/core/models/campaigns.go +++ b/core/models/campaigns.go @@ -494,6 +494,33 @@ func DeleteUnfiredContactEvents(ctx context.Context, tx Queryer, contactIDs []Co return nil } +func DeleteUnfiredContactEventsFromGroups(ctx context.Context, tx Queryer, contactIDs []ContactID, groupIDs []GroupID) error { + if len(contactIDs) == 0 || len(groupIDs) == 0 { + return nil + } + _, err := tx.ExecContext(ctx, deleteUnfiredContactEventsFromGroupsSQL, pq.Array(contactIDs), pq.Array(groupIDs)) + if err != nil { + return errors.Wrapf(err, "error deleting unfired contacts events by groups") + } + return nil +} + +const deleteUnfiredContactEventsFromGroupsSQL = ` +DELETE FROM + public.campaigns_eventfire +WHERE contact_id = ANY ($1) + AND event_id = ANY ( + SELECT id + FROM public.campaigns_campaignevent + WHERE campaign_id IN ( + SELECT id + FROM public.campaigns_campaign + WHERE group_id = ANY ($2) + ) + ) + AND fired IS NULL; +` + const insertEventFiresSQL = ` INSERT INTO campaigns_eventfire(contact_id, event_id, scheduled) VALUES(:contact_id, :event_id, :scheduled) diff --git a/core/models/campaigns_test.go b/core/models/campaigns_test.go index 3781f74b7..cabdfa4e6 100644 --- a/core/models/campaigns_test.go +++ b/core/models/campaigns_test.go @@ -114,3 +114,40 @@ func TestAddEventFires(t *testing.T) { testsuite.AssertQuery(t, db, `SELECT count(*) FROM campaigns_eventfire WHERE contact_id = $1 AND event_id = $2`, testdata.Cathy.ID, testdata.RemindersEvent1.ID).Returns(2) testsuite.AssertQuery(t, db, `SELECT count(*) FROM campaigns_eventfire WHERE contact_id = $1`, testdata.Bob.ID).Returns(2) } + +func TestDeleteEventContactFiresFromGroups(t *testing.T) { + ctx, rt, db, _ := testsuite.Get() + + defer testsuite.Reset(testsuite.ResetDB) + + // create a test group + testdata.InsertContactGroup(db, testdata.Org1, "94c816d7-cc87-42db-a577-ce072ceaab81", "GroupTest", "") + + // create a campaign related to the created group + db.MustExec(`INSERT INTO public.campaigns_campaign + (id, is_active, created_on, modified_on, uuid, "name", is_archived, created_by_id, group_id, modified_by_id, org_id) + VALUES(30001, true, '2021-12-20 11:31:42.996', '2021-12-20 11:31:42.996', '72aa12c5-cc11-4bc7-9406-044047845c72', 'Doctor Reminders 2', false, 2, 30000, 2, 1); + `) + db.MustExec(`INSERT INTO public.campaigns_campaignevent + (id, is_active, created_on, modified_on, uuid, event_type, "offset", unit, start_mode, message, delivery_hour, campaign_id, created_by_id, flow_id, modified_by_id, relative_to_id) + VALUES(30001, true, '2021-12-20 11:31:43.038', '2021-12-20 11:31:43.038', 'aff4b8ac-2534-420f-a353-66a3e74b6e10', 'M', 10, 'M', 'I', '"eng"=>"Hi @contact.name, it is time to consult with your patients.", "fra"=>"Bonjour @contact.name, il est temps de consulter vos patients."', -1, 30001, 2, 10009, 2, 8); + `) + // insert a event fire for cathy from the created event + db.MustExec(`INSERT INTO public.campaigns_eventfire + (id, scheduled, fired, fired_result, contact_id, event_id) + VALUES(1, '2023-11-07 11:03:18.416', NULL, NULL, 10000, 30001);`) + + // previous event fire created must be present here as 1 row returned + testsuite.AssertQuery(t, db, `SELECT count(*) FROM public.campaigns_eventfire`).Returns(1) + + oa, err := models.GetOrgAssetsWithRefresh(ctx, rt, testdata.Org1.ID, models.RefreshNone) + require.NoError(t, err) + + _, cathy := testdata.Cathy.Load(db, oa) + + err = models.DeleteUnfiredContactEventsFromGroups(ctx, db, []models.ContactID{models.ContactID(cathy.ID())}, []models.GroupID{models.GroupID(30000)}) + require.NoError(t, err) + + // after delete the event fire returned rows must be 0 + testsuite.AssertQuery(t, db, `SELECT count(*) FROM public.campaigns_eventfire;`).Returns(0) +} diff --git a/core/models/contacts.go b/core/models/contacts.go index 2657529ff..5be605e39 100644 --- a/core/models/contacts.go +++ b/core/models/contacts.go @@ -604,7 +604,6 @@ func CreateContact(ctx context.Context, db QueryerWithTx, oa *OrgAssets, userID // * If URNs exist but are orphaned it creates a new contact and assigns those URNs to them. // * If URNs exists and belongs to a single contact it returns that contact (other URNs are not assigned to the contact). // * If URNs exists and belongs to multiple contacts it will return an error. -// func GetOrCreateContact(ctx context.Context, db QueryerWithTx, oa *OrgAssets, urnz []urns.URN, channelID ChannelID) (*Contact, *flows.Contact, bool, error) { // ensure all URNs are normalized for i, urn := range urnz { @@ -962,8 +961,13 @@ func CalculateDynamicGroups(ctx context.Context, db Queryer, org *OrgAssets, con return errors.Wrapf(err, "error removing contact from group") } - // clear any unfired campaign events for this contact - err = DeleteUnfiredContactEvents(ctx, db, contactIDs) + removedGroupsIDs := []GroupID{} + for _, grs := range groupRemoves { + removedGroupsIDs = append(removedGroupsIDs, grs.GroupID) + } + + // clear any unfired campaign events for this contact referent to removed groups + err = DeleteUnfiredContactEventsFromGroups(ctx, db, contactIDs, removedGroupsIDs) if err != nil { return errors.Wrapf(err, "error deleting unfired events") }