From 146b8217bbc899d69635079932c68642b384f640 Mon Sep 17 00:00:00 2001 From: Sybrand Strauss Date: Mon, 2 Apr 2018 23:11:44 -0700 Subject: [PATCH 1/2] Code challenge 251 --- .../opportunity-assigned-body.md | 19 ++++++ .../opportunity-assigned-subject.md | 1 + .../proposals.client.controller.js | 21 +++++-- .../services/proposals.client.service.js | 4 ++ .../proposals.server.controller.js | 62 +++++++++++++++++++ .../policies/proposals.server.policy.js | 3 + .../server/routes/proposals.server.routes.js | 2 + 7 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 modules/core/server/email_templates/opportunity-assigned-body.md create mode 100644 modules/core/server/email_templates/opportunity-assigned-subject.md diff --git a/modules/core/server/email_templates/opportunity-assigned-body.md b/modules/core/server/email_templates/opportunity-assigned-body.md new file mode 100644 index 000000000..69256d2c0 --- /dev/null +++ b/modules/core/server/email_templates/opportunity-assigned-body.md @@ -0,0 +1,19 @@ +{{#markdown this}} +![BC Dev Exchange](https://bcdevexchange.org/modules/core/client/img/logo/new-logo-220px.png) + +### An opportunity has been assigned + +[See the details for {{ data.opportunity.name }}]({{ data.domain }}/opportunities/cwu/{{ data.opportunity.code }}) + + Unique ID: {{ data.opportunity.id }} + Vendor's legal name: {{ data.vendor.name }} + Vendor's legal address: {{ data.vendor.address }} + Vendor's business number: {{ data.vendor.business_number }} + Contact (email): {{ data.vendor.email }} + + +----------------------------- +BC Developers' Exchange and DevOps +Ministry of Technology, Innovation and Citizens' Services +[BCDevExchange.org](http://bcdevexchange.org) +{{/markdown}} diff --git a/modules/core/server/email_templates/opportunity-assigned-subject.md b/modules/core/server/email_templates/opportunity-assigned-subject.md new file mode 100644 index 000000000..f34005770 --- /dev/null +++ b/modules/core/server/email_templates/opportunity-assigned-subject.md @@ -0,0 +1 @@ +Opportunity {{data.opportunity.name}} has been assigned \ No newline at end of file diff --git a/modules/proposals/client/controllers/proposals.client.controller.js b/modules/proposals/client/controllers/proposals.client.controller.js index b36247a6e..eca53c8c5 100644 --- a/modules/proposals/client/controllers/proposals.client.controller.js +++ b/modules/proposals/client/controllers/proposals.client.controller.js @@ -106,11 +106,22 @@ function (response) { ppp.proposal = response; Notification.success({ message: ' Company has been assigned'}); - if (ppp.opportunity.opportunityTypeCd === 'sprint-with-us') { - $state.go ('opportunities.viewswu',{opportunityId:ppp.opportunity.code}); - } else { - $state.go ('opportunities.viewcwu',{opportunityId:ppp.opportunity.code}); - } + // NB: I would have thought that kicking off the notification to branch financial staff + // would be something that should be done on the server side (proposals.server.controller). + // I have however placed the logic here due to the specific request: "Ensure that you use a + // REST endpoint to send the email notification" + ProposalsService.notifyBranchFinancialStaff({_id: ppp.proposal._id}) + .$promise + .then() + .finally(function() { + // By placing this section in "finally", we ensure that the flow won't + // be interrupted by a failure to send a notification email. + if (ppp.opportunity.opportunityTypeCd === 'sprint-with-us') { + $state.go ('opportunities.viewswu',{opportunityId:ppp.opportunity.code}); + } else { + $state.go ('opportunities.viewcwu',{opportunityId:ppp.opportunity.code}); + } + }); }, function (error) { Notification.error ({ message: error.data.message, title: ' Proposal Assignment failed!' }); diff --git a/modules/proposals/client/services/proposals.client.service.js b/modules/proposals/client/services/proposals.client.service.js index cfe711432..5de92f552 100644 --- a/modules/proposals/client/services/proposals.client.service.js +++ b/modules/proposals/client/services/proposals.client.service.js @@ -23,6 +23,10 @@ method: 'PUT', url: '/api/assign/proposal/:proposalId' }, + notifyBranchFinancialStaff: { + method: 'PUT', + url: '/api/assign/proposal/:proposalId/notifyFinance' + }, forOpportunity: { method: 'GET', url: '/api/proposals/for/opportunity/:opportunityId', diff --git a/modules/proposals/server/controllers/proposals.server.controller.js b/modules/proposals/server/controllers/proposals.server.controller.js index ba9de107e..a013b072c 100644 --- a/modules/proposals/server/controllers/proposals.server.controller.js +++ b/modules/proposals/server/controllers/proposals.server.controller.js @@ -339,9 +339,71 @@ exports.assign = function (req, res) { .then (function () { return Opportunities.assign (proposal.opportunity._id, proposal._id, proposal.user, req.user); }) + // Note: I would have placed the call to Notify Branch Financial Staff Opportunities + // here if not for the specific instruction to hit a REST service. Doing something as + // follows: + // .then (function () { + // notifyBranchFinancialStaff({...blah blah...}); + // }) + // It doesn't make sense to me to break back to a REST service at this point, so I'm + // assuming it's wanted in the front end. .then (function () {res.json (proposal); }) .catch (function (e) {res.status(422).send ({ message: errorHandler.getErrorMessage(e) }); }); }; +exports.notifyBranchFinancialStaff = function (req, res) { + Proposal.findById(req.params.proposalId) + .populate('user') + .populate('opportunity') + .exec(function (err, proposal) { + if (err) { + res.status(500).send({ message: errorHandler.getErrorMessage(err)}); + } + else if (!proposal) { + res.status(404).send({ message: 'Could not load proposal ' + req.params.proposalId}); + } + else { + var data = { + useremail: 'placeholder@placeholder.com', // TODO: Assumes https://github.com/BCDevExchange/devex/issues/236 has been completed. + opportunity: { + name: proposal.opportunity.name, + id: proposal.opportunity._id, + code: proposal.opportunity.code + }, + vendor: proposal.isCompany ? + { + name: proposal.businessName, + address: proposal.businessAddress, + business_number: proposal.businessNumber, + email: proposal.businessContactEmail + } : + { + name: proposal.user.firstName + ' ' + proposal.user.lastName, + address: proposal.user.address, + business_number: proposal.user.phone, + email: proposal.user.email + } + } + try { + Notifications.notifyUserAdHoc('opportunity-assigned', data).then( + function(success) { + console.log(success); + res.json({}).send(); + }, + function(error) { + console.log('error', error); + res.status(500).send(error); + } + ).catch(function (e) { + res.status(500).send({ message: errorHandler.getErrorMessage(e) }); + }); + } catch (e) { + res.status(500).send({ message: errorHandler.getErrorMessage(e) }); + } + } + }).catch(function (e) { + res.status(500).send({ message: errorHandler.getErrorMessage(e) }); + }); +}; // ------------------------------------------------------------------------- // // unassign gets called from the opportunity side, so just do the work diff --git a/modules/proposals/server/policies/proposals.server.policy.js b/modules/proposals/server/policies/proposals.server.policy.js index 4059d30c8..bda9747a7 100644 --- a/modules/proposals/server/policies/proposals.server.policy.js +++ b/modules/proposals/server/policies/proposals.server.policy.js @@ -38,6 +38,9 @@ exports.invokeRolesPolicies = function () { }, { resources: '/api/proposals/:proposalId', permissions: '*' + }, { + resources: '/api/assign/proposal/:proposalId/notifyFinance', + permissions: '*' }] }, { roles: ['user'], diff --git a/modules/proposals/server/routes/proposals.server.routes.js b/modules/proposals/server/routes/proposals.server.routes.js index b8b5bf636..20027ab10 100644 --- a/modules/proposals/server/routes/proposals.server.routes.js +++ b/modules/proposals/server/routes/proposals.server.routes.js @@ -21,6 +21,8 @@ module.exports = function(app) { .put(proposals.submit); app.route('/api/assign/proposal/:proposalId').all(proposalsPolicy.isAllowed) .put(proposals.assign); + app.route('/api/assign/proposal/:proposalId/notifyFinance').all(proposalsPolicy.isAllowed) + .put(proposals.notifyBranchFinancialStaff) // // proposals for opportunity // From d6ef6e62923add6beb3090e56444cd9cc8620d6d Mon Sep 17 00:00:00 2001 From: Sybrand Strauss Date: Mon, 2 Apr 2018 23:34:36 -0700 Subject: [PATCH 2/2] Fixed company phone number bug --- .../proposals/server/controllers/proposals.server.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/proposals/server/controllers/proposals.server.controller.js b/modules/proposals/server/controllers/proposals.server.controller.js index a013b072c..e3367e444 100644 --- a/modules/proposals/server/controllers/proposals.server.controller.js +++ b/modules/proposals/server/controllers/proposals.server.controller.js @@ -373,7 +373,7 @@ exports.notifyBranchFinancialStaff = function (req, res) { { name: proposal.businessName, address: proposal.businessAddress, - business_number: proposal.businessNumber, + business_number: proposal.businessContactPhone, email: proposal.businessContactEmail } : {