Skip to content

Commit 7749925

Browse files
authored
Upsert Object v2 and Get New and Updated Objects Polling updates (#31)
* New `Upsert Object` action * Old `Upsert Object` action is deprecated * `Get New and Updated Objects Polling` trigger updated: - Default size of pages to be fetched changed from `1000` to `10000` - Restriction `maxFetch should be maximum 10000 objects` is removed
1 parent 1666804 commit 7749925

File tree

67 files changed

+9988
-7568
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+9988
-7568
lines changed

.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# unit tests
2+
OAUTH_CLIENT_ID=
3+
OAUTH_CLIENT_SECRET=
4+
INSTANCE_URL=https://{instanse-name}.salesforce.com
5+
6+
# integration tests (your private data)
7+
ELASTICIO_API_URI=
8+
ELASTICIO_WORKSPACE_ID=
9+
AUTH_SECRET_ID=
10+
ELASTICIO_API_USERNAME=name.surname@mail.com
11+
ELASTICIO_API_KEY= get it by pressing "Profile Information" on ui
12+
Also includes:
13+
1: ACCESS_TOKEN - which will be set by run of /spec-integration/getAccessToken.js in before hook for mocha
14+
2: unit tests envs

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Logs
22
logs
33
*.log
4+
.nyc_output
45

56
# Runtime data
67
pids

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
## 2.2.0 (August 20, 2021)
2+
3+
* New `Upsert Object` action
4+
* Old `Upsert Object` action is deprecated
5+
* `Get New and Updated Objects Polling` trigger updated:
6+
- Default size of pages to be fetched changed from `1000` to `10000`
7+
- Restriction `maxFetch should be maximum 10000 objects` is removed
8+
19
## 2.1.0 (August 10, 2021)
210

3-
* New `Raw Request` Action
11+
* New `Raw Request` action
412

513
## 2.0.4 (February 12, 2021)
614

README.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -317,20 +317,18 @@ Action creates a single object.
317317

318318
#### List of Expected Config fields
319319
* **Object** - Input field where you should choose the object type, which you want to find. E.g. `Account`
320-
* **Optional Upsert field** - Input field where you should specify the ExternalID name field. E.g. `ExtId__c`.
321-
* **Utilize data attachment from previous step (for objects with a binary field)** - a checkbox, if it is checked and an input message contains an attachment and specified object has a binary field (type of base64) then the input data is put into object's binary field. In this case any data specified for the binary field in the data mapper is discarded.
322-
323-
You should specify **external** or **internal Id** for making some updates in salesforce object.
324-
If you want to create new Object you should always specify **Optional Upsert field** and value of ExternalId in input body structure.
320+
* **Type Of Search** - Dropdown list with two values: `Unique Fields` and `All Fields`.
321+
* **Lookup by field** - Dropdown list with all fields on the selected object if the *Type Of Search* is `All Fields`. If the *Type Of Search* is `Unique Fields`, the dropdown lists instead all fields on the selected object where `type` is `id` or `unique` is `true`.
325322

326323
#### Expected input metadata
327-
Input metadata is fetched dynamically from your Salesforce account.
324+
* lookup by - *name of filed selected in 'Lookup by field'*
325+
* other fields, that used by selected **Object**
328326

329327
#### Expected output metadata
330-
Output metadata is the same as input metadata, so you may expect all fields that you mapped as input to be returned as output.
331-
332-
#### Limitations
333-
When **Utilize data attachment from previous step (for objects with a binary field)** is checked and this action is used with Local Agent error would be thrown: 'getaddrinfo ENOTFOUND steward-service.platform.svc.cluster.local steward-service.platform.svc.cluster.local:8200'
328+
The result of creating or updating an object
329+
* **id** - Unic identificator from salesforce
330+
* **success** - Boolean result of creation/update object
331+
* **errors** - Arrey of errors if they exist
334332

335333
## Known limitations
336334
Attachments mechanism does not work with [Local Agent Installation](https://docs.elastic.io/getting-started/local-agent.html)

component.json

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"title": "Salesforce v2",
3-
"version": "2.1.0",
3+
"version": "2.2.0",
44
"description": "Customer relationship management (CRM) software & cloud computing from the leader in CRM solutions for businesses large & small.",
55
"docsUrl": "https://github.com/elasticio/salesforce-component-v2",
66
"url": "http://www.salesforce.com/",
@@ -74,8 +74,8 @@
7474
"label": "Size of Polling Page",
7575
"viewClass": "TextFieldView",
7676
"required": false,
77-
"placeholder": "1000",
78-
"note": "Please set the size of pages to be fetched (defaults to 1000). Please enter positive integer only, max 10000 objects"
77+
"placeholder": "10000",
78+
"note": "Please set the size of pages to be fetched (defaults to 10000). Please enter positive integer only, max 10000 objects"
7979
},
8080
"singlePagePerInterval": {
8181
"label": "Process single page per execution",
@@ -450,12 +450,12 @@
450450
}
451451
},
452452
"upsert": {
453+
"deprecated": true,
453454
"title": "Upsert Object",
454455
"main": "./lib/actions/upsert.js",
455-
"order": 92,
456+
"order": 50,
456457
"help" : {
457-
"description": "Create or Update Selected Object",
458-
"link": "/components/salesforce/actions#upsert-object-action"
458+
"description": "Create or Update Selected Object"
459459
},
460460
"dynamicMetadata": true,
461461
"fields": {
@@ -478,6 +478,47 @@
478478
"label": "Utilize data attachment from previous step (for objects with a binary field)"
479479
}
480480
}
481+
},
482+
"upsert_v2": {
483+
"title": "Upsert Object",
484+
"main": "./lib/actions/upsert_v2.js",
485+
"order": 90,
486+
"help" : {
487+
"description": "Create or Update seleced Object",
488+
"link": "/components/salesforce/actions#upsert-object-action"
489+
},
490+
"dynamicMetadata": true,
491+
"fields": {
492+
"sobject": {
493+
"viewClass": "SelectView",
494+
"label": "Object",
495+
"required": true,
496+
"model": "getObjectTypes",
497+
"prompt": "Please select a Salesforce Object",
498+
"order": 8
499+
},
500+
"typeOfSearch": {
501+
"viewClass": "SelectView",
502+
"label": "Type Of Search",
503+
"required": true,
504+
"require": ["sobject"],
505+
"model": {
506+
"uniqueFields": "Unique Fields",
507+
"allFields": "All Fields"
508+
},
509+
"prompt": "Please select a type of search",
510+
"order": 7
511+
},
512+
"lookupField": {
513+
"viewClass": "SelectView",
514+
"label": "Lookup by field",
515+
"required": true,
516+
"require": ["sobject", "typeOfSearch"],
517+
"model": "getLookupFieldsModel",
518+
"prompt": "Please select the field which you want to use for lookup",
519+
"order": 6
520+
}
521+
}
481522
}
482523
}
483524
}

lib/actions/deleteObject.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ module.exports.process = async function process(message, configuration) {
6262
this.logger.info('Starting Delete Object (at most 1) Action');
6363
const { lookupField } = configuration;
6464
const lookupValue = message.body[lookupField];
65-
let Id;
65+
let objectToDeleteId;
6666

6767
if (!lookupValue) {
6868
this.logger.debug('No unique criteria provided, run previous functionality');
@@ -71,7 +71,7 @@ module.exports.process = async function process(message, configuration) {
7171
this.logger.error('Salesforce error. Empty ID');
7272
return messages.newEmptyMessage();
7373
}
74-
Id = message.body.id;
74+
objectToDeleteId = message.body.id;
7575
} else {
7676
this.logger.debug(`Preparing to delete a ${configuration.sobject} object...`);
7777

@@ -86,7 +86,7 @@ module.exports.process = async function process(message, configuration) {
8686
const results = await callJSForceMethod.call(this, configuration, 'selectQuery', { condition });
8787
if (results.length === 1) {
8888
// eslint-disable-next-line prefer-destructuring
89-
Id = results[0].Id;
89+
objectToDeleteId = results[0].Id;
9090
} else {
9191
if (results.length === 0) {
9292
this.logger.info('No objects are found');
@@ -101,7 +101,7 @@ module.exports.process = async function process(message, configuration) {
101101

102102
let response;
103103
try {
104-
response = await callJSForceMethod.call(this, configuration, 'sobjectDelete', { id: Id });
104+
response = await callJSForceMethod.call(this, configuration, 'sobjectDelete', { id: objectToDeleteId });
105105
} catch (err) {
106106
this.logger.error('Salesforce error occurred');
107107
return messages.newEmptyMessage();

lib/actions/upsert_v2.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/* eslint-disable no-param-reassign, no-unused-vars, class-methods-use-this */
2+
const { messages } = require('elasticio-node');
3+
const { Upsert } = require('@elastic.io/oih-standard-library/lib/actions/upsert');
4+
const { AttachmentProcessor } = require('@elastic.io/component-commons-library');
5+
const { callJSForceMethod } = require('../helpers/wrapper');
6+
const { createProperty, getLookupFieldsModelWithTypeOfSearch } = require('../helpers/utils');
7+
8+
module.exports.getObjectTypes = async function getObjectTypes(configuration) {
9+
return callJSForceMethod.call(this, configuration, 'getObjectTypes');
10+
};
11+
12+
module.exports.getLookupFieldsModel = async function getLookupFieldsModel(configuration) {
13+
const meta = await callJSForceMethod.call(this, configuration, 'describe');
14+
return getLookupFieldsModelWithTypeOfSearch(meta, configuration.typeOfSearch);
15+
};
16+
17+
module.exports.getMetaModel = async function getMetaModel(configuration) {
18+
const meta = await callJSForceMethod.call(this, configuration, 'describe');
19+
const fields = meta.fields.filter((field) => !field.deprecatedAndHidden
20+
&& field.updateable
21+
&& field.createable);
22+
23+
const result = {
24+
in: {
25+
type: 'object',
26+
properties: {},
27+
},
28+
out: {
29+
type: 'object',
30+
properties: {
31+
id: {
32+
type: 'string',
33+
required: true,
34+
title: 'Unique identifier from CRM',
35+
},
36+
success: {
37+
type: 'boolean',
38+
required: true,
39+
title: 'Request result',
40+
},
41+
errors: {
42+
type: 'array',
43+
required: true,
44+
title: 'Founded errors',
45+
},
46+
},
47+
},
48+
};
49+
50+
result.in.properties[configuration.lookupField] = {
51+
type: 'string',
52+
title: `lookup by - ${configuration.lookupField}`,
53+
required: configuration.lookupField !== 'Id',
54+
};
55+
56+
fields.forEach((field) => {
57+
result.in.properties[field.name] = createProperty(field);
58+
if (field.type === 'base64') result.in.properties[field.name].title += ' - use URL to file';
59+
});
60+
return result;
61+
};
62+
63+
class UpsertObject extends Upsert {
64+
constructor(context) {
65+
super(context);
66+
this.logger = context.logger;
67+
}
68+
69+
getCriteria(_msg, _cfg) {
70+
return true;
71+
}
72+
73+
async lookupObject(_criteria, _type, cfg, msg) {
74+
let existingObj;
75+
if (cfg.lookupField === 'Id' && (!msg.body.Id)) {
76+
existingObj = undefined;
77+
} else {
78+
existingObj = await callJSForceMethod.call(this, cfg, 'sobjectLookup', msg);
79+
if (existingObj.length > 1) {
80+
throw new Error('Found more than 1 Object');
81+
} else if (existingObj.length === 0) {
82+
existingObj = undefined;
83+
}
84+
}
85+
return existingObj;
86+
}
87+
88+
async getObjectFromMessage(msg, cfg) {
89+
const meta = await callJSForceMethod.call(this, cfg, 'describe');
90+
await meta.fields.forEach(async (field) => {
91+
if (field.type === 'base64') {
92+
if (msg.body[field.name]) {
93+
const attachmentProcessor = new AttachmentProcessor();
94+
const attachment = await attachmentProcessor.getAttachment(msg.body[field.name], 'arraybuffer');
95+
msg.body[field.name] = attachment.data.toString('base64');
96+
}
97+
}
98+
});
99+
return msg;
100+
}
101+
102+
async updateObject(_criteria, _type, object, cfg, _msg, existingObject) {
103+
object.body.Id = existingObject[0].Id;
104+
const result = await callJSForceMethod.call(this, cfg, 'sobjectUpdate', object);
105+
return result;
106+
}
107+
108+
async createObject(object, cfg, _msg) {
109+
const result = callJSForceMethod.call(this, cfg, 'sobjectCreate', object);
110+
return result;
111+
}
112+
}
113+
114+
module.exports.process = async function upsertObject(msg, cfg) {
115+
const upsert = new UpsertObject(this);
116+
return upsert.process(msg, cfg, {});
117+
};

0 commit comments

Comments
 (0)