diff --git a/v1/README.md b/v1/README.md index 36975dc..5290724 100644 --- a/v1/README.md +++ b/v1/README.md @@ -377,6 +377,8 @@ This endpoint is part of /loads endpoint - shipper_warehouse : id of a company branch - est_loading_date[gte] : Date greater than. - est_loading_date[lte] : Date less than. + - est_unloading_date[gte] : Date greater than. + - est_unloading_date[lte] : Date less than. - company_name[$regex] : Regex string to find company_name - company_name[$options] : Regex options from MongoDB filter description - $sort[ field ] : -1/1 ; Sort result by field name @@ -485,7 +487,11 @@ __This endpoint is only valid for carriers.__ ## Observers endpoints -### observers/account/ +### Public + +The following endpoints doesn't require a JWT authorization + +#### observers/account/ The full endpoint is `observers/account/`, and serves for the account credentials management, the same way it works for the common users at the endpoint `/public/account`, by the process of creating an OTP when requesting a new user or recovering the account password. @@ -496,3 +502,34 @@ The full endpoint is `observers/account/`, and serves for the account credential - `POST /client/recover` or `POST /warehouse/recover`: Requests an OTP recover the account password. - `PATCH /client/recover` or `PATCH /warehouse/recover`: Confirms the new password OTP. +### Private + +The following endpoints require a JWT authorization + +#### observers/loads/ + +##### /find + +- `/warehouse/find`: Warehouse find loads +- `/client/find`: Client find loads + +- `GET /warehouse/find` or `GET /client/find` : Find a list of elements with any of the following fields: + + - company: Id of the shipper company + - carrier: Id of the carrier company + - status: Status of the load + - posted_by: Id of the user posting the load + - load_status + - published_date + - loaded_date + - transit_date + - categories + - product + - shipment_code: ETA code + - origin_warehouse: id of the warehouse + - destination_warehouse: id of the warehouse + - est_loading_date[gte] : Date greater than. + - est_loading_date[lte] : Date less than. + - est_unloading_date[gte] : Date greater than. + - est_unloading_date[lte] : Date less than. + - $sort[ field ] : -1/1 ; Sort result by field name diff --git a/v1/src/apps/observers/private/index.js b/v1/src/apps/observers/private/index.js index 04a4d8d..7862881 100644 --- a/v1/src/apps/observers/private/index.js +++ b/v1/src/apps/observers/private/index.js @@ -4,19 +4,11 @@ const router = require('express').Router(); const jwtValidator = require( '../../../lib/jwtValidator.js' ); const context = require( './lib/context' ); -// const loads = require('./loads/routes.js'); +const loads = require('./loads/routes.js'); router.use( jwtValidator.middleware ); router.use( context.middleware ); -router.use( (req,res) => { - console.log( req.JWT ); - console.log( req.context ); - return res.status(500).send( { - error: "Not implemented yet" - } ); -} ) - -// router.use('/loads', loads); +router.use('/loads', loads); module.exports = router; diff --git a/v1/src/apps/observers/private/loads/routes.js b/v1/src/apps/observers/private/loads/routes.js index 038099a..ac54bcb 100644 --- a/v1/src/apps/observers/private/loads/routes.js +++ b/v1/src/apps/observers/private/loads/routes.js @@ -2,12 +2,22 @@ const router = require('express').Router(); const services= require('./services.js'); -router.get('/find', services.findList); -router.get('/calendar', services.findCalendarList); -router.post('/new', services.postLoad); +router.use('/client', (req,res,next) => { + const { user_type } = req.context; + if( user_type === "client" ){ + return next(); + } + return res.status(401).send({error:"Unauthorized",code:401}); +}); +router.get('/client/find', services.Client_findList); -router.patch('/:id', services.patchLoad); -router.delete('/:id', services.deleteLoad); -router.get('/:id', services.getById); +router.use('/warehouse', (req,res,next) => { + const { user_type } = req.context; + if( user_type === "warehouse" ){ + return next(); + } + return res.status(401).send({error:"Unauthorized",code:401}); +}); +router.get('/warehouse/find', services.Warehouse_findList); module.exports = router; diff --git a/v1/src/apps/observers/private/loads/services.js b/v1/src/apps/observers/private/loads/services.js index 809bce3..2e8f080 100644 --- a/v1/src/apps/observers/private/loads/services.js +++ b/v1/src/apps/observers/private/loads/services.js @@ -1,11 +1,10 @@ "use strict"; -const { getModel } = require( '../../../lib/Models' ); -const { getPagination, genKey } = require( '../../../lib/Misc.js' ); -const { GenericHandler } = require( '../../../lib/Handlers/Generic.handler.js' ); -const Model = getModel('loads'); -const CompanyModel = getModel('companies'); -const ProposalsModel = getModel('proposals'); -const branchesModel = getModel('branches'); +const { getModel } = require( '../../../../lib/Models' ); +const { getPagination } = require( '../../../../lib/Misc.js' ); +const { GenericHandler } = require( '../../../../lib/Handlers/Generic.handler.js' ); + +const BranchesModel = getModel('branches'); +const LoadsModel = getModel('loads'); const carrier_projection = [ 'company_name', @@ -26,24 +25,26 @@ const vehicle_projection = [ ]; const user_projection = ['first_name','last_name','middle_name']; const populate_list = [ + {path:'company',select: carrier_projection }, 'product', - 'company', 'categories', - 'shipper_warehouse', + 'origin_warehouse', + 'destination_warehouse', {path:'carrier',select: carrier_projection }, {path:'vehicle',select: vehicle_projection }, {path:'driver',select: user_projection }, {path:'bidder',select: user_projection }, + {path:'posted_by',select: user_projection } ]; -const generic = new GenericHandler( Model, null, populate_list ); + +const loads_generic_handler = new GenericHandler( LoadsModel, null, populate_list ); function getAndFilterList( query ){ const filter_list = []; + const { company, carrier, - vehicle, - driver, status, posted_by, posted_by_name, @@ -54,15 +55,14 @@ function getAndFilterList( query ){ categories, product, shipment_code, - shipper_warehouse, + origin_warehouse, + destination_warehouse, est_loading_date, - alert_list, + est_unloading_date } = query; if( company ){ filter_list.push( { company } ); } if( carrier ){ filter_list.push( { carrier } ); } - if( vehicle ){ filter_list.push( { vehicle } ); } - if( driver ){ filter_list.push( { driver } ); } if( status ){ filter_list.push( { status } ); } if( posted_by ) { filter_list.push({ posted_by }); } if( posted_by_name ) { filter_list.push({ posted_by_name }); } @@ -73,8 +73,9 @@ function getAndFilterList( query ){ if( categories ) { filter_list.push({ categories }); } if( product ) { filter_list.push({ product }); } if( shipment_code ) { filter_list.push({ shipment_code }); } - if( shipper_warehouse ) { filter_list.push({ shipper_warehouse }); } - if( alert_list ) { filter_list.push({ alert_list }); } + if( origin_warehouse ) { filter_list.push({ origin_warehouse }); } + if( destination_warehouse ) { filter_list.push({ destination_warehouse }); } + if( est_loading_date ) { if( (est_loading_date.gte == undefined) || (est_loading_date.gte == null) ){ throw "est_loading_date[gte] is required"; @@ -90,121 +91,70 @@ function getAndFilterList( query ){ }); } + if( est_unloading_date ) { + if( (est_unloading_date.gte == undefined) || (est_unloading_date.gte == null) ){ + throw "est_unloading_date[gte] is required"; + } + if( (est_unloading_date.lte == undefined) || (est_unloading_date.lte == null) ){ + throw "est_unloading_date[lte] is required"; + } + filter_list.push({ + "est_unloading_date" : { + $gte : new Date( est_unloading_date["gte"] ), + $lte : new Date( est_unloading_date["lte"] ) + } + }); + } + if( filter_list.length == 0 ){ return null; } + return filter_list; } -async function findLoads( query ){ - const { $sort, company_name } = query; +function valid_user_type( user_type ){ + return ( (user_type == "client") || (user_type == "warehouse") ); +} + +async function findList( user_type, email, query ) { + if( !valid_user_type( user_type ) ){ + throw "Invalid user_type"; + } + + const { $sort } = query; const { page, elements } = getPagination( query ); const andFilterList = getAndFilterList( query ) || []; let filter; - if( company_name ){ - /* Populate list of company ids with match on the company_name */ - const company_list = await CompanyModel.find( { company_name }, [ "id" ] ); - const or_company_list = [] - company_list.forEach( (item) =>{ - or_company_list.push({"company" : item.id}); - }) - andFilterList.push({ - $or : or_company_list - }); - } - - if( andFilterList.length > 0 ){ - filter = { $and : andFilterList }; + if( user_type == "client" ){ + andFilterList.push({ "alert_list" : email }); }else{ - filter = null; - } - - const { total , limit, skip, data } = await generic.getList( page , elements, filter, null, $sort ); - - const load_list = data; - - for(let i=0; i{ + or_list.push({"origin_warehouse" : item.id}); + or_list.push({"destination_warehouse" : item.id}); + }) + if( or_list.length > 0 ){ + andFilterList.push({ + $or : or_list + }); + }else{ + /// Add an invalid id to avoid selecting more items than needed! + andFilterList.push({ + $or : [ { + "origin_warehouse" : "invalid_id", + "destination_warehouse" : "invalid_id" + } ] + }); } - ] - - if( !(global) || (global == 0) ){ - andFilterList.push( { - $or : [ - {"bidder" : userId}, - {"posted_by" : userId}, - ] - } ); } - if( load_status ){ - andFilterList.push( { load_status } ) - } + filter = { $and : andFilterList }; - if( shipper_warehouse ){ - andFilterList.push( { shipper_warehouse } ) - } - - const filter = { - $and : andFilterList, - }; - - const { - total, - limit, - skip, - query : model_query, - } = await generic.getListQuery( page , elements, filter , select ); - - if( $sort ){ - model_query.sort( $sort ); - } - - const data = await generic.populateQuery( model_query ); + const { total , limit, skip, data } = await loads_generic_handler.getList( page , elements, filter, { alert_list:0 }, $sort ); return { total, @@ -214,122 +164,27 @@ async function findCalendarLoads( userId, companyId, query ){ }; } -async function findElementById( elementId ){ - let retVal = await Model.findById( elementId ).populate( populate_list ); - if( retVal ){ - retVal = retVal.toObject(); - const no_of_proposals = await ProposalsModel.count({ load : elementId }); - retVal.no_of_proposals = no_of_proposals; - }else{ - retVal = {}; - } - return retVal; -} - -const findCalendarList = async(req, res) => { +const Client_findList = async(req, res) => { try{ + const { email, user_type } = req.context; const query = req.query || {}; - const companyId = req.context.companyId; - const userId = req.context.userId; - const retVal = await findCalendarLoads( userId, companyId, query ); - res.send( retVal ); + res.send( await findList( user_type, email, query ) ); }catch(error){ console.error( error ); return res.status( 500 ).send({ error }); } -} +}; -const findList = async(req, res) => { +const Warehouse_findList = async(req, res) => { try{ + const { email, user_type } = req.context; const query = req.query || {}; - const retVal = await findLoads( query ); - res.send( retVal ); + console.log( email, user_type ); + res.send( await findList( user_type, email, query ) ); }catch(error){ console.error( error ); return res.status( 500 ).send({ error }); } }; -const getById = async(req, res) => { - try{ - const elementId = req.params.id; - res.send( await findElementById( elementId ) ); - }catch(error){ - console.error( error ); - return res.status( 500 ).send({ error }); - } -}; - -const patchLoad = async(req, res) => { - try{ - const elementId = req.params.id; - const permissions = req.context.permissions; - const data = req.body; - const load = await findElementById( elementId ); - if( !load ){ - throw "You can't modify this load"; - } - if( !data ){ - throw "load data not sent"; - } - await Model.findByIdAndUpdate( elementId , data ); - return res.send( await Model.findById( elementId ) ); - }catch(error){ - console.error( error ); - return res.status( 500 ).send({ error }); - } -}; - -const postLoad = async(req, res) => { - try{ - const companyId = req.context.companyId; - const userId = req.context.userId; - const user_name = req.context.user.first_name; - const permissions = req.context.permissions; - const data = req.body; - if( !data ){ - throw "Load data not sent"; - } - if(permissions !== "role_shipper" ){ - throw "You can't create loads"; - } - data.company = companyId; - data.posted_by = userId; - data.name = user_name; - const load = new Model( data ); - await load.save(); - - const id = "" + load._id; - const shipment_code = "ETA-" + genKey( 6, id ); - await Model.findByIdAndUpdate( id , { - shipment_code - }); - load.shipment_code = shipment_code; - return res.send( load ); - }catch(error){ - console.error( error ); - return res.status( 500 ).send({ error }); - } -}; - -const deleteLoad = async(req, res) => { - try{ - const companyId = req.context.companyId; - const elementId = req.params.id; - const permissions = req.context.permissions; - const load = await findElementById( elementId , companyId ); - if(!load){ - throw "You can't delete this load"; - } - if(permissions !== "role_shipper" ){ - throw "You can't delete loads"; - } - await Model.findByIdAndDelete( elementId ); - return res.send(load); - }catch(error){ - console.error( error ); - return res.status( 500 ).send({ error }); - } -}; - -module.exports = { findCalendarList, findList, getById, patchLoad, postLoad, deleteLoad }; +module.exports = { Client_findList, Warehouse_findList }; diff --git a/v1/src/apps/private/loads/services.js b/v1/src/apps/private/loads/services.js index bfa878c..4260763 100644 --- a/v1/src/apps/private/loads/services.js +++ b/v1/src/apps/private/loads/services.js @@ -29,7 +29,8 @@ const populate_list = [ 'product', 'company', 'categories', - 'shipper_warehouse', + 'origin_warehouse', + 'destination_warehouse', {path:'carrier',select: carrier_projection }, {path:'vehicle',select: vehicle_projection }, {path:'driver',select: user_projection }, @@ -54,8 +55,10 @@ function getAndFilterList( query ){ categories, product, shipment_code, - shipper_warehouse, + origin_warehouse, + destination_warehouse, est_loading_date, + est_unloading_date, alert_list, } = query; @@ -73,7 +76,8 @@ function getAndFilterList( query ){ if( categories ) { filter_list.push({ categories }); } if( product ) { filter_list.push({ product }); } if( shipment_code ) { filter_list.push({ shipment_code }); } - if( shipper_warehouse ) { filter_list.push({ shipper_warehouse }); } + if( origin_warehouse ) { filter_list.push({ origin_warehouse }); } + if( destination_warehouse ) { filter_list.push({ destination_warehouse }); } if( alert_list ) { filter_list.push({ alert_list }); } if( est_loading_date ) { if( (est_loading_date.gte == undefined) || (est_loading_date.gte == null) ){ @@ -90,6 +94,21 @@ function getAndFilterList( query ){ }); } + if( est_unloading_date ) { + if( (est_unloading_date.gte == undefined) || (est_unloading_date.gte == null) ){ + throw "est_unloading_date[gte] is required"; + } + if( (est_unloading_date.lte == undefined) || (est_unloading_date.lte == null) ){ + throw "est_unloading_date[lte] is required"; + } + filter_list.push({ + "est_unloading_date" : { + $gte : new Date( est_unloading_date["gte"] ), + $lte : new Date( est_unloading_date["lte"] ) + } + }); + } + if( filter_list.length == 0 ){ return null; } @@ -147,7 +166,6 @@ async function findCalendarLoads( userId, companyId, query ){ const select = null; const { date, load_status , $sort } = query; const { global } = query; - const { shipper_warehouse } = query; if( ! date ){ throw "Date field is required"; @@ -185,10 +203,6 @@ async function findCalendarLoads( userId, companyId, query ){ andFilterList.push( { load_status } ) } - if( shipper_warehouse ){ - andFilterList.push( { shipper_warehouse } ) - } - const filter = { $and : andFilterList, }; diff --git a/v1/src/lib/Handlers/Events/Proposals/index.js b/v1/src/lib/Handlers/Events/Proposals/index.js index ef04373..8aae3b4 100644 --- a/v1/src/lib/Handlers/Events/Proposals/index.js +++ b/v1/src/lib/Handlers/Events/Proposals/index.js @@ -83,17 +83,7 @@ async function onProposalAccepted( userId, proposalId ){ } ); const load = await loadsModel.findById( proposal.load ); - 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 ); - - if( warehouse ){ - /// Notify warehouse only if there is any associated to the load/proposal - await onAcceptedEvents.sendWarehouseEmail( warehouse, load, carrier, product, vehicle, driver ); - } } module.exports = { onProposalCreate, onProposalRejected, onProposalAccepted }; diff --git a/v1/src/lib/Models/loads.model.js b/v1/src/lib/Models/loads.model.js index 174c303..c20ebb3 100644 --- a/v1/src/lib/Models/loads.model.js +++ b/v1/src/lib/Models/loads.model.js @@ -43,7 +43,8 @@ const schema = new Schema({ alert_list: [{ type: String, lowercase: true }], - shipper_warehouse : { type: Schema.Types.ObjectId, ref: 'branches' }, + origin_warehouse : { type: Schema.Types.ObjectId, ref: 'branches' }, + destination_warehouse : { type: Schema.Types.ObjectId, ref: 'branches' }, origin: address, origin_geo: {