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
38 changes: 30 additions & 8 deletions consumer/src/salesforce-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,42 @@ export function consumeMessage(message) {
debug('Got Connect_SFDC__e', message);
const payload = _.get(message, 'payload');
const eventType = _.get(payload, 'Type__c');
const original = JSON.parse(_.get(payload, 'Original__c'));
const updated = JSON.parse(_.get(payload, 'Updated__c'));
let statusToBe = null;
let statusChangeReason = null;
if (eventType === 'billingAccount.updated') {
const original = JSON.parse(_.get(payload, 'Original__c'));
const updated = JSON.parse(_.get(payload, 'Updated__c'));
const oldStatus = _.get(original, 'Active__c');
const updatedStatus = _.get(updated, 'Active__c');
debug(`${oldStatus} === ${updatedStatus}`);
if (oldStatus !== updatedStatus && updatedStatus === true) {
const projectId = _.get(updated, 'TC_Connect_Project_ID__c');
debug(`Activating project with id ${projectId}`);
// TODO retrieve project id from the payload
if (projectId) {
ProjectService.activateProject(projectId);
}
statusToBe = 'active'
}
} else if (eventType === 'opportunity.won') {
// TODO
} else if (eventType === 'opportunity.lost') {
// Cancel connect project
statusToBe = 'cancelled'
statusChangeReason = _.get(updated, 'Loss_Description__c', 'Opportunity Lost');
} else if (eventType === 'lead.disqualified') {
// Cancel the project
statusToBe = 'cancelled'
statusChangeReason = _.get(updated, 'Disqualified_Reason__c', 'Lead Disqualified');
} else if (eventType === 'opportunity.create') {
// Move to reviewed status
statusToBe = 'reviewed'
} else if (eventType === 'lead.qualified') {
// Move to reviewed status
statusToBe = 'reviewed'
}
let projectId = _.get(updated, 'TC_Connect_Project_ID__c');
if (!projectId) {
projectId = _.get(updated, 'TC_Connect_Project_Id__c');
}
debug(`Status to be updated: ${statusToBe} for project with id ${projectId}`);
if (statusToBe && projectId) {
debug(`Updating status to ${statusToBe} project with id ${projectId}`);
ProjectService.updateProjectStatus(projectId, statusToBe, statusChangeReason);
}
}

Expand Down
15 changes: 6 additions & 9 deletions consumer/src/services/ConsumerService.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import IdentityService from './IdentityService';
import SalesforceService from './SalesforceService';
import {UnprocessableError} from '../common/errors';

const memberRole = 'customer';
const duplicateRecordRegex = /TC_Connect_Project_Id__c duplicates value on record/;

const projectCreatedSchema = Joi.object().keys({
Expand Down Expand Up @@ -40,18 +39,15 @@ class ConsumerService {
@log(['project'])
@validate(['logger','project'], projectCreatedSchema)
processProjectCreated(logger, project) {
const member = _.find(project.members, {role: memberRole, isPrimary: true});
if (!member) {
logger.info('Project Members:');
logger.info(project.members);
throw new UnprocessableError('Cannot find primary customer');
}
logger.info(`Project Created By: ${project.createdBy}`);
return Promise.all([
IdentityService.getUser(member.userId),
IdentityService.getUser(project.createdBy),
SalesforceService.authenticate(),
]).then((responses) => {
const user = responses[0];
project.createdByEmail = user.email;
project.createdByFirstName = user.firstName;
project.createdByLastName = user.lastName;
const { accessToken, instanceUrl } = responses[1];
const leadData = {
Type__c: 'connect.project.created',
Expand Down Expand Up @@ -80,7 +76,6 @@ class ConsumerService {
@log(['projectEvent'])
@validate(['logger', 'projectEvent'], projectUpdatedSchema)
processProjectUpdated(logger, projectEvent) {
logger.debug(projectEvent)
delete projectEvent.original.template;
delete projectEvent.updated.template;
var project = projectEvent.original;
Expand All @@ -93,6 +88,8 @@ class ConsumerService {
const user = responses[0];
const { accessToken, instanceUrl } = responses[1];
projectEvent.original.createdByEmail = user.email;
projectEvent.original.createdByFirstName = user.firstName;
projectEvent.original.createdByLastName = user.lastName;

const leadData = {
Type__c: 'connect.project.updated',
Expand Down
44 changes: 22 additions & 22 deletions consumer/src/services/ProjectService.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const request = require('superagent');
const config = require('config');
const _ = require('lodash');

const debug = require('debug')('app:project-service');

/**
* Get project details
*
Expand All @@ -14,25 +16,22 @@ const _ = require('lodash');
* @return {Promise} promise resolved to project details
*/
const getProject = (projectId) => {
console.log(`AUTH0_CLIENT_ID: ${config.AUTH0_CLIENT_ID.substring(0, 5)}`);
console.log(`AUTH0_CLIENT_SECRET: ${config.AUTH0_CLIENT_SECRET.substring(0, 5)}`);
console.log(`AUTH0_URL: ${config.AUTH0_URL}`);
console.log(`AUTH0_AUDIENCE: ${config.AUTH0_AUDIENCE}`);
console.log(`AUTH0_PROXY_SERVER_URL: ${config.AUTH0_PROXY_SERVER_URL}`);
debug(`AUTH0_CLIENT_ID: ${config.AUTH0_CLIENT_ID.substring(0, 5)}`);
debug(`AUTH0_CLIENT_SECRET: ${config.AUTH0_CLIENT_SECRET.substring(0, 5)}`);
return M2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET)
.then((token) => (
request
.get(`${config.projectApi.url}/projects/${projectId}`)
.set('accept', 'application/json')
.set('authorization', `Bearer ${token}`)
.then((res) => {
if (!_.get(res, 'body.result.success')) {
if (res.status !== 200) {
throw new Error(`Failed to get project details of project id: ${projectId}`);
}
const project = _.get(res, 'body.result.content');
const project = _.get(res, 'body');
return project;
}).catch((err) => {
const errorDetails = _.get(err, 'response.body.result.content.message');
const errorDetails = _.get(err, 'response.body');
throw new Error(
`Failed to get project details of project id: ${projectId}.` +
(errorDetails ? ' Server response: ' + errorDetails : '')
Expand All @@ -52,31 +51,32 @@ const getProject = (projectId) => {
*
* @return {Promise} promise resolved to the updated project
*/
const activateProject = (projectId) => {
console.log(`AUTH0_CLIENT_ID: ${config.AUTH0_CLIENT_ID.substring(0, 5)}`);
console.log(`AUTH0_CLIENT_SECRET: ${config.AUTH0_CLIENT_SECRET.substring(0, 5)}`);
console.log(`AUTH0_URL: ${config.AUTH0_URL}`);
console.log(`AUTH0_AUDIENCE: ${config.AUTH0_AUDIENCE}`);
console.log(`AUTH0_PROXY_SERVER_URL: ${config.AUTH0_PROXY_SERVER_URL}`);
const updateProjectStatus = (projectId, status='active', changeReason) => {
debug(`AUTH0_CLIENT_ID: ${config.AUTH0_CLIENT_ID.substring(0, 5)}`);
debug(`AUTH0_CLIENT_SECRET: ${config.AUTH0_CLIENT_SECRET.substring(0, 5)}`);
const updatedProject = { status };
if (changeReason) {
updatedProject.cancelReason = changeReason;
}
return M2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET)
.then((token) => (
request
.patch(`${config.projectApi.url}/projects/${projectId}`)
.set('accept', 'application/json')
.set('Authorization', `Bearer ${token}`)
.send({ param : { status : 'active' } })
.send(updatedProject)
.then((res) => {
if (!_.get(res, 'body.result.success')) {
throw new Error(`Failed to activate project with id: ${projectId}`);
if (res.status !== 200) {
throw new Error(`Failed to update project with id: ${projectId}`);
}
const project = _.get(res, 'body.result.content');
const project = _.get(res, 'body');
if (project) {
console.log(`Successfully activated the project with id ${projectId}`);
debug(`Successfully updated the project ${projectId} with status ${status}`);
}
return project;
}).catch((err) => {
console.log(err);
const errorDetails = _.get(err, 'response.body.result.content.message');
debug(err);
const errorDetails = _.get(err, 'response.body');
throw new Error(
`Failed to update project with id: ${projectId}.` +
(errorDetails ? ' Server response: ' + errorDetails : '')
Expand All @@ -91,5 +91,5 @@ const activateProject = (projectId) => {

module.exports = {
getProject,
activateProject
updateProjectStatus
};
52 changes: 36 additions & 16 deletions consumer/test/ConsumerService.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,12 @@ describe('ConsumerService', () => {
isPrimary: true,
},
],
createdByEmail : "jd@example.com"
createdBy: userId
};
const projectUpdatePaylod = {
original: {
id: 1,
status: 'in_review',
createdByEmail : "jd@example.com"
status: 'in_review'
},
updated: {
id: 1,
Expand All @@ -84,7 +83,12 @@ describe('ConsumerService', () => {
it('should process project successfully', async() => {
const expectedLead = {
Type__c: 'connect.project.created',
Json__c: JSON.stringify(project)
Json__c: JSON.stringify({
...project,
createdByEmail : user.email,
createdByFirstName: user.firstName,
createdByLastName: user.lastName
})
};

const createObjectStub = sandbox.stub(SalesforceService, 'createObject', async() => leadId);
Expand All @@ -95,19 +99,27 @@ describe('ConsumerService', () => {
createObjectStub.should.have.been.calledWith('Connect_Event__c', expectedLead, sfAuth.accessToken, sfAuth.instanceUrl);
});

it('should throw UnprocessableError primary customer is not found', async() => {
it('should NOT throw any error even if primary customer is not found', async() => {
const projectWihoutMembers = {
id: 1,
members: [],
...project,
members : []
};
try {
ConsumerService.processProjectCreated(logger, projectWihoutMembers);
sinon.fail('Should be rejected');
} catch(err) {
expect(err).to.exist
.and.be.instanceof(UnprocessableError)
.and.have.property('message').and.match(/Cannot find primary customer/);
}
const expectedLead = {
Type__c: 'connect.project.created',
Json__c: JSON.stringify({
...projectWihoutMembers,
createdByEmail : user.email,
createdByFirstName: user.firstName,
createdByLastName: user.lastName
})
};

const createObjectStub = sandbox.stub(SalesforceService, 'createObject', async() => leadId);

await ConsumerService.processProjectCreated(logger, projectWihoutMembers);
getUserStub.should.have.been.calledWith(userId);
authenticateStub.should.have.been.called;
createObjectStub.should.have.been.calledWith('Connect_Event__c', expectedLead, sfAuth.accessToken, sfAuth.instanceUrl);
});

it('should rethrow Error from createObject if error is not duplicate', async() => {
Expand All @@ -128,7 +140,15 @@ describe('ConsumerService', () => {
const memberId = 'member-id';
const expectedLead = {
Type__c: 'connect.project.updated',
Json__c: JSON.stringify(projectUpdatePaylod)
Json__c: JSON.stringify({
original: {
...projectUpdatePaylod.original,
createdByEmail : user.email,
createdByFirstName: user.firstName,
createdByLastName: user.lastName
},
updated: projectUpdatePaylod.updated
})
};
const createObjectStub = sandbox.stub(SalesforceService,'createObject', async() => {});

Expand Down
32 changes: 12 additions & 20 deletions consumer/test/ProjectService.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,13 @@ const authenticateResponse = {
};

const getProjectResponse = {
id: '-88f3803:1557f8485b0:-b0a',
result: {
success: true,
status: 200,
metadata: null,
content: {
id: '265522',
modifiedBy: null,
modifiedAt: '2016-06-01T16:57:47.000Z',
createdBy: null,
createdAt: '2002-02-06T18:06:40.000Z',
status: 'active',
name: 'Test Project',
},
},
version: 'v4',
id: '265522',
modifiedBy: null,
modifiedAt: '2016-06-01T16:57:47.000Z',
createdBy: null,
createdAt: '2002-02-06T18:06:40.000Z',
status: 'active',
name: 'Test Project',
};


Expand Down Expand Up @@ -80,8 +71,8 @@ describe('ProjectService', () => {
})
.get('/projects/1234')
.reply(200, getProjectResponse);
const user = await ProjectService.getProject(1234);
expect(user).to.deep.equal(getProjectResponse.result.content);
const project = await ProjectService.getProject(1234);
expect(project).to.deep.equal(getProjectResponse);
fakeHttp.done();
});

Expand All @@ -93,8 +84,9 @@ describe('ProjectService', () => {
})
.patch('/projects/1234')
.reply(200, getProjectResponse);
const user = await ProjectService.activateProject(1234);
expect(user).to.deep.equal(getProjectResponse.result.content);
const project = await ProjectService.updateProjectStatus(1234);
console.log(project, 'project')
expect(project).to.deep.equal(getProjectResponse);
fakeHttp.done();
});
});
Expand Down
6 changes: 3 additions & 3 deletions consumer/test/salesforce-worker.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ describe('salesforce-worker', () => {
}
}
describe('consumeMessage', () => {
let activateProjectSpy;
let updateProjectStatusSpy;
beforeEach(() => {
activateProjectSpy = ProjectService.activateProject = sinon.spy();
updateProjectStatusSpy = ProjectService.updateProjectStatus = sinon.spy();
});

/**
Expand All @@ -29,7 +29,7 @@ describe('salesforce-worker', () => {

it('should consume and active project successfully', (done) => {
invokeConsume(done);
activateProjectSpy.should.have.been.calledWith(1234);
updateProjectStatusSpy.should.have.been.calledWith(1234);
done();
});
});
Expand Down