Skip to content
Merged
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
2 changes: 1 addition & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ deployment:
production:
branch: master
commands:
- ./deploy/eb-deploy.sh tc-connect2sf PROD $CIRCLE_BUILD_NUM
- ./deploy/eb-deploy.sh tc-connect2sf PROD $CIRCLE_BUILD_NUM
17 changes: 16 additions & 1 deletion consumer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ Use following JSON for testing
```
{
"id": 1,
"status": "draft",
"details": {
"utm": {
"code": "123"
}
},
"directProjectId": 5001,
"cancelReason":null,
"members": [
{
"userId": 40135978,
Expand All @@ -195,7 +203,14 @@ Use following JSON for testing
},
"updated": {
"id": 1,
"status": "active"
"status": "active",
"directProjectId": 6001,
"cancelReason": "Spam",
"details": {
"utm": {
"code": "123"
}
}
}
}
```
Expand Down
4 changes: 2 additions & 2 deletions consumer/src/scheduled-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ process.once('SIGINT', () => {
});

let EVENT_HANDLERS = {
[EVENT.ROUTING_KEY.PROJECT_DRAFT_CREATED]: ConsumerService.processProjectCreated
// [EVENT.ROUTING_KEY.PROJECT_UPDATED]: ConsumerService.processProjectUpdated
[EVENT.ROUTING_KEY.PROJECT_DRAFT_CREATED]: ConsumerService.processProjectCreated,
[EVENT.ROUTING_KEY.PROJECT_UPDATED]: ConsumerService.processProjectUpdated
}

function close() {
Expand Down
60 changes: 49 additions & 11 deletions consumer/src/services/ConsumerService.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,28 @@ const projectUpdatedSchema = Joi.object().keys({
}).required()
}).unknown(true);

function getUpdatedLeadFieldData(projectUpdated) {
const updatedLead = {};

if (projectUpdated.status) {
updatedLead.TC_Connect_Project_Status__c = projectUpdated.status;
}

if (projectUpdated.cancelReason) {
updatedLead.TC_Connect_Cancel_Reason__c = projectUpdated.cancelReason;
}

if (projectUpdated.details) {
updatedLead.Ref_Code__c = _.get(projectUpdated,"details.utm.code", "");
}
if (projectUpdated.directProjectId) {
updatedLead.TC_Connect_Direct_Project_Id__c = _.get(projectUpdated, "directProjectId","");
}

return updatedLead;
}


class ConsumerService {

/**
Expand Down Expand Up @@ -65,6 +87,10 @@ class ConsumerService {
Company: company,
OwnerId: config.ownerId,
TC_Connect_Project_Id__c: project.id,
TC_Connect_Project_Status__c: _.get(project,"status",""),
Ref_Code__c: _.get(project, "details.utm.code",""),
TC_Connect_Direct_Project_Id__c: _.get(project, "directProjectId",""),
TC_Connect_Cancel_Reason__c: _.get(project,"cancelReason","")
};
return SalesforceService.createObject('Lead', lead, accessToken, instanceUrl)
.then((leadId) => {
Expand All @@ -84,6 +110,7 @@ class ConsumerService {
});
}


/**
* Handle created/launched project
* @param {Object} projectEvent the project
Expand All @@ -92,29 +119,40 @@ class ConsumerService {
processProjectUpdated(logger, projectEvent) {
logger.debug(projectEvent)
var project = projectEvent.original;
var projectUpdated = projectEvent.updated;


return Promise.all([
ConfigurationService.getSalesforceCampaignId(),
SalesforceService.authenticate(),
]).then((responses) => {
const campaignId = responses[0];
const { accessToken, instanceUrl } = responses[1];

// queries existing lead for the project
let sql = `SELECT id FROM Lead WHERE TC_Connect_Project_Id__c = '${project.id}'`;
let sql = `SELECT id,IsConverted FROM Lead WHERE TC_Connect_Project_Id__c = '${project.id}'`;
return SalesforceService.query(sql, accessToken, instanceUrl)
.then((response) => {
const {records: [lead]} = response;
if (!lead) {
throw new UnprocessableError(`Cannot find Lead with TC_Connect_Project_Id__c = '${project.id}'`);
throw new UnprocessableError(`Cannot find Lead with TC_Connect_Project_Id__c = '${project.id}'`);
}

const leadUpdate = getUpdatedLeadFieldData(projectUpdated);

if (lead.IsConverted != true && !_.isEmpty(leadUpdate)) {
return SalesforceService.updateObject(lead.Id, 'Lead', leadUpdate, accessToken, instanceUrl);
}
sql = `SELECT id FROM CampaignMember WHERE LeadId = '${lead.Id}' AND CampaignId ='${campaignId}'`;
return SalesforceService.query(sql, accessToken, instanceUrl)
.then((response) => {
const {records: [member]} = response;
if (!member) {
throw new UnprocessableError(`Cannot find CampaignMember for Lead.TC_Connect_Project_Id__c = '${project.id}'`);
}
return SalesforceService.deleteObject('CampaignMember', member.Id, accessToken, instanceUrl);
})

// sql = `SELECT id FROM CampaignMember WHERE LeadId = '${lead.Id}' AND CampaignId ='${campaignId}'`;
// return SalesforceService.query(sql, accessToken, instanceUrl)
// .then((response) => {
// const {records: [member]} = response;
// if (!member) {
// throw new UnprocessableError(`Cannot find CampaignMember for Lead.TC_Connect_Project_Id__c = '${project.id}'`);
// }
// return SalesforceService.deleteObject('CampaignMember', member.Id, accessToken, instanceUrl);
// })
})
});
}
Expand Down
28 changes: 28 additions & 0 deletions consumer/src/services/SalesforceService.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ const createObjectSchema = {
instanceUrl: Joi.string().required(),
};

const updateObjectSchema = {
id: Joi.string().required(),
type: Joi.string().required(),
params: Joi.object().required(),
accessToken: Joi.string().required(),
instanceUrl: Joi.string().required(),
};

const deleteObjectSchema = {
type: Joi.string().required(),
id: Joi.string().required(),
Expand Down Expand Up @@ -86,6 +94,26 @@ class SalesforceService {
.then((res) => res.body.id);
}

/**
* Update an existing object
* @param {String} type the type name
* @param {String} params the object properties
* @param {String} accessToken the access token
* @param {String} instanceUrl the salesforce instance url
* @returns {String} the updated object id
*/
@logAndValidate(['id','type', 'params', 'accessToken', 'instanceUrl'], updateObjectSchema)
updateObject(id, type, params, accessToken, instanceUrl) {
return request
.patch(`${instanceUrl}/services/data/v37.0/sobjects/${type}/${id}`)
.set({
authorization: `Bearer ${accessToken}`,
})
.send(params)
.end();
}


/**
* Run the query statement
* @param {String} sql the Saleforce sql statement
Expand Down
4 changes: 2 additions & 2 deletions consumer/src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ process.once('SIGINT', () => {
});

let EVENT_HANDLERS = {
[EVENT.ROUTING_KEY.PROJECT_DRAFT_CREATED]: ConsumerService.processProjectCreated
// [EVENT.ROUTING_KEY.PROJECT_UPDATED]: ConsumerService.processProjectUpdated
[EVENT.ROUTING_KEY.PROJECT_DRAFT_CREATED]: ConsumerService.processProjectCreated,
[EVENT.ROUTING_KEY.PROJECT_UPDATED]: ConsumerService.processProjectUpdated
}

export function initHandlers(handlers) {
Expand Down
39 changes: 29 additions & 10 deletions consumer/test/ConsumerService.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,15 @@ describe('ConsumerService', () => {
instanceUrl: 'http://fake-domain',
};
const userId = 40135978;

const project = {
id: 1,
details: {
utm: {
code: "123"
}
},
cancelReason: null,
members: [
{
id: 1234,
Expand All @@ -42,7 +49,8 @@ describe('ConsumerService', () => {
},
updated: {
id: 1,
status: 'active'
status: 'active',
cancelReason: null
}
}
let sandbox;
Expand All @@ -64,6 +72,7 @@ describe('ConsumerService', () => {

describe('processProjectCreated', () => {
it('should process project successfully', async() => {

const expectedLead = {
FirstName: 'john',
LastName: 'doe',
Expand All @@ -72,6 +81,10 @@ describe('ConsumerService', () => {
Company: 'Unknown',
OwnerId: config.ownerId,
TC_Connect_Project_Id__c: 1,
Ref_Code__c: '123',
TC_Connect_Project_Status__c: '',
TC_Connect_Cancel_Reason__c: null,
TC_Connect_Direct_Project_Id__c: ''
};

const expectedCampaignMember = {
Expand Down Expand Up @@ -132,21 +145,26 @@ describe('ConsumerService', () => {
describe('processProjectUpdated', () => {
it('should process project successfully', async() => {
const memberId = 'member-id';
const leadSql = `SELECT id FROM Lead WHERE TC_Connect_Project_Id__c = '${project.id}'`;
const memberSql = `SELECT id FROM CampaignMember WHERE LeadId = '${leadId}' AND CampaignId ='${sfCampaignId}'`;
const leadSql = `SELECT id,IsConverted FROM Lead WHERE TC_Connect_Project_Id__c = '${project.id}'`;
// const memberSql = `SELECT id FROM CampaignMember WHERE LeadId = '${leadId}' AND CampaignId ='${sfCampaignId}'`;

const queryStub = sandbox.stub(SalesforceService, 'query');


queryStub.onCall(0)
.returns(Promise.resolve({ records: [{ Id: leadId }] }));
queryStub.onCall(1)
.returns(Promise.resolve({ records: [{ Id: memberId }] }));
const deleteObjectStub = sandbox.stub(SalesforceService, 'deleteObject');
// queryStub.onCall(1)
// .returns(Promise.resolve({ records: [{ Id: memberId }] }));
// const deleteObjectStub = sandbox.stub(SalesforceService, 'deleteObject');

const updateStub = sandbox.stub(SalesforceService,'updateObject', async() => {});


await ConsumerService.processProjectUpdated(logger, projectUpdatePaylod);
queryStub.should.have.been.calledWith(leadSql, sfAuth.accessToken, sfAuth.instanceUrl);
queryStub.should.have.been.calledWith(memberSql, sfAuth.accessToken, sfAuth.instanceUrl);
deleteObjectStub.should.have.been.calledWith('CampaignMember', memberId, sfAuth.accessToken,
sfAuth.instanceUrl);
// queryStub.should.have.been.calledWith(memberSql, sfAuth.accessToken, sfAuth.instanceUrl);
// deleteObjectStub.should.have.been.calledWith('CampaignMember', memberId, sfAuth.accessToken,
// sfAuth.instanceUrl);
});

it('should throw UnprocessableError if Lead cannot be found', async() => {
Expand All @@ -158,7 +176,8 @@ describe('ConsumerService', () => {
queryStub.should.have.been.called;
});

it('should throw UnprocessableError if CampaignMember cannot be found', async() => {
// Not a valid use case any more
xit('should throw UnprocessableError if CampaignMember cannot be found', async() => {
const queryStub = sandbox.stub(SalesforceService, 'query');
queryStub.onCall(0)
.returns(Promise.resolve({ records: [{ Id: leadId }] }));
Expand Down