mcdev 7.10.0 → 7.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
- package/@types/lib/index.d.ts +4 -4
- package/@types/lib/index.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Asset.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Automation.d.ts +62 -51
- package/@types/lib/metadataTypes/Automation.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtract.d.ts +13 -2
- package/@types/lib/metadataTypes/DataExtract.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Event.d.ts +8 -0
- package/@types/lib/metadataTypes/Event.d.ts.map +1 -1
- package/@types/lib/metadataTypes/ImportFile.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MetadataType.d.ts +19 -3
- package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MobileMessage.d.ts.map +1 -1
- package/@types/lib/metadataTypes/SenderProfile.d.ts +3 -1
- package/@types/lib/metadataTypes/SenderProfile.d.ts.map +1 -1
- package/@types/lib/metadataTypes/definitions/Automation.definition.d.ts +37 -1
- package/@types/lib/metadataTypes/definitions/DataExtract.definition.d.ts +21 -3
- package/@types/lib/metadataTypes/definitions/SenderProfile.definition.d.ts +3 -1
- package/@types/lib/util/util.d.ts +1 -0
- package/@types/lib/util/util.d.ts.map +1 -1
- package/@types/lib/util/validations.d.ts.map +1 -1
- package/@types/types/mcdev.d.d.ts +32 -0
- package/@types/types/mcdev.d.d.ts.map +1 -1
- package/lib/index.js +14 -7
- package/lib/metadataTypes/Asset.js +4 -5
- package/lib/metadataTypes/Automation.js +202 -399
- package/lib/metadataTypes/DataExtension.js +1 -1
- package/lib/metadataTypes/DataExtract.js +41 -6
- package/lib/metadataTypes/DomainVerification.js +1 -1
- package/lib/metadataTypes/EmailSend.js +3 -3
- package/lib/metadataTypes/Event.js +39 -20
- package/lib/metadataTypes/FileTransfer.js +5 -5
- package/lib/metadataTypes/ImportFile.js +9 -7
- package/lib/metadataTypes/Journey.js +4 -9
- package/lib/metadataTypes/MetadataType.js +80 -58
- package/lib/metadataTypes/MobileKeyword.js +2 -2
- package/lib/metadataTypes/MobileMessage.js +4 -2
- package/lib/metadataTypes/Query.js +5 -5
- package/lib/metadataTypes/Script.js +5 -5
- package/lib/metadataTypes/SendClassification.js +3 -3
- package/lib/metadataTypes/SenderProfile.js +3 -3
- package/lib/metadataTypes/TransactionalEmail.js +1 -1
- package/lib/metadataTypes/TransactionalMessage.js +1 -1
- package/lib/metadataTypes/TriggeredSend.js +3 -3
- package/lib/metadataTypes/Verification.js +1 -1
- package/lib/metadataTypes/definitions/Automation.definition.js +43 -7
- package/lib/metadataTypes/definitions/DataExtract.definition.js +16 -3
- package/lib/metadataTypes/definitions/DomainVerification.definition.js +1 -1
- package/lib/metadataTypes/definitions/SenderProfile.definition.js +3 -1
- package/lib/util/util.js +12 -0
- package/lib/util/validations.js +3 -1
- package/package.json +1 -1
- package/test/general.test.js +39 -34
- package/test/mockRoot/.mcdevrc.json +1 -1
- package/test/resourceFactory.js +8 -5
- package/test/resources/9999999/automation/create-expected.json +2 -1
- package/test/resources/9999999/automation/retrieve-expected.json +7 -1
- package/test/resources/9999999/automation/retrieve-wait-expected.json +7 -1
- package/test/resources/9999999/automation/update-expected.json +24 -2
- package/test/resources/9999999/automation/update-testExisting_automation-expected.md +5 -2
- package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_pause/patch-response.json +1 -0
- package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_schedule/patch-response.json +1 -0
- package/test/resources/9999999/dataExtract/build-expected.json +2 -2
- package/test/resources/9999999/dataExtract/get-expected.json +2 -2
- package/test/resources/9999999/dataExtract/patch-expected.json +2 -2
- package/test/resources/9999999/dataExtract/post-expected.json +2 -2
- package/test/resources/9999999/dataExtract/template-expected.json +2 -2
- package/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow-PAUSED/get-response.json +3 -0
- package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/NewRkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/get-response.json +29 -0
- package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/get-response.json +50 -0
- package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow-PAUSED/get-response.json +51 -0
- package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/bHF6Q0Q3b1VXa21OdVQzZFQ0ckVSQToyNTow/get-response.json +7 -1
- package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/cDhLQ2o2NExxVVc5N3VZeHF5WEExUToyNTow/get-response.json +79 -0
- package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json +61 -2
- package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/post-response-pauseSchedule.json +1 -0
- package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/post-response-schedule.json +1 -0
- package/test/resources/9999999/messaging/v1/domainverification/get-response.json +10 -1
- package/test/resources/9999999/senderProfile/build-expected.json +1 -1
- package/test/resources/9999999/senderProfile/get-expected.json +1 -1
- package/test/resources/9999999/senderProfile/patch-expected.json +1 -1
- package/test/resources/9999999/senderProfile/retrieve-response.xml +1 -1
- package/test/resources/9999999/senderProfile/template-expected.json +1 -1
- package/test/type.automation.test.js +18 -17
- package/test/type.dataExtract.test.js +4 -4
- package/test/type.domainVerification.test.js +3 -3
- package/test/type.journey.test.js +11 -4
- package/test/type.query.test.js +2 -2
- package/test/type.script.test.js +1 -1
- package/test/type.senderProfile.test.js +20 -3
- package/test/type.triggeredSend.test.js +13 -1
- package/types/mcdev.d.js +8 -0
- package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +0 -52
- package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-ad2e-pause-response.xml +0 -38
- package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-fixKey_pause-response.xml +0 -52
- package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-fixKey_schedule-response.xml +0 -52
- package/test/resources/9999999/automation/schedule-a8afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +0 -52
|
@@ -146,12 +146,11 @@ class Automation extends MetadataType {
|
|
|
146
146
|
* helper for {@link Automation.retrieve} to get Automation Notifications
|
|
147
147
|
*
|
|
148
148
|
* @param {MetadataTypeMap} metadataMap keyField => metadata map
|
|
149
|
+
* @param {boolean} [skipNotification] skip notification retrieval
|
|
149
150
|
* @returns {Promise.<object>} Promise of automation legacy api response
|
|
150
151
|
*/
|
|
151
|
-
static async #getAutomationLegacyREST(metadataMap) {
|
|
152
|
-
Util.logger.info(
|
|
153
|
-
Util.getGrayMsg(` Retrieving Automation Notification & wait information...`)
|
|
154
|
-
);
|
|
152
|
+
static async #getAutomationLegacyREST(metadataMap, skipNotification = false) {
|
|
153
|
+
Util.logger.info(Util.getGrayMsg(` Retrieving additional automation details...`));
|
|
155
154
|
|
|
156
155
|
// get list of keys that we retrieved so far
|
|
157
156
|
const foundKeys = Object.keys(metadataMap);
|
|
@@ -172,27 +171,9 @@ class Automation extends MetadataType {
|
|
|
172
171
|
id: automationLegacyMapObj.metadata[key].id,
|
|
173
172
|
key,
|
|
174
173
|
}));
|
|
175
|
-
// wait
|
|
176
|
-
const
|
|
174
|
+
// created / modified / paused / wait activities
|
|
175
|
+
const extendedDetailsLegacyMap = Object.keys(automationLegacyMapObj.metadata)
|
|
177
176
|
.filter((key) => foundKeys.includes(key))
|
|
178
|
-
.filter((key) => {
|
|
179
|
-
const steps = automationLegacyMapObj.metadata[key].processes;
|
|
180
|
-
// wait activities
|
|
181
|
-
if (!Array.isArray(steps)) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
for (const step of steps) {
|
|
185
|
-
if (!Array.isArray(step.workerCounts)) {
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
for (const activity of step.workerCounts) {
|
|
189
|
-
if (activity.objectTypeId === 467) {
|
|
190
|
-
return true;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return false;
|
|
195
|
-
})
|
|
196
177
|
.map((key) => ({
|
|
197
178
|
id: automationLegacyMapObj.metadata[key].id,
|
|
198
179
|
key,
|
|
@@ -202,31 +183,61 @@ class Automation extends MetadataType {
|
|
|
202
183
|
|
|
203
184
|
// get wait activities for automations using it
|
|
204
185
|
await Promise.all(
|
|
205
|
-
|
|
186
|
+
extendedDetailsLegacyMap.map((automationLegacy) =>
|
|
206
187
|
// notifications
|
|
207
188
|
rateLimit(async () => {
|
|
208
189
|
// this is a file so extended is at another endpoint
|
|
209
190
|
try {
|
|
210
|
-
|
|
191
|
+
/** @type {AutomationItem} */
|
|
192
|
+
const item = metadataMap[automationLegacy.key];
|
|
193
|
+
item.legacyId = automationLegacy.id;
|
|
194
|
+
|
|
195
|
+
const extended = await this.client.rest.get(
|
|
211
196
|
`/legacy/v1/beta/bulk/automations/automation/definition/` +
|
|
212
197
|
automationLegacy.id
|
|
213
198
|
);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
199
|
+
// set those for {@link schedule}
|
|
200
|
+
item.type ||= extended.automationType;
|
|
201
|
+
item.status ||= extended.status;
|
|
202
|
+
|
|
203
|
+
// created
|
|
204
|
+
item.createdName = extended.createdBy?.name;
|
|
205
|
+
item.createdDate = extended.createdDate;
|
|
206
|
+
|
|
207
|
+
// last modified
|
|
208
|
+
item.modifiedName = extended.lastSavedBy?.name;
|
|
209
|
+
item.modifiedDate = extended.lastSaveDate;
|
|
210
|
+
|
|
211
|
+
// last paused
|
|
212
|
+
item.pausedName = extended.lastPausedBy?.name;
|
|
213
|
+
item.pausedDate = extended.lastPausedDate;
|
|
214
|
+
|
|
215
|
+
// schedule id for activating the schedule
|
|
216
|
+
if (extended?.scheduleObject?.id && item.schedule) {
|
|
217
|
+
// save schedule id in cached metadata for retrieval during scheduling
|
|
218
|
+
item.schedule.id = extended.scheduleObject.id;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// add timezone to wait activities
|
|
222
|
+
if (Array.isArray(extended?.processes)) {
|
|
223
|
+
for (const step of extended.processes) {
|
|
224
|
+
// steps
|
|
225
|
+
if (!Array.isArray(step?.workers)) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
218
228
|
for (const activity of step.workers) {
|
|
229
|
+
// activties
|
|
219
230
|
if (
|
|
220
231
|
activity.objectTypeId === 467 &&
|
|
221
232
|
activity.serializedObject
|
|
222
233
|
) {
|
|
234
|
+
// wait activities
|
|
223
235
|
const waitObj = JSON.parse(activity.serializedObject);
|
|
224
236
|
if (waitObj.timeZone) {
|
|
225
237
|
// add timezone to the wait activity
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
].
|
|
229
|
-
waitObj.timeZone;
|
|
238
|
+
item.steps[step.sequence].activities[
|
|
239
|
+
activity.sequence
|
|
240
|
+
].timeZone = waitObj.timeZone;
|
|
230
241
|
}
|
|
231
242
|
// * wait activities are not supported in the new API
|
|
232
243
|
}
|
|
@@ -235,13 +246,16 @@ class Automation extends MetadataType {
|
|
|
235
246
|
}
|
|
236
247
|
} catch (ex) {
|
|
237
248
|
Util.logger.debug(
|
|
238
|
-
` ☇ issue retrieving
|
|
249
|
+
` ☇ issue retrieving extended details for automation ${automationLegacy.key}: ${ex.message} ${ex.code}`
|
|
239
250
|
);
|
|
240
251
|
}
|
|
241
252
|
})
|
|
242
253
|
)
|
|
243
254
|
);
|
|
244
255
|
|
|
256
|
+
if (skipNotification) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
245
259
|
// get notifications for each automation
|
|
246
260
|
let found = 0;
|
|
247
261
|
let skipped = 0;
|
|
@@ -644,220 +658,179 @@ class Automation extends MetadataType {
|
|
|
644
658
|
return null;
|
|
645
659
|
}
|
|
646
660
|
}
|
|
647
|
-
|
|
648
661
|
/**
|
|
649
|
-
* a function to
|
|
662
|
+
* a function to active the schedule of an automation
|
|
650
663
|
*
|
|
651
664
|
* @param {string[]} keyArr customerkey of the metadata
|
|
652
665
|
* @returns {Promise.<string[]>} Returns list of keys that were executed
|
|
653
666
|
*/
|
|
654
|
-
static async
|
|
655
|
-
|
|
667
|
+
static async schedule(keyArr) {
|
|
668
|
+
return this.#schedulePause('schedule', keyArr);
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* a function to pause the schedule of an automation
|
|
672
|
+
*
|
|
673
|
+
* @param {string[]} keyArr customerkey of the metadata
|
|
674
|
+
* @returns {Promise.<string[]>} Returns list of keys that were executed
|
|
675
|
+
*/
|
|
676
|
+
static async pause(keyArr) {
|
|
677
|
+
return this.#schedulePause('pause', keyArr);
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* a function to active the schedule of an automation
|
|
681
|
+
*
|
|
682
|
+
* @param {'schedule'|'pause'} mode what to do
|
|
683
|
+
* @param {string[]} keyArr customerkey of the metadata
|
|
684
|
+
* @returns {Promise.<string[]>} Returns list of keys that were executed
|
|
685
|
+
*/
|
|
686
|
+
static async #schedulePause(mode, keyArr) {
|
|
656
687
|
const metadataMap = {};
|
|
657
688
|
for (const key of keyArr) {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
// runOnce
|
|
674
|
-
const objectId = await this.#getObjectIdForSingleRetrieve(key);
|
|
675
|
-
/** @type {AutomationItem} */
|
|
676
|
-
metadataMap[key] = { key, id: objectId };
|
|
689
|
+
metadataMap[key] = { key, schedule: {} };
|
|
690
|
+
}
|
|
691
|
+
await this.#getAutomationLegacyREST(metadataMap, true);
|
|
692
|
+
for (const key of keyArr) {
|
|
693
|
+
const item = metadataMap[key];
|
|
694
|
+
if (!item.type) {
|
|
695
|
+
Util.logger.error(
|
|
696
|
+
` ☇ skipping ${Util.getTypeKeyName(this.definition, item)}: automation not found.`
|
|
697
|
+
);
|
|
698
|
+
delete metadataMap[key];
|
|
699
|
+
} else if (item.type !== 'scheduled') {
|
|
700
|
+
Util.logger.error(
|
|
701
|
+
` ☇ skipping ${Util.getTypeKeyName(this.definition, item)}: cannot ${mode} an automation of type '${item.type}'.`
|
|
702
|
+
);
|
|
703
|
+
delete metadataMap[key];
|
|
677
704
|
}
|
|
678
705
|
}
|
|
679
706
|
if (!Object.keys(metadataMap).length) {
|
|
680
|
-
Util.logger.error(`No ${this.definition.type} to
|
|
681
|
-
return;
|
|
707
|
+
Util.logger.error(`No ${this.definition.type} to ` + mode);
|
|
708
|
+
return [];
|
|
682
709
|
}
|
|
683
|
-
Util.logger.info(
|
|
684
|
-
`Starting automations ${
|
|
685
|
-
Util.OPTIONS.schedule
|
|
686
|
-
? 'according to schedule'
|
|
687
|
-
: 'to run once (use --schedule or --execute=schedule to schedule instead)'
|
|
688
|
-
}: ${Object.keys(metadataMap).length}`
|
|
689
|
-
);
|
|
710
|
+
Util.logger.info(`${mode === 'schedule' ? 'Activating' : 'Pausing'} automations`);
|
|
690
711
|
const promiseResults = [];
|
|
691
712
|
for (const key of Object.keys(metadataMap)) {
|
|
692
|
-
|
|
713
|
+
/** @type {AutomationItem} */
|
|
714
|
+
const item = metadataMap[key];
|
|
715
|
+
if (item.status === (mode === 'schedule' ? 'Scheduled' : 'PausedSchedule')) {
|
|
693
716
|
// schedule
|
|
694
717
|
Util.logger.info(
|
|
695
|
-
`
|
|
718
|
+
` ☇ skipping ${Util.getTypeKeyName(this.definition, item)}: already ${mode === 'schedule' ? 'activated' : 'paused'}.`
|
|
696
719
|
);
|
|
697
720
|
} else {
|
|
698
|
-
// schedule
|
|
699
|
-
promiseResults.push(
|
|
721
|
+
// schedule
|
|
722
|
+
promiseResults.push(
|
|
723
|
+
this.#schedulePauseItem(mode, key, item.legacyId, item.schedule.id)
|
|
724
|
+
);
|
|
700
725
|
}
|
|
701
726
|
}
|
|
702
727
|
const results = await Promise.all(promiseResults);
|
|
703
|
-
const
|
|
728
|
+
const updatedKeyArr = results
|
|
704
729
|
.filter(Boolean)
|
|
705
|
-
.filter((r) => r.response.
|
|
730
|
+
.filter((r) => r.response.id)
|
|
706
731
|
.map((r) => r.key);
|
|
707
|
-
Util.logger.info(
|
|
708
|
-
|
|
709
|
-
|
|
732
|
+
Util.logger.info(
|
|
733
|
+
`${mode === 'schedule' ? 'Activated' : 'Paused'} ${updatedKeyArr.length} of ${keyArr.length} items`
|
|
734
|
+
);
|
|
710
735
|
|
|
711
|
-
|
|
712
|
-
* helper for {@link Automation.execute}
|
|
713
|
-
*
|
|
714
|
-
* @param {AutomationMap} metadataMap map of metadata
|
|
715
|
-
* @param {string} key key of the metadata
|
|
716
|
-
* @returns {Promise.<{key:string, response:object}>} metadata key and API response
|
|
717
|
-
*/
|
|
718
|
-
static async #executeItem(metadataMap, key) {
|
|
719
|
-
if (Util.OPTIONS.schedule) {
|
|
720
|
-
this.#preDeploySchedule(metadataMap[key]);
|
|
721
|
-
metadataMap[key].status = 'Scheduled';
|
|
722
|
-
return this.#scheduleAutomation(metadataMap, metadataMap, key);
|
|
723
|
-
} else {
|
|
724
|
-
return this.#runOnce(metadataMap[key]);
|
|
725
|
-
}
|
|
736
|
+
return updatedKeyArr;
|
|
726
737
|
}
|
|
727
738
|
|
|
728
739
|
/**
|
|
729
|
-
* helper for {@link Automation.
|
|
740
|
+
* helper for {@link Automation.schedule}
|
|
730
741
|
*
|
|
731
|
-
* @param {
|
|
742
|
+
* @param {'schedule'|'pause'} mode what to do
|
|
743
|
+
* @param {string} key automation key
|
|
744
|
+
* @param {string} automationLegacyId automation id
|
|
745
|
+
* @param {string} [scheduleLegacyId] schedule id
|
|
732
746
|
* @returns {Promise.<{key:string, response:object}>} metadata key and API response
|
|
733
747
|
*/
|
|
734
|
-
static async #
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
748
|
+
static async #schedulePauseItem(mode, key, automationLegacyId, scheduleLegacyId) {
|
|
749
|
+
if (!scheduleLegacyId) {
|
|
750
|
+
const extended = await this.client.rest.get(
|
|
751
|
+
`/legacy/v1/beta/bulk/automations/automation/definition/` + automationLegacyId
|
|
752
|
+
);
|
|
753
|
+
if (extended.scheduleObject?.id) {
|
|
754
|
+
scheduleLegacyId = extended.scheduleObject.id;
|
|
755
|
+
} else {
|
|
756
|
+
Util.logger.error(
|
|
757
|
+
` ☇ skipping ${this.definition.type} ${key}: no valid schedule settings found.`
|
|
758
|
+
);
|
|
759
|
+
return null;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
const response = await this.client.rest.post(
|
|
763
|
+
'/legacy/v1/beta/bulk/automations/automation/definition/?action=' +
|
|
764
|
+
(mode === 'schedule' ? 'schedule' : 'pauseSchedule'),
|
|
765
|
+
{
|
|
766
|
+
id: automationLegacyId,
|
|
767
|
+
scheduleObject: {
|
|
768
|
+
id: scheduleLegacyId,
|
|
769
|
+
},
|
|
770
|
+
}
|
|
771
|
+
);
|
|
772
|
+
if (response?.id === automationLegacyId) {
|
|
773
|
+
const item = {};
|
|
774
|
+
item[this.definition.keyField] = key;
|
|
775
|
+
Util.logger.info(
|
|
776
|
+
` - ${mode === 'schedule' ? '✅ activated' : '🛑 paused'} scheduled ${Util.getTypeKeyName(this.definition, item)}`
|
|
751
777
|
);
|
|
752
778
|
}
|
|
753
|
-
return errors;
|
|
754
|
-
}
|
|
755
779
|
|
|
780
|
+
return { key, response };
|
|
781
|
+
}
|
|
756
782
|
/**
|
|
757
783
|
* a function to start query execution via API
|
|
758
784
|
*
|
|
759
785
|
* @param {string[]} keyArr customerkey of the metadata
|
|
760
|
-
* @returns {Promise.<string[]>} Returns list of keys that were
|
|
786
|
+
* @returns {Promise.<string[]>} Returns list of keys that were executed
|
|
761
787
|
*/
|
|
762
|
-
static async
|
|
788
|
+
static async execute(keyArr) {
|
|
789
|
+
/** @type {AutomationMap} */
|
|
763
790
|
const metadataMap = {};
|
|
764
791
|
for (const key of keyArr) {
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
if (this.#isValidSchedule(results.metadata[key])) {
|
|
770
|
-
metadataMap[key] = results.metadata[key];
|
|
771
|
-
} else {
|
|
772
|
-
Util.logger.error(
|
|
773
|
-
` - skipping ${this.definition.type} ${results.metadata[key].name}: no valid schedule settings found.`
|
|
774
|
-
);
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
}
|
|
792
|
+
// runOnce
|
|
793
|
+
const objectId = await this.#getObjectIdForSingleRetrieve(key);
|
|
794
|
+
/** @type {AutomationItem} */
|
|
795
|
+
metadataMap[key] = { key, id: objectId };
|
|
779
796
|
}
|
|
780
|
-
|
|
781
|
-
|
|
797
|
+
if (!Object.keys(metadataMap).length) {
|
|
798
|
+
Util.logger.error(`No ${this.definition.type} to execute`);
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
Util.logger.info(
|
|
802
|
+
`Starting automations to run once (use --schedule or --execute=schedule to schedule instead): ${Object.keys(metadataMap).length}`
|
|
803
|
+
);
|
|
782
804
|
const promiseResults = [];
|
|
783
805
|
for (const key of Object.keys(metadataMap)) {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
} else if (metadataMap[key].status === 'PausedSchedule') {
|
|
787
|
-
Util.logger.info(
|
|
788
|
-
` - skipping ${this.definition.type} ${metadataMap[key].name}: already paused.`
|
|
789
|
-
);
|
|
790
|
-
} else {
|
|
791
|
-
Util.logger.error(
|
|
792
|
-
` - skipping ${this.definition.type} ${
|
|
793
|
-
metadataMap[key].name
|
|
794
|
-
}: currently ${metadataMap[
|
|
795
|
-
key
|
|
796
|
-
].status.toLowerCase()}. Please try again in a few minutes.`
|
|
797
|
-
);
|
|
798
|
-
}
|
|
806
|
+
// schedule + runOnce
|
|
807
|
+
promiseResults.push(super.executeSOAP(metadataMap[key]));
|
|
799
808
|
}
|
|
800
|
-
const
|
|
809
|
+
const results = await Promise.all(promiseResults);
|
|
810
|
+
const executedKeyArr = results
|
|
801
811
|
.filter(Boolean)
|
|
802
812
|
.filter((r) => r.response.OverallStatus === 'OK')
|
|
803
813
|
.map((r) => r.key);
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
return pausedKeyArr;
|
|
814
|
+
Util.logger.info(`Executed ${executedKeyArr.length} of ${keyArr.length} items`);
|
|
815
|
+
return executedKeyArr;
|
|
807
816
|
}
|
|
808
817
|
|
|
809
818
|
/**
|
|
810
|
-
*
|
|
819
|
+
* Standardizes a check for multiple messages but adds query specific filters to error texts
|
|
811
820
|
*
|
|
812
|
-
* @param {
|
|
813
|
-
* @returns {
|
|
821
|
+
* @param {object} ex response payload from REST API
|
|
822
|
+
* @returns {string[]} formatted Error Message
|
|
814
823
|
*/
|
|
815
|
-
static
|
|
816
|
-
const
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
Interaction: {
|
|
823
|
-
ObjectID: metadata[this.definition.idField],
|
|
824
|
-
},
|
|
825
|
-
},
|
|
826
|
-
'pause',
|
|
827
|
-
{}
|
|
828
|
-
);
|
|
829
|
-
Util.logger.info(
|
|
830
|
-
` - paused ${this.definition.type}: ${metadata[this.definition.keyField]} / ${
|
|
831
|
-
metadata[this.definition.nameField]
|
|
832
|
-
}`
|
|
824
|
+
static getErrorsREST(ex) {
|
|
825
|
+
const errors = super.getErrorsREST(ex);
|
|
826
|
+
if (errors?.length > 0) {
|
|
827
|
+
return errors.map((msg) =>
|
|
828
|
+
msg
|
|
829
|
+
.split('403 Forbidden')
|
|
830
|
+
.join('403 Forbidden: Please check if the automation is currently running.')
|
|
833
831
|
);
|
|
834
|
-
return { key: metadata[this.definition.keyField], response };
|
|
835
|
-
} catch (ex) {
|
|
836
|
-
this._handleSOAPErrors(ex, 'pausing', metadata, false);
|
|
837
|
-
return null;
|
|
838
832
|
}
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
/**
|
|
842
|
-
* Deploys automation - the saved file is the original one due to large differences required for deployment
|
|
843
|
-
*
|
|
844
|
-
* @param {AutomationMap} metadata metadata mapped by their keyField
|
|
845
|
-
* @param {string} targetBU name/shorthand of target businessUnit for mapping
|
|
846
|
-
* @param {string} retrieveDir directory where metadata after deploy should be saved
|
|
847
|
-
* @returns {Promise.<AutomationMap>} Promise
|
|
848
|
-
*/
|
|
849
|
-
static async deploy(metadata, targetBU, retrieveDir) {
|
|
850
|
-
const upsertResults = await this.upsert(metadata, targetBU);
|
|
851
|
-
const savedMetadata = await this.saveResults(upsertResults, retrieveDir, null);
|
|
852
|
-
if (
|
|
853
|
-
this.properties.metaDataTypes.documentOnRetrieve.includes(this.definition.type) &&
|
|
854
|
-
!this.definition.documentInOneFile
|
|
855
|
-
) {
|
|
856
|
-
const count = Object.keys(savedMetadata).length;
|
|
857
|
-
Util.logger.debug(` - Running document for ${count} record${count === 1 ? '' : 's'}`);
|
|
858
|
-
await this.document(savedMetadata);
|
|
859
|
-
}
|
|
860
|
-
return upsertResults;
|
|
833
|
+
return errors;
|
|
861
834
|
}
|
|
862
835
|
|
|
863
836
|
/**
|
|
@@ -965,7 +938,7 @@ class Automation extends MetadataType {
|
|
|
965
938
|
|
|
966
939
|
this.#preDeploySchedule(metadata);
|
|
967
940
|
// * run _buildSchedule here but only to check if things look ok - do not use the returned schedule object for deploy
|
|
968
|
-
this.
|
|
941
|
+
this._checkSchedule(metadata.schedule);
|
|
969
942
|
|
|
970
943
|
delete metadata.schedule.timezoneName;
|
|
971
944
|
delete metadata.startSource.schedule.timezoneName;
|
|
@@ -1144,10 +1117,9 @@ class Automation extends MetadataType {
|
|
|
1144
1117
|
* Gets executed after deployment of metadata type
|
|
1145
1118
|
*
|
|
1146
1119
|
* @param {AutomationMap} metadataMap metadata mapped by their keyField
|
|
1147
|
-
* @param {AutomationMap} originalMetadataMap metadata to be updated (contains additioanl fields)
|
|
1148
1120
|
* @returns {Promise.<void>} -
|
|
1149
1121
|
*/
|
|
1150
|
-
static async postDeployTasks(metadataMap
|
|
1122
|
+
static async postDeployTasks(metadataMap) {
|
|
1151
1123
|
for (const key in metadataMap) {
|
|
1152
1124
|
const item = metadataMap[key];
|
|
1153
1125
|
|
|
@@ -1156,8 +1128,12 @@ class Automation extends MetadataType {
|
|
|
1156
1128
|
|
|
1157
1129
|
if (!item.type) {
|
|
1158
1130
|
// create response does not return the type attribute
|
|
1159
|
-
|
|
1160
|
-
|
|
1131
|
+
if (item.startSource?.schedule) {
|
|
1132
|
+
// rewrite upsert reponse into retrieve format
|
|
1133
|
+
item.schedule = item.startSource.schedule;
|
|
1134
|
+
delete item.startSource;
|
|
1135
|
+
}
|
|
1136
|
+
const scheduleHelper = item.schedule;
|
|
1161
1137
|
|
|
1162
1138
|
// el.type
|
|
1163
1139
|
item.type = scheduleHelper
|
|
@@ -1179,7 +1155,13 @@ class Automation extends MetadataType {
|
|
|
1179
1155
|
item.status ||= Util.inverseGet(this.definition.statusMapping, item.statusId);
|
|
1180
1156
|
}
|
|
1181
1157
|
// need to put schedule on here if status is scheduled
|
|
1182
|
-
|
|
1158
|
+
if (Util.OPTIONS.schedule) {
|
|
1159
|
+
await Automation.#schedulePauseItem(
|
|
1160
|
+
'schedule',
|
|
1161
|
+
oldKey || key,
|
|
1162
|
+
metadataMap[key]?.legacyId
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1183
1165
|
|
|
1184
1166
|
// need to update notifications separately if there are any
|
|
1185
1167
|
await Automation.#updateNotificationInfoREST(metadataMap, key);
|
|
@@ -1192,10 +1174,24 @@ class Automation extends MetadataType {
|
|
|
1192
1174
|
}
|
|
1193
1175
|
}
|
|
1194
1176
|
}
|
|
1195
|
-
|
|
1177
|
+
|
|
1178
|
+
if (Util.OPTIONS.execute) {
|
|
1196
1179
|
Util.logger.info(`Executing: ${this.definition.type}`);
|
|
1197
1180
|
await this.execute(Object.keys(metadataMap));
|
|
1198
1181
|
}
|
|
1182
|
+
Util.logger.debug(
|
|
1183
|
+
`Caching all ${this.definition.type} post-deploy to ensure we have all fields`
|
|
1184
|
+
);
|
|
1185
|
+
|
|
1186
|
+
// post-deploy re-retrieve
|
|
1187
|
+
// dont use retrieveForCache here because that is simplified for automations
|
|
1188
|
+
const typeCache = await this.retrieve();
|
|
1189
|
+
// update values in upsertResults with retrieved values before saving to disk
|
|
1190
|
+
for (const key of Object.keys(metadataMap)) {
|
|
1191
|
+
if (typeCache.metadata[key]) {
|
|
1192
|
+
metadataMap[key] = typeCache.metadata[key];
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1199
1195
|
}
|
|
1200
1196
|
|
|
1201
1197
|
/**
|
|
@@ -1245,90 +1241,6 @@ class Automation extends MetadataType {
|
|
|
1245
1241
|
}
|
|
1246
1242
|
}
|
|
1247
1243
|
|
|
1248
|
-
/**
|
|
1249
|
-
* helper for {@link Automation.postDeployTasks}
|
|
1250
|
-
*
|
|
1251
|
-
* @param {AutomationMap} metadataMap metadata mapped by their keyField
|
|
1252
|
-
* @param {AutomationMap} originalMetadataMap metadata to be updated (contains additioanl fields)
|
|
1253
|
-
* @param {string} key current customer key
|
|
1254
|
-
* @param {string} [oldKey] old customer key before fixKey / changeKeyValue / changeKeyField
|
|
1255
|
-
* @returns {Promise.<{key:string, response:object}>} metadata key and API response
|
|
1256
|
-
*/
|
|
1257
|
-
static async #scheduleAutomation(metadataMap, originalMetadataMap, key, oldKey) {
|
|
1258
|
-
let response = null;
|
|
1259
|
-
oldKey ||= key;
|
|
1260
|
-
if (originalMetadataMap[oldKey]?.type === 'scheduled') {
|
|
1261
|
-
// Starting Source == 'Schedule': Try starting the automation
|
|
1262
|
-
if (originalMetadataMap[oldKey].status === 'Scheduled') {
|
|
1263
|
-
let schedule = null;
|
|
1264
|
-
try {
|
|
1265
|
-
schedule = this._buildSchedule(originalMetadataMap[oldKey].schedule);
|
|
1266
|
-
} catch (ex) {
|
|
1267
|
-
Util.logger.error(
|
|
1268
|
-
`- Could not create schedule for automation '${originalMetadataMap[oldKey].name}' to start it: ${ex.message}`
|
|
1269
|
-
);
|
|
1270
|
-
}
|
|
1271
|
-
if (schedule !== null) {
|
|
1272
|
-
try {
|
|
1273
|
-
// remove the fields that are not needed for the schedule but only for CLI output
|
|
1274
|
-
const schedule_StartDateTime = schedule._StartDateTime;
|
|
1275
|
-
delete schedule._StartDateTime;
|
|
1276
|
-
const schedule_interval = schedule._interval;
|
|
1277
|
-
delete schedule._interval;
|
|
1278
|
-
const schedule_timezoneString = schedule._timezoneString;
|
|
1279
|
-
delete schedule._timezoneString;
|
|
1280
|
-
// start the automation
|
|
1281
|
-
response = await this.client.soap.schedule(
|
|
1282
|
-
'Automation',
|
|
1283
|
-
schedule,
|
|
1284
|
-
{
|
|
1285
|
-
Interaction: {
|
|
1286
|
-
ObjectID: metadataMap[key][this.definition.idField],
|
|
1287
|
-
},
|
|
1288
|
-
},
|
|
1289
|
-
'start',
|
|
1290
|
-
{}
|
|
1291
|
-
);
|
|
1292
|
-
const intervalString =
|
|
1293
|
-
(schedule_interval > 1 ? `${schedule_interval} ` : '') +
|
|
1294
|
-
(schedule.RecurrenceType === 'Daily'
|
|
1295
|
-
? 'Day'
|
|
1296
|
-
: schedule.RecurrenceType.slice(0, -2) +
|
|
1297
|
-
(schedule_interval > 1 ? 's' : ''));
|
|
1298
|
-
Util.logger.warn(
|
|
1299
|
-
` - scheduled automation '${
|
|
1300
|
-
originalMetadataMap[oldKey].name
|
|
1301
|
-
}' deployed as Active: runs every ${intervalString} starting ${
|
|
1302
|
-
schedule_StartDateTime.split('T').join(' ').split('.')[0]
|
|
1303
|
-
} ${schedule_timezoneString}`
|
|
1304
|
-
);
|
|
1305
|
-
} catch {
|
|
1306
|
-
// API does not return anything usefull here. We have to know the rules instead
|
|
1307
|
-
Util.logger.error(
|
|
1308
|
-
` ☇ error starting scheduled ${this.definition.type}${key}: Please check schedule settings`
|
|
1309
|
-
);
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
} else {
|
|
1313
|
-
Util.logger.info(
|
|
1314
|
-
Util.getGrayMsg(
|
|
1315
|
-
` - scheduled automation '${originalMetadataMap[oldKey].name}' deployed as Paused`
|
|
1316
|
-
)
|
|
1317
|
-
);
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
if (metadataMap[key].startSource) {
|
|
1321
|
-
metadataMap[key].schedule = metadataMap[key].startSource.schedule;
|
|
1322
|
-
|
|
1323
|
-
delete metadataMap[key].startSource;
|
|
1324
|
-
}
|
|
1325
|
-
if (metadataMap[key].schedule?.scheduleTypeId) {
|
|
1326
|
-
metadataMap[key].schedule.typeId = metadataMap[key].schedule.scheduleTypeId;
|
|
1327
|
-
delete metadataMap[key].schedule.scheduleTypeId;
|
|
1328
|
-
}
|
|
1329
|
-
return { key, response };
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
1244
|
/**
|
|
1333
1245
|
* generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
|
|
1334
1246
|
*
|
|
@@ -1369,18 +1281,9 @@ class Automation extends MetadataType {
|
|
|
1369
1281
|
* based on combination of ical string and start/end dates.
|
|
1370
1282
|
*
|
|
1371
1283
|
* @param {AutomationSchedule} scheduleObject child of automation metadata used for scheduling
|
|
1372
|
-
* @returns {
|
|
1284
|
+
* @returns {void} throws and error in case of problems
|
|
1373
1285
|
*/
|
|
1374
|
-
static
|
|
1375
|
-
/**
|
|
1376
|
-
* @type {AutomationScheduleSoap}
|
|
1377
|
-
*/
|
|
1378
|
-
const schedule = {
|
|
1379
|
-
Recurrence: {},
|
|
1380
|
-
TimeZone: { ID: null, IDSpecified: true },
|
|
1381
|
-
RecurrenceRangeType: null,
|
|
1382
|
-
StartDateTime: null,
|
|
1383
|
-
};
|
|
1286
|
+
static _checkSchedule(scheduleObject) {
|
|
1384
1287
|
// build recurrence
|
|
1385
1288
|
const recurHelper = {};
|
|
1386
1289
|
// ical values are split by ; then have key values split by =
|
|
@@ -1391,34 +1294,7 @@ class Automation extends MetadataType {
|
|
|
1391
1294
|
if (recurHelper.INTERVAL) {
|
|
1392
1295
|
recurHelper.INTERVAL = Number.parseInt(recurHelper.INTERVAL);
|
|
1393
1296
|
}
|
|
1394
|
-
// the ical schedule is all in caps but soap objects require Title Case.
|
|
1395
|
-
const keyStem = recurHelper.FREQ.charAt(0) + recurHelper.FREQ.slice(1, -2).toLowerCase();
|
|
1396
|
-
|
|
1397
|
-
const patternType = recurHelper['BYMONTH']
|
|
1398
|
-
? 'ByMonth'
|
|
1399
|
-
: recurHelper['BYWEEK']
|
|
1400
|
-
? 'ByWeek'
|
|
1401
|
-
: recurHelper['BYDAY']
|
|
1402
|
-
? 'ByDay'
|
|
1403
|
-
: 'Interval';
|
|
1404
|
-
schedule.Recurrence[keyStem + 'lyRecurrencePatternType'] = patternType;
|
|
1405
|
-
schedule.Recurrence['@_xsi:type'] = keyStem + 'lyRecurrence';
|
|
1406
|
-
schedule.RecurrenceType = keyStem + 'ly';
|
|
1407
|
-
if (keyStem === 'Dai') {
|
|
1408
|
-
schedule.Recurrence['DayInterval'] = recurHelper.INTERVAL;
|
|
1409
|
-
} else {
|
|
1410
|
-
schedule.Recurrence[keyStem + 'Interval'] = recurHelper.INTERVAL;
|
|
1411
|
-
}
|
|
1412
|
-
schedule._interval = recurHelper.INTERVAL; // for CLI output only
|
|
1413
1297
|
|
|
1414
|
-
if (!['Minute', 'Hour', 'Dai'].includes(keyStem)) {
|
|
1415
|
-
// todo: add support for weekly
|
|
1416
|
-
// todo: add support for monthly
|
|
1417
|
-
// todo: add support for yearly
|
|
1418
|
-
throw new Error(
|
|
1419
|
-
'Scheduling automatically not supported for Weekly, Monthly and Yearly, please configure manually.'
|
|
1420
|
-
);
|
|
1421
|
-
}
|
|
1422
1298
|
if (recurHelper.FREQ === 'MINUTELY' && recurHelper.INTERVAL && recurHelper.INTERVAL < 5) {
|
|
1423
1299
|
throw new Error(
|
|
1424
1300
|
'The smallest interval you can configure is 5 minutes. Please adjust your schedule.'
|
|
@@ -1433,79 +1309,6 @@ class Automation extends MetadataType {
|
|
|
1433
1309
|
`Could not find timezone ${scheduleObject.timezoneName} in definition.timeZoneMapping`
|
|
1434
1310
|
);
|
|
1435
1311
|
}
|
|
1436
|
-
schedule.TimeZone.ID = scheduleObject.timezoneId;
|
|
1437
|
-
schedule._timezoneString = this.definition.timeZoneDifference[scheduleObject.timezoneId];
|
|
1438
|
-
|
|
1439
|
-
// add tz to input date to ensure Date() creates a date object with the right tz
|
|
1440
|
-
const inputStartDateString = scheduleObject.startDate + schedule._timezoneString;
|
|
1441
|
-
|
|
1442
|
-
/** @type {Date | string} */
|
|
1443
|
-
let startDateTime;
|
|
1444
|
-
if (new Date(inputStartDateString) > new Date()) {
|
|
1445
|
-
// if start date is in future take this
|
|
1446
|
-
startDateTime = scheduleObject.startDate;
|
|
1447
|
-
schedule._StartDateTime = scheduleObject.startDate; // store copy for CLI output
|
|
1448
|
-
} else {
|
|
1449
|
-
// if start date is in past calculate new start date
|
|
1450
|
-
const scheduledDate = new Date(inputStartDateString);
|
|
1451
|
-
const futureDate = new Date();
|
|
1452
|
-
|
|
1453
|
-
switch (keyStem) {
|
|
1454
|
-
case 'Dai': {
|
|
1455
|
-
// keep time from template and start today if possible
|
|
1456
|
-
if (scheduledDate.getHours() <= futureDate.getHours()) {
|
|
1457
|
-
// hour on template has already passed today, start tomorrow
|
|
1458
|
-
futureDate.setDate(futureDate.getDate() + 1);
|
|
1459
|
-
}
|
|
1460
|
-
futureDate.setHours(scheduledDate.getHours());
|
|
1461
|
-
futureDate.setMinutes(scheduledDate.getMinutes());
|
|
1462
|
-
|
|
1463
|
-
break;
|
|
1464
|
-
}
|
|
1465
|
-
case 'Hour': {
|
|
1466
|
-
// keep minute and start next possible hour
|
|
1467
|
-
if (scheduledDate.getMinutes() <= futureDate.getMinutes()) {
|
|
1468
|
-
futureDate.setHours(futureDate.getHours() + 1);
|
|
1469
|
-
}
|
|
1470
|
-
futureDate.setMinutes(scheduledDate.getMinutes());
|
|
1471
|
-
|
|
1472
|
-
break;
|
|
1473
|
-
}
|
|
1474
|
-
case 'Minute': {
|
|
1475
|
-
// schedule in next 15 minutes randomly to avoid that all automations run at exactly
|
|
1476
|
-
// earliest start 1 minute from now
|
|
1477
|
-
// the same time which would slow performance
|
|
1478
|
-
futureDate.setMinutes(
|
|
1479
|
-
futureDate.getMinutes() + 1 + Math.ceil(Math.random() * 15)
|
|
1480
|
-
);
|
|
1481
|
-
|
|
1482
|
-
break;
|
|
1483
|
-
}
|
|
1484
|
-
// No default
|
|
1485
|
-
}
|
|
1486
|
-
// return time as Dateobject
|
|
1487
|
-
startDateTime = futureDate;
|
|
1488
|
-
const localTimezoneOffset = futureDate.getTimezoneOffset() / -60;
|
|
1489
|
-
schedule._StartDateTime = this._calcTime(localTimezoneOffset, futureDate); // store copy for CLI output
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
// The Create/Update API expects dates to be in US-Central time
|
|
1493
|
-
// The retrieve API returns the date in whatever timezone one chose, hence we need to convert this upon upsert
|
|
1494
|
-
schedule.StartDateTime = this._calcTime(
|
|
1495
|
-
this.properties.options.serverTimeOffset,
|
|
1496
|
-
startDateTime,
|
|
1497
|
-
schedule._timezoneString
|
|
1498
|
-
);
|
|
1499
|
-
|
|
1500
|
-
if (recurHelper.UNTIL) {
|
|
1501
|
-
schedule.RecurrenceRangeType = 'EndOn';
|
|
1502
|
-
schedule.EndDateTime = scheduleObject.endDate;
|
|
1503
|
-
} else {
|
|
1504
|
-
schedule.RecurrenceRangeType = 'EndAfter';
|
|
1505
|
-
schedule.Occurrences = recurHelper.COUNT;
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
return schedule;
|
|
1509
1312
|
}
|
|
1510
1313
|
|
|
1511
1314
|
/**
|
|
@@ -1799,7 +1602,7 @@ class Automation extends MetadataType {
|
|
|
1799
1602
|
// the delete endpoint returns a general exception if the automation does not exist; handle it gracefully instead by adding a retrieve first
|
|
1800
1603
|
const objectId = key ? await this.#getObjectIdForSingleRetrieve(key) : null;
|
|
1801
1604
|
if (!objectId) {
|
|
1802
|
-
|
|
1605
|
+
await this.deleteNotFound(key);
|
|
1803
1606
|
return false;
|
|
1804
1607
|
}
|
|
1805
1608
|
return super.deleteByKeySOAP(key, 'CustomerKey');
|