generated from OpenFn/project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathopenfn-f07240d8-8bb7-4cff-9e20-cc8d8059892f-state.json
167 lines (167 loc) · 15.4 KB
/
openfn-f07240d8-8bb7-4cff-9e20-cc8d8059892f-state.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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
156
157
158
159
160
161
162
163
164
165
166
167
{
"id": "f07240d8-8bb7-4cff-9e20-cc8d8059892f",
"name": "gife-salesforce-to-mailchimp",
"description": null,
"concurrency": null,
"inserted_at": "2024-03-19T13:09:53Z",
"updated_at": "2025-02-27T14:39:16Z",
"scheduled_deletion": null,
"project_credentials": {
"[email protected]": {
"id": "7085f9d0-6bc9-403d-8e9b-cea31d66593a",
"name": "GIFE - Salesforce Production - Evan",
"owner": "[email protected]"
},
"[email protected]": {
"id": "e3e5410c-ff69-4373-9cb1-2850551a1543",
"name": "GIFE - MailChimp",
"owner": "[email protected]"
},
"[email protected]": {
"id": "88f01b04-692a-4e63-b1f1-4fb0b3e04cf3",
"name": "GIFE - MailChimp Teste",
"owner": "[email protected]"
},
"[email protected]": {
"id": "447cb045-646a-4b01-a7d4-182bc566363a",
"name": "GIFE Production Salesforce - Mari",
"owner": "[email protected]"
},
"[email protected]": {
"id": "538b75a8-52d5-480a-bc89-68b6f7104120",
"name": "GIFE Production Salesforce - Emilie",
"owner": "[email protected]"
},
"mribeirocruz@verasolutions.org-Sandbox---OpenFn-Mailchimp-integration-2": {
"id": "becd5822-0191-4800-8a19-c7e24ff3589c",
"name": "Sandbox - OpenFn Mailchimp integration 2",
"owner": "[email protected]"
},
"[email protected]": {
"id": "abb69f2c-78d5-467a-adf6-58a98ceb53f9",
"name": "Sandbox Mailchimp Shreya",
"owner": "[email protected]"
},
"[email protected]": {
"id": "658eb830-d38f-46e5-87a6-cd60bbf3b83d",
"name": "Mailchimp - Will - Test enviroment 3",
"owner": "[email protected]"
},
"[email protected]": {
"id": "42df6cdd-f792-478b-8f7a-4c73dd913c81",
"name": "Mailchimp HTTP - test credential",
"owner": "[email protected]"
},
"[email protected]": {
"id": "b2f164e7-3e80-4aaf-8184-b4eb49b740e4",
"name": "GIFE - MailChimp - Mari",
"owner": "[email protected]"
},
"[email protected]": {
"id": "d3c0c70f-b20f-42f0-ad6b-8c70eeb03f65",
"name": "Mailchimp Test Environment - Mari",
"owner": "[email protected]"
}
},
"history_retention_period": 180,
"dataclip_retention_period": 180,
"retention_policy": "retain_all",
"collections": {},
"workflows": {
"Upsert-Members": {
"id": "c1873753-c335-40ad-8fcc-bc3a347ca0e0",
"name": "Upsert Members",
"inserted_at": "2025-03-05T06:46:12.935528Z",
"lock_version": 48,
"triggers": {
"cron": {
"enabled": true,
"id": "b22a60d5-7c93-4ebd-805b-772b9f738e76",
"type": "cron",
"cron_expression": "*/150 * * * *"
}
},
"jobs": {
"Get-members-for-upsert": {
"id": "767da658-51fe-49e6-a3a8-a90695c51dc7",
"name": "Get members for upsert",
"body": "fn(state => {\n const manualCursor = '2025-03-01T15:30:00.000Z';\n //console.log(manualCursor, 'manualCursor');\n\n const cursor = state.lastRunTime || manualCursor;\n const lastRunTime = new Date().toISOString();\n console.log('time at job start:: ', lastRunTime);\n console.log('Cursor date to use in queries:: ', cursor);\n\n return { ...state, cursor, lastRunTime };\n});\n\nbulkQuery(\n state => `\nSELECT Id, Name, FirstName, LastName, Email, CreatedDate,\n Contact.AccountId, Contact.LastModifiedDate, Contact.CreatedDate,\n Campaign.Name, Campaign.Nome_da_Tag__c\nFROM CampaignMember\nWHERE Campaign.RecordType.Name = 'Grupos, RTs ou Áreas Temáticas'\n AND Campaign.IsActive = true\n AND (Contact.LastModifiedDate > ${state.cursor} OR CreatedDate > ${state.cursor})\n`\n);\n\n//Seperate members for each batch\nfn(state => {\n const lastRunTime = state; \n const campaignMembers = state.data;\n const membersToCreate = [];\n const membersToUpdate = [];\n\n console.log(campaignMembers.length, 'campaignMembers');\n\n for (const member of campaignMembers) {\n const mappedMember = {\n email_address: member.Email,\n full_name: member.Name,\n merge_fields: {\n FNAME: member.FirstName,\n LNAME: member.LastName,\n MMERGE4: member['Contact.AccountId'],\n },\n tags: [member['Campaign.Nome_da_tag__c']],\n };\n if (\n member['Contact.LastModifiedDate'] > state.cursor ||\n member.CreatedDate > state.cursor\n ) {\n membersToCreate.push({ ...mappedMember, status: 'subscribed' });\n } else {\n membersToUpdate.push(mappedMember);\n }\n }\n\n console.log(membersToCreate.length, 'membersToCreate before merge tags');\n console.log(membersToUpdate.length, 'membersToUpdate before merge tags');\n\n let mergeCreateMemberTags = [];\n let mergeUpdateMemberTags = [];\n\n if (membersToCreate.length > 0) {\n mergeCreateMemberTags = membersToCreate.reduce((result, item) => {\n const existingItem = result.find(\n existing => existing.email_address === item.email_address\n );\n\n if (existingItem) {\n existingItem.tags = [...new Set([...existingItem.tags, ...item.tags])];\n } else {\n result.push(item);\n }\n\n return result;\n }, []);\n }\n\n if (membersToUpdate.length > 0) {\n mergeUpdateMemberTags = membersToUpdate.reduce((result, item) => {\n const existingItem = result.find(\n existing => existing.email_address === item.email_address\n );\n\n if (existingItem) {\n existingItem.tags = [...new Set([...existingItem.tags, ...item.tags])];\n } else {\n result.push(item);\n }\n return result;\n }, []);\n }\n\n console.log(\n mergeCreateMemberTags.length,\n 'mergeCreateMemberTags after merge tags'\n );\n\n console.log(\n mergeUpdateMemberTags.length,\n 'mergeUpdateMemberTags after merge tags'\n );\n\n return {\n ...state,\n references: [],\n members: [\n ...chunk(mergeCreateMemberTags, 500),\n ...chunk(mergeUpdateMemberTags, 500),\n ],\n chunkErrors: [],\n };\n});\n",
"adaptor": "@openfn/[email protected]",
"project_credential_id": "447cb045-646a-4b01-a7d4-182bc566363a"
},
"Add-or-update-member-tags": {
"id": "b302b4b7-aa10-499c-b91a-cc9f5cf3a50b",
"name": "Add or update member tags",
"body": "// Add or Update members to Mailchimp\neach(\n '$.members[*]',\n post(\n '/lists/43fead6cd7',\n state => {\n console.log(`Upserting ${state.data.length} members...`);\n return {\n sync_tags: false,\n update_existing: true,\n email_type: 'html',\n members: state.data,\n };\n },\n {},\n state => {\n if (state.response.total_created > 0)\n console.log(`Added ${state.response.total_created} members`);\n if (state.response.total_updated > 0)\n console.log(`Updated ${state.response.total_updated} members`);\n\n if (state.response.error_count > 0)\n state.chunkErrors.push(state.response.errors);\n return state;\n }\n )\n);\n\n// Alert admin if response has errors\nfn(state => {\n // Check if chunks response has errors\n const chunkErrors = state.chunkErrors.flat();\n if (chunkErrors.length > 0) {\n throw new Error(JSON.stringify(chunkErrors, null, 2));\n }\n return state;\n});\n",
"adaptor": "@openfn/[email protected]",
"project_credential_id": "b2f164e7-3e80-4aaf-8184-b4eb49b740e4"
}
},
"edges": {
"cron->Get-members-for-upsert": {
"enabled": true,
"id": "e8588202-23da-42b3-8ee5-b04cff8342ee",
"target_job_id": "767da658-51fe-49e6-a3a8-a90695c51dc7",
"source_trigger_id": "b22a60d5-7c93-4ebd-805b-772b9f738e76",
"condition_type": "always"
},
"Get-members-for-upsert->Add-or-update-member-tags": {
"enabled": true,
"id": "11ccb755-d08e-4c78-ad2e-dbea16de18eb",
"target_job_id": "b302b4b7-aa10-499c-b91a-cc9f5cf3a50b",
"source_job_id": "767da658-51fe-49e6-a3a8-a90695c51dc7",
"condition_type": "on_job_success"
}
}
},
"Remove-Deleted-Campaign-Members/Tags": {
"id": "273e2c2a-a97d-49eb-bebb-2dad0666a716",
"name": "Remove Deleted Campaign Members/Tags",
"inserted_at": "2025-03-05T06:48:02.711520Z",
"lock_version": 247,
"triggers": {
"cron": {
"enabled": true,
"id": "cf67b9c5-e2e0-4ca1-8aca-8e7f32c79d98",
"type": "cron",
"cron_expression": "*/150 * * * *"
}
},
"jobs": {
"Get-deleted-campaign-members": {
"id": "de821b2b-f7f8-4cc3-ad8f-c746c8698b0f",
"name": "Get deleted campaign members",
"body": "// To test with manual cursor simply create a new input with lastRunTime as the manual cursor\n// cursor($.lastRunTime || '2023-08-16T15:30:00.000Z', { key: 'lastSyncTime' });\n// cursor('now', { key: 'lastRunTime', format: c => new Date(c).toISOString() });\nfn(state => {\n delete state?.members\n delete state?.references\n const manualCursor = '2023-08-16T15:30:00.000Z'; // SF timestamp\n state.lastSyncTime = state.lastRunTime || manualCursor;\n state.lastRunTime = new Date().toISOString();\n console.log('Cursor date to use in SF queries:: ', state.lastSyncTime); \n return state;\n});\n\n//Get Deleted Campaign Member Records in Salesforce since last run\nbulkQuery(\n `SELECT Contact__r.Id, Contact__r.Name, Email__c, Nome_da_Tag__c FROM Deleted_Campaign_Member__c WHERE CreatedDate > ${$.lastSyncTime}`\n).then(state => {\n const uniqueContactsMap = new Map();\n state.data.forEach(contact => {\n uniqueContactsMap.set(contact['Contact__r.Id'], contact);\n });\n\n const uniqueContacts = Array.from(uniqueContactsMap.values());\n state.deletedMembers = uniqueContacts;\n state.contactIdsList = uniqueContacts\n .map(contact => `'${contact['Contact__r.Id']}'`)\n .join(', ');\n\n console.log('Unique Contact IDs List:', uniqueContacts?.length);\n return state;\n});\n\nfnIf(!$.contactIdsList, state => {\n console.log('No contact IDs found. Skipping second bulk query.');\n return state;\n});\n\n//Get corresponding Campaign Member details for Deleted Campaign Members\nfnIf(\n $.contactIdsList,\n bulkQuery(\n `SELECT Contact.Id, Contact.Name, Contact.Email, Campaign_Tag_Name__c FROM CampaignMember WHERE Campaign.RecordType.Name = 'Grupos, RTs ou Áreas Temáticas' AND Campaign.IsActive = true AND Contact.Id IN (${$.contactIdsList})`\n ).then(state => {\n const deletedMembers = state.deletedMembers.map(i => ({\n \"Campaign_Tag_Name__c\": \"\",\n \"Contact.Email\": i[\"Email__c\"],\n \"Contact.Id\": i[\"Contact__r.Id\"],\n \"Contact.Name\": i[\"Contact__r.Name\"]\n\n }))\n const campaginMembers = [...state.data, ...deletedMembers];\n \n\n console.log(campaginMembers.length, 'Deleted Campaign Members');\n if (!campaginMembers.length > 0) {\n console.log(\n 'No campaing members found for contacts ids: ',\n state.contactIdsList\n );\n return state;\n }\n\n let mergeMemberTags = [];\n for (const member of campaginMembers) {\n const email = member['Contact.Email'];\n const campaignName = member.Campaign_Tag_Name__c;\n // Find the existing mapped member for this email\n const existingMember = mergeMemberTags.find(\n item => item.email_address === email\n );\n if (existingMember) {\n console.log('Existing member found', { campaignName });\n // If the email already exists, add the campaign name to its tags array\n campaignName && existingMember.tags.push(campaignName);\n } else {\n // If the email doesn't exist, create a new mapped member\n const newMember = {\n email_address: email,\n tags: campaignName\n ? [campaignName].map(str => str.replace(/\\n/g, ''))\n : [],\n email_type: 'html',\n };\n mergeMemberTags.push(newMember);\n }\n }\n console.log(mergeMemberTags.length, 'Retrieved mapped members');\n\n state.members = [...chunk(mergeMemberTags, 500)];\n return state;\n })\n);\n\nfnIf(!$.members && $.deletedMembers.length > 0, state => {\n console.log('Query 2 had 0 results mapping using query 1');\n state.members = [...chunk(state.deletedMembers.map(m => ({\n email_address: m['Email__c'],\n tags: [],\n email_type: 'html',\n })), 500)];\n return state;\n});\n",
"adaptor": "@openfn/[email protected]",
"project_credential_id": "447cb045-646a-4b01-a7d4-182bc566363a"
},
"Remove-deleted-members-tags": {
"id": "d839d64f-78f7-4178-ab9d-482bbedd8866",
"name": "Remove deleted members tags",
"body": "//Sync contacts and create only active campaign tags\n//'/lists/25299978a7 Mailchimp Shreya's Test' 8eec4f86ed Will's Mailchimp Test,\n//'/lists/a2ff510317', //will enviroment test 3\n//'/lists/43fead6cd7',\neach(\n $.members,\n post('/lists/43fead6cd7', state => {\n const payload = {\n sync_tags: true,\n update_existing: true,\n email_type: 'html',\n members: state.data,\n };\n console.log('Sending payload to Mailchimp', payload);\n return payload;\n })\n .catch((error, state) => {\n console.log(error);\n return state;\n })\n .then(state => {\n console.log(\n 'Mailchimp updated_members response',\n state.data.updated_members.length\n );\n console.log(\n 'Mailchimp new_members response',\n state.data.new_members.length\n );\n state.chunkErrors ??= [];\n state.chunkErrors.push(state.response.errors);\n return state;\n })\n);\n\n// Alert admin if response has errors\nfn(state => {\n const { lastSyncTime, lastRunTime } = state;\n // Check if response has errors\n const chunkErrors = state.chunkErrors.flat().filter(Boolean);\n if (chunkErrors.length > 0) {\n throw new Error(JSON.stringify(chunkErrors, null, 2));\n }\n // return state;\n return { lastSyncTime, lastRunTime };\n});\n",
"adaptor": "@openfn/[email protected]",
"project_credential_id": "b2f164e7-3e80-4aaf-8184-b4eb49b740e4"
}
},
"edges": {
"cron->Get-deleted-campaign-members": {
"enabled": true,
"id": "52a622f3-ab69-4453-9a42-698cc4bf0ff5",
"target_job_id": "de821b2b-f7f8-4cc3-ad8f-c746c8698b0f",
"source_trigger_id": "cf67b9c5-e2e0-4ca1-8aca-8e7f32c79d98",
"condition_type": "always"
},
"Get-deleted-campaign-members->Remove-deleted-members-tags": {
"enabled": true,
"id": "d0104c99-4efe-4783-9314-f10421927c65",
"target_job_id": "d839d64f-78f7-4178-ab9d-482bbedd8866",
"source_job_id": "de821b2b-f7f8-4cc3-ad8f-c746c8698b0f",
"condition_type": "js_expression",
"condition_label": "has-members",
"condition_expression": "state?.members?.length > 0 && !state.errors\n"
}
}
}
},
"requires_mfa": false
}