diff --git a/scripts/playground.mongodb.js b/scripts/playground.mongodb.js index 92ae89b..be81bbf 100644 --- a/scripts/playground.mongodb.js +++ b/scripts/playground.mongodb.js @@ -1,14 +1,28 @@ -// MongoDB Playground -// Use Ctrl+Space inside a snippet or a string literal to trigger completions. - -// The current database to use. -use('enrutaviaporte'); - -// Create a new document in the collection. -db.getCollection('notifications').insertOne({ - "owner" : ObjectId("65eeadb8ed616b897ca4c4cd"), - "title":"Notification title", - "description":"Notification description", - "tag":"category", - "deleted":false -}); +/* global use, db */ +// MongoDB Playground +// Use Ctrl+Space inside a snippet or a string literal to trigger completions. + +// The current database to use. +use('enrutaviaporte'); + +// Search for documents in the current collection. +db.getCollection('loads') + .find( + { + _id : ObjectId('66c151a1299e3cfe8fa4a1dc') + }, + { + /* + * Projection + * _id: 0, // exclude _id + * fieldA: 1 // include field + */ + } + ) + .sort({ + /* + * fieldA: 1 // ascending + * fieldB: -1 // descending + */ + }); + diff --git a/v1/src/lib/Handlers/Events/Proposals/index.js b/v1/src/lib/Handlers/Events/Proposals/index.js new file mode 100644 index 0000000..12a67ab --- /dev/null +++ b/v1/src/lib/Handlers/Events/Proposals/index.js @@ -0,0 +1,90 @@ +'user strict'; +const { getModel } = require( '../../../Models' ); + +const onAcceptedEvents = require('./onAccepted'); + +const branchesModel = getModel('branches') +const vehiclesModel = getModel('vehicles'); +const proposalsModel = getModel('proposals'); +const loadsModel = getModel('loads'); +const usersModel = getModel('users'); +const companiesModel = getModel('companies'); +const notificationsModel = getModel('notifications'); +const productsModel = getModel('products'); + +/** + * When the proposal is created then the load owner should be notified + */ +async function onProposalCreate( proposal_id ){ + const proposal = await proposalsModel.findById( proposal_id ); + const load = await loadsModel.findById( proposal.load ); + const user = await usersModel.findById( load.posted_by ); + + const notification = new notificationsModel({ + "owner": user.id, + "title": "New proposal", + "description": `${load.shipment_code}`, + "tag":"new_proposal", + "deleted":false + }); + + await notification.save(); +} + +/** + * When a proposal is removed from the load, it is considered as rejected + */ +async function onProposalRejected( proposal_id ){ + const proposal = await proposalsModel.findById( proposal_id ); + + /// Update Proposal: + /// Remove shipper + await proposalsModel.findByIdAndUpdate( id , { + shipper : null + } ); + + /// Update Load: + /// Remove carrier, driver and vehicle + await loadsModel.findByIdAndUpdate( proposal.load, { + carrier : null, + driver : null, + vehicle : null, + bidder : null + } ); +} + +/** + * When a proposal is accepted by the shipper + */ +async function onProposalAccepted( proposal_id ){ + const proposal = await proposalsModel.findById( proposal_id ); + const shipper_user = await usersModel.findById( proposal.accepted_by ); + const shipper = await companiesModel.findById( shipper_user.company ); + const vehicle = await vehiclesModel.findById( proposal.vehicle ); + const load = await loadsModel.findById( proposal.load ); + + /// Update Proposal: + /// Adding shipper to proposal + await proposalsModel.findByIdAndUpdate( proposal_id , { + shipper : shipper.id + } ); + + /// Update Load: + /// Add carrier, driver and vehicle + await loadsModel.findByIdAndUpdate( proposal.load, { + carrier : proposal.carrier, + driver : vehicle.driver, + vehicle : proposal.vehicle, + bidder : proposal.bidder // Who created the proposal (carrier user) + } ); + + const carrier = await companiesModel.findById( load.carrier ); + const product = await productsModel.findById( load.product ); + const driver = await usersModel.findById( load.driver ); + const warehouse = await branchesModel.findById( load.shipper_warehouse ); + + await onAcceptedEvents.sendNotification( proposal, load ); + await onAcceptedEvents.sendWarehouseEmail( warehouse, load, carrier, product, vehicle, driver ); +} + +module.exports = { onProposalCreate, onProposalRejected, onProposalAccepted }; diff --git a/v1/src/lib/Handlers/Events/Proposals/onAccepted.js b/v1/src/lib/Handlers/Events/Proposals/onAccepted.js new file mode 100644 index 0000000..f75f580 --- /dev/null +++ b/v1/src/lib/Handlers/Events/Proposals/onAccepted.js @@ -0,0 +1,29 @@ +'user strict'; +const { getModel } = require( '../../../Models' ); +const warehouseEvents = require('../Warehouse'); +const notificationsModel = getModel('notifications'); + +/** + * Send a platform notification to the + * @param {*} proposal + * @param {*} shipper + * @param {*} vehicle + * @param {*} load + */ +async function sendNotification( proposal, load ){ + const notification = new notificationsModel({ + "owner": proposal.bidder, + "title": `Your proposal has been accepted!`, + "description": `${load.shipment_code}`, + "tag":"accepted_proposal", + "deleted":false + }); + + await notification.save(); +} + +async function sendWarehouseEmail( warehouse, load, carrier, product, vehicle, driver ){ + await warehouseEvents.onProposalAccepted( warehouse, load, carrier, product, vehicle, driver ); +} + +module.exports = { sendNotification, sendWarehouseEmail }; diff --git a/v1/src/lib/Handlers/Events/Warehouse/index.js b/v1/src/lib/Handlers/Events/Warehouse/index.js new file mode 100644 index 0000000..8392bbe --- /dev/null +++ b/v1/src/lib/Handlers/Events/Warehouse/index.js @@ -0,0 +1,36 @@ +'user strict'; +const { getModel } = require( '../../../Models' ); +const { emailEvent , EMAIL_EVENTS } = require( '../../MailClient' ); + +const usersModel = getModel('users'); + +async function onProposalAccepted( warehouse, load, carrier, product, vehicle, driver ){ + const driver_name = `${driver.first_name} ${driver.last_name}`; + + const list_of_warehouse_responsibles = await usersModel.find( + { + branch: warehouse.id, + job_role: 'warehouse' + } + ); + + for( const entry of list_of_warehouse_responsibles ){ + warehouse_email = entry.email; + emailEvent( + EMAIL_EVENTS.WAREHOUSE_DRIVER_ASSIGNED, + warehouse_email, + { + code : load.shipment_code, + date : new Date( load.est_loading_date ).toLocaleString("es-MX",{year: 'numeric', month: '2-digit', day: '2-digit'}), + company: carrier.company_name, + product: product.name, + plate: vehicle.circulation_serial_number, + truck_type: vehicle.truck_type, + driver: driver_name, + note: load.notes, + } + ); + } +} + +module.exports = { onProposalAccepted }; diff --git a/v1/src/lib/Handlers/MailClient/StandAlone.handler.js b/v1/src/lib/Handlers/MailClient/StandAlone.handler.js index 0a8f230..6c08ec9 100644 --- a/v1/src/lib/Handlers/MailClient/StandAlone.handler.js +++ b/v1/src/lib/Handlers/MailClient/StandAlone.handler.js @@ -88,4 +88,11 @@ async function ContactEmail( receiver, content ){ return await sendMailTemplate( receiver, subject, html ); } -module.exports = { AccountVerifyEmail, AccountConfirmed, AccountPwdResetEmail, ContactEmail, StandAloneContactEmail }; +async function WarehouseDriverAssignedNotification( receiver, content ){ + const subject = "[ETA] Warehouse Notification"; + const { code, date, company, product, plate, truck_type, driver, note } = content; + const html = warehouseNotificationTemplate( code, date, company, product, plate, truck_type, driver, note ); + return await sendMailTemplate( receiver, subject, html ); +} + +module.exports = { AccountVerifyEmail, AccountConfirmed, AccountPwdResetEmail, ContactEmail, StandAloneContactEmail, WarehouseDriverAssignedNotification }; diff --git a/v1/src/lib/Handlers/MailClient/index.js b/v1/src/lib/Handlers/MailClient/index.js index 765f9e1..b9637e9 100644 --- a/v1/src/lib/Handlers/MailClient/index.js +++ b/v1/src/lib/Handlers/MailClient/index.js @@ -1,11 +1,12 @@ 'user strict'; -const { AccountVerifyEmail, AccountConfirmed, AccountPwdResetEmail, ContactEmail, StandAloneContactEmail } = require('./StandAlone.handler'); +const { AccountVerifyEmail, AccountConfirmed, AccountPwdResetEmail, ContactEmail, StandAloneContactEmail, WarehouseDriverAssignedNotification } = require('./StandAlone.handler'); const EMAIL_EVENTS={ ACCOUNT_VERIFY:1, ACCOUNT_CONFIRMED:2, ACCOUNT_PWD_RESET:3, CONTACT_EMAIL:4, + WAREHOUSE_DRIVER_ASSIGNED:5, } /** @@ -37,6 +38,11 @@ async function emailEvent( eventId, receiver , content ){ return await ContactEmail( receiver, content ); } break; + case EMAIL_EVENTS.WAREHOUSE_DRIVER_ASSIGNED: + { + return await WarehouseDriverAssignedNotification( receiver, content ); + } + break; default: { throw new Error(`Email event not defined ${eventId}`); diff --git a/v1/src/lib/Handlers/Proposals.handler.js b/v1/src/lib/Handlers/Proposals.handler.js index b4ddcf3..00ce276 100644 --- a/v1/src/lib/Handlers/Proposals.handler.js +++ b/v1/src/lib/Handlers/Proposals.handler.js @@ -1,7 +1,8 @@ 'user strict'; const { getModel } = require( '../Models' ); -const vehiclesModel = require('../Models/vehicles.model'); +const ProposalsEvents = require( './Events/Proposals' ); +const vehiclesModel = getModel('vehicles'); const proposalsModel = getModel('proposals'); const loadsModel = getModel('loads'); const usersModel = getModel('users'); @@ -16,19 +17,8 @@ const notificationsModel = getModel('notifications'); * @returns */ async function onPostEvent( id , newProposalData ){ - const proposal = await proposalsModel.findById( id ); - const load = await loadsModel.findById( proposal.load ); - const user = await usersModel.findById( load.posted_by ); - - const notification = new notificationsModel({ - "owner": user.id, - "title": "New proposal", - "description": `${load.shipment_code}`, - "tag":"new_proposal", - "deleted":false - }); - - await notification.save(); + /// When a post event happens it is assumed that a proposal is created + ProposalsEvents.onProposalCreate( id ); } /** @@ -39,51 +29,10 @@ async function onPostEvent( id , newProposalData ){ * @returns */ async function onPatchEvent( id , newProposalData ){ - const proposal = await proposalsModel.findById( id ); if( !newProposalData.is_accepted ){ - /// Update Proposal: - /// Remove shipper - await proposalsModel.findByIdAndUpdate( id , { - shipper : null - } ); - - /// Update Load: - /// Remove carrier, driver and vehicle - await loadsModel.findByIdAndUpdate( proposal.load, { - carrier : null, - driver : null, - vehicle : null, - bidder : null - } ); + ProposalsEvents.onProposalRejected( id ); }else{ - const shipper_user = await usersModel.findById( proposal.accepted_by ); - const shipper = await companiesModel.findById( shipper_user.company ); - const vehicle = await vehiclesModel.findById( proposal.vehicle ); - const load = await loadsModel.findById( proposal.load ); - /// Update Proposal: - /// Adding shipper to proposal - await proposalsModel.findByIdAndUpdate( id , { - shipper : shipper.id - } ); - - /// Update Load: - /// Add carrier, driver and vehicle - await loadsModel.findByIdAndUpdate( proposal.load, { - carrier : proposal.carrier, - driver : vehicle.driver, - vehicle : proposal.vehicle, - bidder : proposal.bidder - } ); - - const notification = new notificationsModel({ - "owner": proposal.bidder, - "title": `Your proposal has been accepted!`, - "description": `${load.shipment_code}`, - "tag":"accepted_proposal", - "deleted":false - }); - - await notification.save(); + ProposalsEvents.onProposalAccepted( id ); } } diff --git a/v1/src/lib/Models/loads.model.js b/v1/src/lib/Models/loads.model.js index bcf6265..3daf9a4 100644 --- a/v1/src/lib/Models/loads.model.js +++ b/v1/src/lib/Models/loads.model.js @@ -39,7 +39,7 @@ const schema = new Schema({ driver: { type: Schema.Types.ObjectId, ref: 'users' }, posted_by: { type: Schema.Types.ObjectId, ref: 'users' }, // shipper posted_by_name: { type: String }, // search purpose - bidder: { type: Schema.Types.ObjectId, ref: 'users' }, + bidder: { type: Schema.Types.ObjectId, ref: 'users' }, // who sent the proposal (carrier user) shipper_warehouse : { type: Schema.Types.ObjectId, ref: 'branches' }, diff --git a/v1/src/lib/Models/proposals.model.js b/v1/src/lib/Models/proposals.model.js index 9099638..507d479 100644 --- a/v1/src/lib/Models/proposals.model.js +++ b/v1/src/lib/Models/proposals.model.js @@ -7,11 +7,11 @@ const schema = new Schema({ carrier: { type: Schema.Types.ObjectId, ref: 'companies' }, // who transport the load vehicle: { type: Schema.Types.ObjectId, ref: 'vehicles' }, - bidder: { type: Schema.Types.ObjectId, ref: 'users' }, + bidder: { type: Schema.Types.ObjectId, ref: 'users' }, // who sends the proposal (proposal author, carrier) comment: { type: String }, - accepted_by: { type: Schema.Types.ObjectId, ref: 'users' }, + accepted_by: { type: Schema.Types.ObjectId, ref: 'users' }, // who accepts the proposal (shipper) accepted_date: { type: Date }, is_withdrawn: { type: Boolean, default: false },