feat: Split v1 and v2 apis

This commit is contained in:
Josepablo C
2024-08-05 15:33:23 -06:00
parent 49ee7d7b5a
commit c3f0b08cb7
149 changed files with 284 additions and 33 deletions

View File

@@ -0,0 +1,7 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.post('/register', services.register);
module.exports = router;

View File

@@ -0,0 +1,15 @@
"use strict";
const { ROOT_PATH, HANDLERS_PATH } = process.env;
const { complete_register } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Account` );
const register = async( req, res ) => {
try{
const result = await complete_register( req.context.userId , req.body );
return res.send( result );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
module.exports = { register };

View File

@@ -0,0 +1,12 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/new', services.postBranch);
router.patch('/:id', services.patchBranch);
router.delete('/:id', services.deleteBranch);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,147 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getModel } = require( `${ROOT_PATH}/${MODELS_PATH}` );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = getModel('branches');
const populate_list = ['company', 'categories'];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const { categories, branch_name, phone, city, state, truck_type } = query;
if( categories ) { filter_list.push({ categories }); }
if( branch_name ) { filter_list.push({ branch_name }); }
if( phone ) { filter_list.push({ phone }); }
if( city ) { filter_list.push({ city }); }
if( state ) { filter_list.push({ state }); }
if( truck_type ) { filter_list.push({ truck_type }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findElements( companyId , query ){
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query );
let filter;
if( andFilterList ){
andFilterList.push({ company : companyId });
filter = { $and : andFilterList };
}else{
filter = { company : companyId };
}
const { total , limit, skip, data } = await generic.getList( page , elements, filter );
const list_elements = data;
// for(let i=0; i<list_elements.length; i++){
// const item = list_elements[i].toObject();
// if (item.categories) {
// let categories = item.categories.map((c) => c.name);
// item._categories = categories.join(", ");
// }
// if (item.truck_type) {
// item._truck_types = item.truck_type.join(", ");
// }
// list_elements[i] = item;
// }
return {
total,
limit,
skip,
data:list_elements
};
}
async function findElementById( elementId , companyId ){
const filter = {
$and : [
{ _id : elementId },
{ company : companyId }
]
};
let retVal = await Model.findOne( filter ).populate( populate_list ) || {};
return retVal;
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const companyId = req.context.companyId;
const retVal = await findElements( companyId , query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const getById = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
res.send( await findElementById( elementId , companyId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const patchBranch = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
const data = req.body;
const branch = await findElementById( elementId , companyId );
if( !branch ){
throw "You can't modify this branch";
}
if( !data ){
throw "load data not sent";
}
data.company = companyId;
await Model.findByIdAndUpdate( elementId , data );
return res.send( await Model.findById( elementId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const postBranch = async(req, res) => {
try{
const companyId = req.context.companyId;
const data = req.body;
if( !data ){
throw "Branch data not sent";
}
data.company = companyId;
const branch = new Model( data );
await branch.save();
return res.send( branch );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const deleteBranch = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
const element = await findElementById( elementId , companyId );
if(!element){
throw "You can't delete this branch";
}
await Model.findByIdAndDelete( elementId );
return res.send(element);
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { findList, getById, patchBranch, postBranch, deleteBranch };

View File

@@ -0,0 +1,12 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/new', services.postBudget);
router.patch('/:id', services.patchBudget);
router.delete('/:id', services.deleteBudget);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,178 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getModel } = require( '../../../lib/Models' );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = getModel('budgets');
const populate_list = ['company'];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const {
client,
material,
origin,
destination,
truck_type,
num_tons,
price_per_ton,
tonnage,
pickup_distance,
delivery_distance,
warehouse_distance,
total_km_travel,
cost_per_liter,
fuel_price_per_liter,
other_fuel_expenses,
total_fuel_consumed,
total_cost_fuel,
driver_salary,
accomadation_allowance,
other_administrative_expenses,
total_before_tax,
total_utility_per_km,
total_profit,
profit_percentage,
total_administrative_expenses,
} = query;
if( client ) { filter_list.push({ client }); }
if( material ) { filter_list.push({ material }); }
if( origin ) { filter_list.push({ origin }); }
if( destination ) { filter_list.push({ destination }); }
if( truck_type ) { filter_list.push({ truck_type }); }
if( num_tons ) { filter_list.push({ num_tons }); }
if( price_per_ton ) { filter_list.push({ price_per_ton }); }
if( tonnage ) { filter_list.push({ tonnage }); }
if( pickup_distance ) { filter_list.push({ pickup_distance }); }
if( delivery_distance ) { filter_list.push({ delivery_distance }); }
if( warehouse_distance ) { filter_list.push({ warehouse_distance }); }
if( total_km_travel ) { filter_list.push({ total_km_travel }); }
if( cost_per_liter ) { filter_list.push({ cost_per_liter }); }
if( fuel_price_per_liter ) { filter_list.push({ fuel_price_per_liter }); }
if( other_fuel_expenses ) { filter_list.push({ other_fuel_expenses }); }
if( total_fuel_consumed ) { filter_list.push({ total_fuel_consumed }); }
if( total_cost_fuel ) { filter_list.push({ total_cost_fuel }); }
if( driver_salary ) { filter_list.push({ driver_salary }); }
if( accomadation_allowance ) { filter_list.push({ accomadation_allowance }); }
if( other_administrative_expenses ) { filter_list.push({ other_administrative_expenses }); }
if( total_before_tax ) { filter_list.push({ total_before_tax }); }
if( total_utility_per_km ) { filter_list.push({ total_utility_per_km }); }
if( total_profit ) { filter_list.push({ total_profit }); }
if( profit_percentage ) { filter_list.push({ profit_percentage }); }
if( total_administrative_expenses ) { filter_list.push({ total_administrative_expenses }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findElements( companyId , query ){
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query );
let filter;
if( andFilterList ){
andFilterList.push({ company : companyId });
filter = { $and : andFilterList };
}else{
filter = { company : companyId };
}
const { total , limit, skip, data } = await generic.getList( page , elements, filter );
return {
total,
limit,
skip,
data:data
};
}
async function findElementById( elementId , companyId ){
const filter = {
$and : [
{ _id : elementId },
{ company : companyId }
]
};
let retVal = await Model.findOne( filter ).populate( populate_list ) || {};
return retVal;
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const companyId = req.context.companyId;
const retVal = await findElements( companyId , query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const getById = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
res.send( await findElementById( elementId , companyId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const patchBudget = async(req, res) => {
try{
const elementId = req.params.id;
const budget = await Model.findById( elementId );
const data = req.body;
if( !budget ){
throw "You can't modify this budget";
}
if( !data ){
throw "budget 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 postBudget = async(req, res) => {
try{
const companyId = req.context.companyId;
const data = req.body;
if( !data ){
throw "budget data not sent";
}
data.company = companyId;
const budget = new Model( data );
await budget.save();
return res.send( budget );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const deleteBudget = async(req, res) => {
try{
const elementId = req.params.id;
const budget = await Model.findById( elementId );
if(!budget){
throw "You can't delete this budget";
}
await Model.findByIdAndDelete( elementId );
return res.send(budget);
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { findList, getById, patchBudget, postBudget, deleteBudget };

View File

@@ -0,0 +1,15 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/own', services.getOwnCompany);
router.patch('/own', services.patchOwnCompany);
router.get('/shipper', services.getListShippers);
router.get('/carrier', services.getListCarriers);
router.get('/users/:companyId', services.getUserLists);
router.get('/:id', services.getCompanyById);
module.exports = router;

View File

@@ -0,0 +1,229 @@
"use strict";
const { ROOT_PATH, MODELS_PATH, HANDLERS_PATH, LIB_PATH } = process.env;
const { getModel } = require( `${ROOT_PATH}/${MODELS_PATH}` );
const { GenericHandler } = require( '../../../lib/Handlers/Generic.handler.js' );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const usersModel = getModel('users');
const companiesModel = getModel('companies');
const branchesModel = getModel('branches');
const vehiclesModel = getModel('vehicles');
const loadsModel = getModel('loads');
const productCategoriesModel = getModel('product_categories');
const populate_select = {
categories:"-_id name",
};
const generic = new GenericHandler( companiesModel, null, null , populate_select );
const user_generic = new GenericHandler( usersModel );
function join_field_list( obj_with_fields , list_of_fields )
{
for(let field_idx=0; field_idx < list_of_fields.length; field_idx++){
const field_name = list_of_fields[ field_idx ];
const new_field_name = "_" + list_of_fields[ field_idx ];
if( obj_with_fields[ field_name ] ){
obj_with_fields[ new_field_name ] = obj_with_fields[field_name].join(", ");
}
}
return obj_with_fields;
}
function getAndFilterList( query ){
const filter_list = [];
const { company_type, company_name, truck_type, categories, company_state, company_city } = query;
if( company_name ){ filter_list.push( { company_name } ); }
if( company_type ){ filter_list.push( { company_type } ); }
if( company_state ){ filter_list.push( { company_state } ); }
if( company_city ){ filter_list.push( { company_city } ); }
if( truck_type ){ filter_list.push( { truck_type } ); }
if( categories ){ filter_list.push( { categories } ); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function getListByType( type , req ){
const filter = { "company_type" : type , "is_hidden" : false };
const select = [
"rfc",
"company_name",
"company_type",
"company_code",
"company_city",
"company_state",
"createdAt",
"membership",
"categories",
"truck_type",
"company_description"
];
const { $sort } = req.query;
const { elements , page } = getPagination( req.query );
let query_elements;
if( elements >= 100 ){
query_elements = 100;// Never return more than 100 elements
}else{
query_elements = elements;
}
const andFilterList = getAndFilterList( req.query );
if( andFilterList ){
filter.$and = andFilterList;
}
const queryVal = await generic.getList(page , query_elements, filter, select, $sort );
const data_list = queryVal.data;
for(let i=0; i<data_list.length; i++){
data_list[i] = data_list[i].toObject();
data_list[i] = join_field_list( data_list[i] , ["company_city","company_state","truck_type"] );
let categories = data_list[i].categories.map( ( c ) => c.name);
data_list[i]._truck_types = data_list[i]._truck_type;
data_list[i]._categories = categories.join(", ");
/** Remove not requried fields */
delete data_list[i].categories;
delete data_list[i].company_city;
delete data_list[i].company_state;
delete data_list[i].truck_type;
delete data_list[i]._truck_type;
}
const retVal = {
total : queryVal.total,
limit : queryVal.limit,
skip : queryVal.skip,
data : data_list
};
return retVal;
}
async function getOwnCompany( req , res ) {
try{
const companyId = req.context.companyId;
const result = await companiesModel.findById( companyId )
.populate("categories" , "_id name")
.populate("company_city", "-_id name")
.populate("company_state", "-_id name")
.populate("truck_type", "-_id name");
return res.send( result );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
async function patchOwnCompany( req , res ) {
try{
const companyId = req.context.companyId;
const data = req.body;
if( data.company_type ){ delete data.company_type; }
await companiesModel.findByIdAndUpdate( companyId , data );
const result = await companiesModel.findById( companyId );
return res.send( result );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
async function getCompanyById( req , res ) {
try{
const companyId = req.params.id;
const result = await companiesModel.findById( companyId );
return res.send( result );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
async function getListShippers( req , res ) {
try{
const retVal = await getListByType( "Shipper" , req );
res.send( retVal );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
async function getListCarriers( req , res ) {
try{
const retVal = await getListByType( "Carrier" , req );
res.send( retVal );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
const getUserLists = async(req, res) => {
try{
const companyId = req.params.companyId;
const { elements, page } = getPagination( req.query );
let query_elements;
if( elements >= 100 ){
query_elements = 100;// Never return more than 100 elements
}else{
query_elements = elements;
}
const select = [
"first_name",
"middle_name",
"last_name",
"company",
"employe_id",
"phone",
"phone2",
"email",
"categories",
"user_city",
"user_state",
"truck_type"
];
const queryVal = await user_generic.getList(page , query_elements, { company : companyId }, select );
const data_list = queryVal.data;
for(let i=0; i<data_list.length; i++){
data_list[i] = data_list[i].toObject();
let name;
name = ( !data_list[i].first_name )? "" : data_list[i].first_name;
name += ( !data_list[i].middle_name )? "": " " + data_list[i].middle_name;
name += ( !data_list[i].last_name )? "": " " + data_list[i].last_name;
data_list[i].name = name;
data_list[i] = join_field_list( data_list[i] , ["categories","user_city","user_state","truck_type"] );
// let categories = data_list[i].categories.map( ( c ) => c.name);
/** Remove not requried fields */
delete data_list[i].categories;
delete data_list[i].user_city;
delete data_list[i].user_state;
delete data_list[i].truck_type;
}
const retVal = {
total : queryVal.total,
limit : queryVal.limit,
skip : queryVal.skip,
data : data_list
};
return res.status(200).send( retVal );
} catch ( err ){
console.error( err );
return res.status(500).send({ error : "Companies: Internal error" });
}
};
module.exports = {
getOwnCompany,
patchOwnCompany,
getCompanyById,
getListShippers,
getListCarriers,
getUserLists
};

View File

@@ -0,0 +1,45 @@
'use strict';
const { ROOT_PATH , LIB_PATH } = process.env;
/// Router instance
const router = require('express').Router();
const jwtValidator = require( `${ROOT_PATH}/${LIB_PATH}/jwtValidator.js` );
const context = require( './lib/context' );
const account = require('./account/routes.js');
const budgets = require('./budgets/routes.js')
const branches = require('./branches/routes.js');
const companies = require('./companies/routes.js');
const loadAttachments = require('./load-attachments/routes.js');
const loads = require('./loads/routes.js');
const proposals = require('./proposals/routes.js');
const users = require('./users/routes.js');
const vehicles = require('./vehicles/routes.js');
router.use( jwtValidator.middleware );
router.use( context.middleware );
router.use('/account', account);
router.use('/budgets', budgets);
router.use('/branches', branches);
router.use('/companies', companies);
router.use('/load-attachments', loadAttachments );
router.use('/loads', loads);
router.use('/proposals', proposals);
router.use('/users', users);
router.use('/vehicles', vehicles);
/*
router.use('/orders', test);
router.use('/mailer', test);
router.use('/memberships', test);
router.use('/bootresolvers', test);
router.use('/news', test);
router.use('/branches', test);
router.use('/trackings', test);
router.use('/upload', test);
router.use('/calendars', test);
router.use('/dashboard', test);
*/
module.exports = router;

View File

@@ -0,0 +1,23 @@
'use strict';
const { ROOT_PATH, MODELS_PATH } = process.env;
const { getModel } = require( `${ROOT_PATH}/${MODELS_PATH}` );
const usersModel = getModel('users');
async function middleware( req, res, next ){
if( ! req.JWT?.isValid ){
return res.status(401).send({error:"Unauthorized",code:401});
}
const userID = req.JWT.payload.sub;
req.context = {
user : await usersModel.findById( userID , { password : 0 , session_token : 0 , session_token_exp : 0 } ).populate('company')
}
req.context.userId = req.context.user.id;
req.context.companyId = req.context.user.company.id || null;
req.context.job_role = req.context.user.job_role || null;
req.context.permissions = req.context.user.permissions || null;
next();
}
module.exports = {
middleware
};

View File

@@ -0,0 +1,11 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.post('/loading/:id', services.postLoadingAttachment );
router.post('/downloading/:id', services.postDownloadingAttachment );
router.get('/load/:id', services.getLoadAttachmentList );
router.get('/:id', services.getAttachment );
router.get('/', services.getAttachmentList );
module.exports = router;

View File

@@ -0,0 +1,164 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, API_CONFIG } = process.env;
const { getPagination , getPage } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const s3Client = new S3Client({
region : apiConfig.S3.region,
credentials : {
accessKeyId : apiConfig.S3.accessKeyId,
secretAccessKey : apiConfig.S3.secretAccessKey
}
});
const s3Bucket = apiConfig.S3.bucket;
const s3BucketKey = apiConfig.S3.load_attachments_key;
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/load-attachments.model.js` );
const UserModel = require( `${ROOT_PATH}/${MODELS_PATH}/users.model.js` );
const LoadsModel = require( `${ROOT_PATH}/${MODELS_PATH}/loads.model.js` );
async function getAuthorizationFilter( userId ){
const user = await UserModel.findById( userId );
const companyId = user.company.toString();
return {
$or: [
{ company : companyId },
{ carrier : companyId },
]
};
}
const getAttachment = async(req, res) => {
try{
const attachmentId = req.params.id;
const CompanyAccessFilter = await getAuthorizationFilter( req.JWT.payload.sub );
const filter = {
$and : [
{ _id : attachmentId },
CompanyAccessFilter
]
};
const retVal = await Model.findOne( filter ) || {};
res.send( retVal );
}catch( err ){
res.send( {} );
}
};
const getAttachmentList = async(req, res) => {
const filter = await getAuthorizationFilter( req.JWT.payload.sub );
const { page , elements } = getPagination( req.query );
const retVal = await getPage( page, elements, Model, filter );
res.send( retVal );
};
const getLoadAttachmentList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const loadId = req.params.id;
try{
const CompanyAccessFilter = await getAuthorizationFilter( req.JWT.payload.sub );
const filter = {
$and : [
{ load : loadId },
CompanyAccessFilter
]
};
const retVal = await getPage( page, elements, Model, filter );
return res.send( retVal );
}catch( error ){
console.log( error );
return res.send({
total: 0,
limit: elements,
skip: page*elements,
data : []
});
}
};
async function getLoadById( loadId , companyId ){
const filter = {
$and : [
{ _id : loadId },
{
$or: [
{ company : companyId },
{ carrier : companyId },
]
}
]
};
return await LoadsModel.findOne( filter ) || null;
}
async function createLoadAttachment( type , userId , loadId ){
const user = await UserModel.findById( userId );
const companyId = user.company.toString();
const load = await getLoadById( loadId , companyId );
const prevAttachment = (load)? await Model.findOne({ load : loadId , type : type }) : null;
let attachment = null;
if( load && !prevAttachment ){
attachment = new Model({
type : type,
carrier : companyId,
company : load.company,
load : loadId,
author : userId
});
await attachment.save();
}
else if( load && prevAttachment ){
prevAttachment.updatedAt = Date.now();
await prevAttachment.save();
attachment = prevAttachment;
}else{
/**
* load is not valid => I don't have access to this load!
*/
attachment = null;
}
return attachment;
}
async function uploadFile( bucket, key, file , obj_id ){
const params = {
Bucket: bucket,
Key : `${key}/${obj_id}`,
ContentType : file.mimetype,
Body : file.data
};
const s3resp = await s3Client.send( new PutObjectCommand( params ) );
return s3resp;
}
const postLoadingAttachment = async(req, res) => {
const loadId = req.params.id;
const attachment = await createLoadAttachment( "Loading", req.JWT.payload.sub , loadId );
const file = req.files.attachment;
if( attachment && file ){
const s3resp = await uploadFile( s3Bucket, s3BucketKey, file , attachment._id );
res.send( attachment );
}else if( !file ){
res.status(400).send({ error : "attachment file not found" , code: 400 });
}else{
res.status(401).send({error:"Unauthorized",code:401});
}
};
const postDownloadingAttachment = async(req, res) => {
const loadId = req.params.id;
const attachment = await createLoadAttachment( "Downloading", req.JWT.payload.sub , loadId );
const file = req.files.attachment;
if( attachment && file ){
const s3resp = await uploadFile( s3Bucket, s3BucketKey, file , attachment._id );
res.send( attachment );
}else if( !file ){
res.status(400).send({ error : "attachment file not found" , code: 400 });
}else{
res.status(401).send({error:"Unauthorized",code:401});
}
};
module.exports = { getAttachment, getAttachmentList, getLoadAttachmentList, postLoadingAttachment, postDownloadingAttachment };

View File

@@ -0,0 +1,13 @@
'use strict';
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.patch('/:id', services.patchLoad);
router.delete('/:id', services.deleteLoad);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,294 @@
"use strict";
const { ROOT_PATH, LIB_PATH } = process.env;
const { getModel } = require( '../../../lib/Models' );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( '../../../lib/Handlers/Generic.handler.js' );
const Model = getModel('loads');
const CompanyModel = getModel('companies');
const ProposalsModel = getModel('proposals');
const populate_list = ['product', 'company', 'carrier', 'vehicle', 'categories'];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const {
companyId,
carrier,
vehicle,
driver,
status,
posted_by,
posted_by_name,
load_status,
published_date,
loaded_date,
transit_date,
categories,
product,
shipment_code
} = query;
if( companyId ){ filter_list.push( { company : companyId } ); }
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 }); }
if( load_status ) { filter_list.push({ load_status }); }
if( published_date ) { filter_list.push({ published_date }); }
if( loaded_date ) { filter_list.push({ loaded_date }); }
if( transit_date ) { filter_list.push({ transit_date }); }
if( categories ) { filter_list.push({ categories }); }
if( product ) { filter_list.push({ product }); }
if( shipment_code ) { filter_list.push({ shipment_code }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findLoads( query ){
const { $sort, company_name } = 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 };
}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<load_list.length; i++){
const load_id = load_list[ i ].id;
load_list[i] = load_list[i].toObject();
const no_of_proposals = await ProposalsModel.count({ load : load_id });
load_list[i].no_of_proposals = no_of_proposals;
}
return {
total,
limit,
skip,
data : load_list
};
}
async function findCalendarLoads( userId, companyId, query ){
const select = [
"company",
"carrier",
"posted_by",
"bidder",
"status",
"load_status",
"published_date",
"load_status_updated",
"loaded_date",
"transit_date",
"delivered_date",
"createdAt",
"shipment_code",
"est_loading_date",
"est_unloading_date"
];
const { date, load_status , $sort } = query;
const { global } = query;
if( ! date ){
throw "Date field is required";
}
const { page, elements } = getPagination( query );
const orFilterList = [
{"company" : companyId},
{"carrier" : companyId}
]
const andFilterList = [
{
"est_loading_date" : {
$gte : new Date( date["gte"] ),
$lte : new Date( date["lte"] )
}
},
{
$or : orFilterList
}
]
if( !(global) || (global == 0) ){
andFilterList.push( {
$or : [
{"bidder" : userId},
{"posted_by" : userId},
]
} );
}
if( load_status ){
andFilterList.push( { load_status } )
}
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 model_query.exec();
return {
total,
limit,
skip,
data
};
}
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) => {
try{
const query = req.query || {};
const companyId = req.context.companyId;
const userId = req.context.userId;
const retVal = await findCalendarLoads( userId, companyId, query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const retVal = await findLoads( query );
res.send( retVal );
}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-" + id.substring( 0 , 6 );
await Model.findByIdAndUpdate( id , {
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 };

View File

@@ -0,0 +1,12 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/new', services.postProposal);
router.patch('/:id', services.patchProposal);
router.delete('/:id', services.deleteProposal);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,142 @@
"use strict";
const { getModel } = require( '../../../lib/Models' );
const { getPagination } = require( '../../../lib/Misc' );
const { GenericHandler } = require( '../../../lib/Handlers/Generic.handler' );
const { onPatchEvent } = require('../../../lib/Handlers/Proposals.handler');
const Model = getModel('proposals');
const populate_list = [
{ path:'load' , populate : { path : 'categories' } },
{ path:'load' , populate : { path : 'company' } },
'shipper',
'carrier',
'vehicle',
'bidder',
'accepted_by'
];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const { load, categories, branch_name, phone, city, state, truck_type } = query;
if( load ) { filter_list.push({ load }); }
if( categories ) { filter_list.push({ categories }); }
if( branch_name ) { filter_list.push({ branch_name }); }
if( phone ) { filter_list.push({ phone }); }
if( city ) { filter_list.push({ city }); }
if( state ) { filter_list.push({ state }); }
if( truck_type ) { filter_list.push({ truck_type }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findElements( query ){
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query );
let filter;
if( andFilterList ){
filter = { $and : andFilterList };
}else{
filter = null;
}
const { total , limit, skip, data } = await generic.getList( page , elements, filter );
return {
total,
limit,
skip,
data:data
};
}
async function findElementById( elementId , companyId ){
const filter = {
$and : [
{ _id : elementId },
{ $or :[
{ shipper : companyId },
{ carrier : companyId }
]}
]
};
let retVal = await Model.findOne( filter ).populate( populate_list ) || {};
return retVal;
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const retVal = await findElements( query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const getById = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
res.send( await findElementById( elementId , companyId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const patchProposal = async(req, res) => {
try{
const elementId = req.params.id;
const proposal = await Model.findById( elementId );
const data = req.body;
if( !proposal ){
throw "You can't modify this proposal";
}
if( !data ){
throw "proposal data not sent";
}
await Model.findByIdAndUpdate( elementId , data );
await onPatchEvent( elementId , data );
return res.send( await Model.findById( elementId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const postProposal = async(req, res) => {
try{
const data = req.body;
if( !data ){
throw "proposal data not sent";
}
const proposal = new Model( data );
await proposal.save();
return res.send( proposal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const deleteProposal = async(req, res) => {
try{
const elementId = req.params.id;
const proposal = await Model.findById( elementId );
if(!proposal){
throw "You can't delete this proposal";
}
await Model.findByIdAndDelete( elementId );
return res.send(proposal);
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { findList, getById, patchProposal, postProposal, deleteProposal };

View File

@@ -0,0 +1,16 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/member', services.postTeamMemberData);
router.patch('/member/:id', services.patchTeamMemberProfileData);
router.delete('/member/:id', services.deleteTeamMember);
router.get('/profile', services.getProfileData);
router.patch('/profile', services.patchProfileData);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,177 @@
"use strict";
const { ROOT_PATH, HANDLERS_PATH } = process.env;
const { getUserById, findUsers, patchUserData, createUserWithinCompany, deleteUserWithinCompany } = require( "../../../lib/Handlers/Users.handler" );
const findList = async(req, res) => {
try{
const {
total,
limit,
skip,
data
} = await findUsers( req.query );
return res.send({
total,
limit,
skip,
data});
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
};
const getById = async(req, res) => {
try{
const id = req.params.id;
const user = await getUserById( id );
res.send({ user });
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
};
const getProfileData = async(req, res) => {
res.send( req.context.user );
};
const patchProfileData = async(req, res) => {
try{
const data = req.body;
if( (data.email) && (data.email === req.context.user.email ) ){
delete data.email;
}
if( req.body.job_role ){
/// You can't change your own role
delete data.job_role;
}
const user = await patchUserData( req.context.user.id , data );
res.send( user );
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
};
function job_role_change_allowance( change_author_job_role , affected_job_role ){
try{
if( (change_author_job_role !== "owner") && (change_author_job_role !== "manager") ){
return false;
}
if( affected_job_role === "owner" ){
return false;
}
switch( affected_job_role ){
case 'manager':
case 'driver':
case 'staff':
return true;
default:
return false;
}
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
const patchTeamMemberProfileData = async(req, res) => {
try{
const id = req.params.id;
if( id === req.context.userId ){
return await patchProfileData( req, res);
}
const companyId = req.context.companyId;
if( !companyId ){
return res.status(400).send( { error : "Not authorized to modify this user" } );
}
/// If a job_role change is requested, validate with rules.
if( ( req.body.job_role ) &&
( !job_role_change_allowance( req.context.job_role , req.body.job_role ) )
){
return res.status(400).send( { error : "Not authorized to upgrade the role as requested" } );
}
if( ( req.body.job_role ) && ( req.body.job_role === "driver" ) && (req.context.permissions !== "role_carrier" ) ){
return res.status(400).send( { error : "Your company can not create drivers" } );
}
if( (req.context.job_role !== "owner") && (req.context.job_role !== "manager") ){
/// Only an owner or manager can modify a team member.
return res.status(400).send( { error : "Your role does not allow to modify this user" } );
}
/// No one can modify an "owner".
const teamMember = await getUserById( id , { company : companyId , job_role : { $ne: "owner" } } );
if( !teamMember ){
return res.status(400).send( { error : "You can't modify users outside of your company" } );
}
/// Apply change to user.
const user_patch_result = await patchUserData( id , req.body );
return res.send( user_patch_result );
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
};
const postTeamMemberData = async(req, res) => {
try{
const companyId = req.context.companyId;
if( !companyId ){
return res.status(400).send( { error : "Not authorized to create users" } );
}
if( !req.body.job_role ){
return res.status(400).send( { error : "job_role is mandatory!" } );
}
if( ( req.body.job_role ) &&
( !job_role_change_allowance( req.context.job_role , req.body.job_role ) )
){
return res.status(400).send( { error : "Not authorized to create the role as requested" } );
}
if( (req.context.job_role !== "owner") && (req.context.job_role !== "manager") ){
return res.status(400).send( { error : "Not authorized to create users" } );
}
if( ( req.body.job_role ) && ( req.body.job_role === "driver" ) && (req.context.permissions !== "role_carrier" ) ){
return res.status(400).send( { error : "Your company can not create drivers" } );
}
if( !req.body.email ){
return res.status(400).send( { error : "email is mandatory to create a new user" } );
}
/// Only an owner or manager can create a new user
const teamMember = await createUserWithinCompany( companyId , req.body );
return res.send( teamMember );
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
const deleteTeamMember = async(req, res) => {
try{
const user_to_remove_id = req.params.id;
const manager_id = req.context.userId;
if( (req.context.job_role !== "owner") && (req.context.job_role !== "manager") ){
return res.status(400).send( { error : "Not authorized to delete this user" } );
}
const teamMember = await deleteUserWithinCompany( manager_id, user_to_remove_id );
return res.send( teamMember );
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
module.exports = { findList , getById , getProfileData, patchProfileData, patchTeamMemberProfileData, postTeamMemberData , deleteTeamMember };

View File

@@ -0,0 +1,12 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/new', services.postVehicle);
router.patch('/:id', services.patchVehicle);
router.delete('/:id', services.deleteVehicle);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,168 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getModel } = require( `${ROOT_PATH}/${MODELS_PATH}` );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = getModel('vehicles');
const populate_list = ['categories', 'active_load','load_shipper','driver'];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const {
categories,
active_load,
load_shipper,
driver,
vehicle_code,
vehicle_name,
vehicle_number,
circulation_serial_number,
truck_type,
tyre_type,
city,
state,
status,
destino
} = query;
if( categories ) { filter_list.push({ categories }); }
if( active_load ) { filter_list.push({ active_load }); }
if( load_shipper ) { filter_list.push({ load_shipper }); }
if( driver ) { filter_list.push({ driver }); }
if( vehicle_code ) { filter_list.push({ vehicle_code }); }
if( vehicle_name ) { filter_list.push({ vehicle_name }); }
if( vehicle_number ) { filter_list.push({ vehicle_number }); }
if( circulation_serial_number ) { filter_list.push({ circulation_serial_number }); }
if( truck_type ) { filter_list.push({ truck_type }); }
if( tyre_type ) { filter_list.push({ tyre_type }); }
if( city ) { filter_list.push({ city }); }
if( state ) { filter_list.push({ state }); }
if( status ) { filter_list.push({ status }); }
if( destino ) { filter_list.push({ destino }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findElements( companyId , query ){
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query );
let filter;
if( andFilterList ){
andFilterList.push({ company : companyId });
filter = { $and : andFilterList };
}else{
filter = { company : companyId };
}
const { total , limit, skip, data } = await generic.getList( page , elements, filter );
return {
total,
limit,
skip,
data:data
};
}
async function findElementById( elementId , companyId ){
let retVal = await Model.findById( elementId ).populate( populate_list ) || {};
return retVal;
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const companyId = req.context.companyId;
const retVal = await findElements( companyId , query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const getById = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
res.send( await findElementById( elementId , companyId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const patchVehicle = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
const permissions = req.context.permissions;
const vehicle = await findElementById( elementId , companyId );
const data = req.body;
if( !vehicle ){
throw "You can't modify this vehicle";
}
if( !data ){
throw "Vehicle data not sent";
}
if( permissions !== "role_carrier" ){
throw "You can't modify vehicles";
}
data.company = companyId;
await Model.findByIdAndUpdate( elementId , data );
return res.send( await Model.findById( elementId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const postVehicle = async(req, res) => {
try{
const userId = req.context.userId;
const companyId = req.context.companyId;
const permissions = req.context.permissions;
const data = req.body;
if( !data ){
throw "Vehicle data not sent";
}
if(permissions !== "role_carrier" ){
throw "You can't create vehicles";
}
data.company = companyId;
data.status = "Free";
data.is_available = false;
data.posted_by = userId;
const vehicle = new Model( data );
await vehicle.save();
return res.send( vehicle );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const deleteVehicle = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
const permissions = req.context.permissions;
const vehicle = await findElementById( elementId , companyId );
if( !vehicle ){
throw "You can't delete this vehicle";
}
if(permissions !== "role_carrier" ){
throw "You can't delete vehicles";
}
await Model.findByIdAndDelete( elementId );
return res.send(vehicle);
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { findList, getById, patchVehicle, postVehicle, deleteVehicle };