1- import _ from 'lodash' ;
21import config from 'config' ;
32import moment from 'moment' ;
43import { Op } from 'sequelize' ;
54
65import models from '../../models' ;
7- import { CONNECT_NOTIFICATION_EVENT , COPILOT_OPPORTUNITY_STATUS , COPILOT_REQUEST_STATUS , TEMPLATE_IDS , USER_ROLE } from '../../constants' ;
6+ import {
7+ CONNECT_NOTIFICATION_EVENT ,
8+ COPILOT_OPPORTUNITY_STATUS ,
9+ COPILOT_REQUEST_STATUS ,
10+ TEMPLATE_IDS ,
11+ USER_ROLE ,
12+ } from '../../constants' ;
813import util from '../../util' ;
914import { createEvent } from '../../services/busApi' ;
1015import { getCopilotTypeLabel } from '../../utils/copilot' ;
@@ -17,85 +22,86 @@ const resolveTransaction = (transaction, callback) => {
1722 return models . sequelize . transaction ( callback ) ;
1823} ;
1924
20- module . exports = ( req , data , existingTransaction ) => {
25+ module . exports = async ( req , data , existingTransaction ) => {
2126 const { projectId, copilotRequestId, opportunityTitle, type, startDate } = data ;
2227
23- return resolveTransaction ( existingTransaction , transaction =>
24- models . Project . findOne ( {
25- where : { id : projectId , deletedAt : { $eq : null } } ,
26- } , { transaction } )
27- . then ( ( existingProject ) => {
28- if ( ! existingProject ) {
29- const err = new Error ( `active project not found for project id ${ projectId } ` ) ;
30- err . status = 404 ;
31- throw err ;
32- }
33- return models . CopilotRequest . findByPk ( copilotRequestId , { transaction } )
34- . then ( ( existingCopilotRequest ) => {
35- if ( ! existingCopilotRequest ) {
36- const err = new Error ( `no active copilot request found for copilot request id ${ copilotRequestId } ` ) ;
37- err . status = 404 ;
38- throw err ;
39- }
40-
41- return existingCopilotRequest . update ( {
42- status : COPILOT_REQUEST_STATUS . APPROVED ,
43- } , { transaction } ) . then ( ( ) => models . CopilotOpportunity
44- . findOne ( {
45- where : {
46- projectId,
47- type : data . type ,
48- status : {
49- [ Op . in ] : [ COPILOT_OPPORTUNITY_STATUS . ACTIVE ] ,
50- }
51- } ,
52- } )
53- . then ( ( existingCopilotOpportunityOfSameType ) => {
54- if ( existingCopilotOpportunityOfSameType ) {
55- const err = new Error ( 'There\'s an active opportunity of same type already!' ) ;
56- _ . assign ( err , {
57- status : 403 ,
58- } ) ;
59- throw err ;
60- }
61- return models . CopilotOpportunity
62- . create ( data , { transaction } ) ;
63- } ) )
64- . then ( async ( opportunity ) => {
65- const roles = await util . getRolesByRoleName ( USER_ROLE . TC_COPILOT , req . log , req . id ) ;
66- const { subjects = [ ] } = await util . getRoleInfo ( roles [ 0 ] , req . log , req . id ) ;
67- const emailEventType = CONNECT_NOTIFICATION_EVENT . EXTERNAL_ACTION_EMAIL ;
68- const copilotPortalUrl = config . get ( 'copilotPortalUrl' ) ;
69- req . log . info ( "Sending emails to all copilots about new opportunity" ) ;
70-
71- const sendNotification = ( userName , recipient ) => createEvent ( emailEventType , {
72- data : {
73- user_name : userName ,
74- opportunity_details_url : `${ copilotPortalUrl } /opportunity/${ opportunity . id } ` ,
75- work_manager_url : config . get ( 'workManagerUrl' ) ,
76- opportunity_type : getCopilotTypeLabel ( type ) ,
77- opportunity_title : opportunityTitle ,
78- start_date : moment ( startDate ) . format ( "DD-MM-YYYY" ) ,
79- } ,
80- sendgrid_template_id : TEMPLATE_IDS . CREATE_REQUEST ,
81- recipients : [ recipient ] ,
82- version : 'v3' ,
83- } , req . log ) ;
84-
85- subjects . forEach ( subject => sendNotification ( subject . handle , subject . email ) ) ;
86-
87- // send email to notify via slack
88- sendNotification ( 'Copilots' , config . copilotsSlackEmail ) ;
89-
90- req . log . info ( "Finished sending emails to copilots" ) ;
91-
92- return opportunity ;
93- } )
94- . catch ( ( err ) => {
95- transaction . rollback ( ) ;
96- return Promise . reject ( err ) ;
97- } ) ;
98- } ) ;
99- } ) ,
100- ) ;
28+ return resolveTransaction ( existingTransaction , async ( transaction ) => {
29+ try {
30+ const existingProject = await models . Project . findOne ( {
31+ where : { id : projectId , deletedAt : { $eq : null } } ,
32+ transaction,
33+ } ) ;
34+
35+ if ( ! existingProject ) {
36+ const err = new Error ( `active project not found for project id ${ projectId } ` ) ;
37+ err . status = 404 ;
38+ throw err ;
39+ }
40+
41+ const copilotRequest = await models . CopilotRequest . findByPk ( copilotRequestId , { transaction } ) ;
42+
43+ if ( ! copilotRequest ) {
44+ const err = new Error ( `no active copilot request found for copilot request id ${ copilotRequestId } ` ) ;
45+ err . status = 404 ;
46+ throw err ;
47+ }
48+
49+ await copilotRequest . update ( { status : COPILOT_REQUEST_STATUS . APPROVED } , { transaction } ) ;
50+
51+ const existingOpportunity = await models . CopilotOpportunity . findOne ( {
52+ where : {
53+ projectId,
54+ type : data . type ,
55+ status : { [ Op . in ] : [ COPILOT_OPPORTUNITY_STATUS . ACTIVE ] } ,
56+ } ,
57+ transaction,
58+ } ) ;
59+
60+ if ( existingOpportunity ) {
61+ const err = new Error ( 'There\'s an active opportunity of same type already!' ) ;
62+ err . status = 403 ;
63+ throw err ;
64+ }
65+
66+ const opportunity = await models . CopilotOpportunity . create ( data , { transaction } ) ;
67+ req . log . debug ( 'Created new copilot opportunity' , { opportunityId : opportunity . id } ) ;
68+
69+ // Send notifications
70+ try {
71+ const roles = await util . getRolesByRoleName ( USER_ROLE . TC_COPILOT , req . log , req . id ) ;
72+
73+ const { subjects = [ ] } = await util . getRoleInfo ( roles [ 0 ] , req . log , req . id ) ;
74+ const emailEventType = CONNECT_NOTIFICATION_EVENT . EXTERNAL_ACTION_EMAIL ;
75+ const copilotPortalUrl = config . get ( 'copilotPortalUrl' ) ;
76+ req . log . info ( 'Sending emails to all copilots about new opportunity' ) ;
77+
78+ const sendNotification = ( userName , recipient ) => createEvent ( emailEventType , {
79+ data : {
80+ user_name : userName ,
81+ opportunity_details_url : `${ copilotPortalUrl } /opportunity/${ opportunity . id } ` ,
82+ work_manager_url : config . get ( 'workManagerUrl' ) ,
83+ opportunity_type : getCopilotTypeLabel ( type ) ,
84+ opportunity_title : opportunityTitle ,
85+ start_date : moment ( startDate ) . format ( 'DD-MM-YYYY' ) ,
86+ } ,
87+ sendgrid_template_id : TEMPLATE_IDS . CREATE_REQUEST ,
88+ recipients : [ recipient ] ,
89+ version : 'v3' ,
90+ } , req . log ) ;
91+
92+ subjects . forEach ( subject => sendNotification ( subject . handle , subject . email ) ) ;
93+
94+ // send email to notify via slack
95+ sendNotification ( 'Copilots' , config . copilotsSlackEmail ) ;
96+ req . log . info ( 'Finished sending emails to copilots' ) ;
97+ } catch ( emailErr ) {
98+ req . log . error ( 'Error sending notifications' , { error : emailErr } ) ;
99+ }
100+
101+ return opportunity ;
102+ } catch ( err ) {
103+ req . log . error ( 'approveRequest failed' , { error : err } ) ;
104+ throw err ; // let outer transaction handle rollback
105+ }
106+ } ) ;
101107} ;
0 commit comments