| Current Path : /proc/thread-self/root/home/deltalab/PMS/partner-manager-backend/test/ |
| Current File : //proc/thread-self/root/home/deltalab/PMS/partner-manager-backend/test/parcels.test.js |
/**
* Shipment tests, creation, control and monitoring.
*/
// DEPENDENCIES ====================================
const { expect, assert } = require('chai');
const { dotenv } = require('dotenv').config();
const mongoose = require('mongoose');
const mail = require('../services/mail');
// RESOURCES =======================================
const oms = require('../services/oms');
const sms = require('../services/sms');
const { orderModel } = require('../models/mongoose/order');
const { orderItemModel } = require('../models/mongoose/order');
const { parcelModel } = require('../models/mongoose/parcel');
const { parcelBaseModel } = require('../models/mongoose/parcel');
const { boxModel } = require('../models/mongoose/parcel');
const { partnerModel } = require('../models/mongoose/partner');
const { shipmentBaseInfoModel } = require('../models/mongoose/shipment');
const { carrierModel } = require('../models/mongoose/carrier');
// TEST OBJECTS ====================================
// OMS order to be checked for
// this order data is meant to be received by the OMS
// either by polling or by webhook
// TEST OBJECTS ====================================
// OMS order to be checked for
// this order data is meant to be received by the OMS
// either by polling or by webhook
const myorder = {
items: [
// {
// name : "Example T-Shirt - Lithograph - Height: 9\" x Width: 12\"",
// imsgid : "gid://shopify/Product/6734691500208",
// sku : "1612xxx",
// quantity : 1,
// totalPriceSet : {
// amount : 25,
// currencyCode : "EUR"
// },
// unitPriceSet : {
// amount : 25,
// currencyCode : "EUR"
// },
// },
// {
// name : "pms 0120b",
// imsgid : "gid://shopify/Product/7027111198896",
// sku : "0120b",
// quantity : 20,
// totalPriceSet : {
// amount : 25,
// currencyCode : "EUR"
// },
// unitPriceSet : {
// amount : 25,
// currencyCode : "EUR"
// },
{
name: 'Prodotto da magazzino con tante mail',
imsgid: 'gid://shopify/Product/7038210146480',
sku: '1612xxx',
quantity: 1,
totalPriceSet: {
amount: 111,
currencyCode: 'EUR',
},
unitPriceSet: {
amount: 111,
currencyCode: 'EUR',
},
},
],
omsgid: 'gid://shopify/Order/3882359750832',
name: '#1006',
createdAt: '2021-07-01T13:21:49.000Z', // ISODate
customer: {
displayName: 'Daniele Dellagiacoma',
phone: '+393493408911',
email: 'deltalab@deltainformatica.eu',
},
shippingAddress: {
name: 'Daniele Dellagiacoma',
company: '',
address1: 'via del Revì, 24',
address2: '',
city: 'Aldeno',
province: 'TN',
state: 'Italy',
zip: '38060',
country: 'Italy',
email: 'deltalab@deltainformatica.eu',
phone: '+393493408911',
},
totalPriceSet: {
amount: 34.99,
currencyCode: 'EUR',
},
// status : "Fulfilled",
status: 'Processing',
partnerId: '6125199597b1612d8071eafd',
updatedAt: '2021-11-05T17:18:52.452Z', // ISODate
shipmentId: '6185677cddc25834befa82eb',
};
// TEST CASES ======================================
describe('parcels', function () {
this.timeout(15000);
// Initialization --------------------------------
before((done) => {
mongoose.connect(process.env.database_url);
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error'));
db.once('open', () => {
console.log('We are connected to test database!');
done();
});
});
let orderId; // the id of the created order
it('get order warehouse', async () => {
console.log('start');
const order = orderModel.findOne();
console.log(order.partner);
console.log(`found ${warehouses.length} warehouses for order ${myorder.name}`);
const warehouseAddress = await sms.getBestWarehouseAddress(myorder, warehouses);
});
it('get pickup date', async () => {
const pickupDate = new Date('2022-02-13T16:16:00');
pickupDate.setDate(sms.getPickupDate(pickupDate).getDate()); // Next working day
console.log(`pickup date ${pickupDate}`);
});
it('order parcels', async () => {
const parcels = await sms.createParcels(myorder);
console.log(parcels);
});
it('select carrier', async () => {
const carrier = new carrierModel();
carrier.name = 'Test';
carrier.description = 'Test';
carrier.smsid = '2861';
carrier.service = 'Standard';
carrier.partnerId = myorder.partnerId;
await carrier.save();
const carrierIds = await sms.getCarrierIds(myorder.partnerId);
console.log(carrierIds);
});
it('shipping rates', async () => {
console.log('entro');
console.log(`found ${warehouses.length} warehouses for order ${myorder.name}`);
const warehouseAddress = await sms.getBestWarehouseAddress(myorder, warehouses);
console.log(warehouseAddress.from);
const parcels = await sms.createParcels(myorder);
const shipmentBaseInfo = new shipmentBaseInfoModel();
shipmentBaseInfo.from = warehouseAddress.from;
shipmentBaseInfo.to = sms.getShippingAddress(myorder);
shipmentBaseInfo.parcels = parcels;
shipmentBaseInfo.shipmentValueInfo = sms.createShipmentValueInfo(
myorder.totalPriceSet.amount,
myorder.totalPriceSet.currencyCode,
);
// shipmentBaseInfo.shipmentValueInfo.shippingService = "EXPRESS DOMESTIC";
console.log(shipmentBaseInfo);
const rates = await sms.fetchRates(shipmentBaseInfo);
console.log(rates);
const carrierIds = [];
carrierIds.push('2861'); // Generic Carrier
// carrierIds.push("7571"); // DHL Express
const rate = sms.getBestRate(rates, carrierIds);
console.log(rate);
// parcels override ---------------
const customParcels = [];
const parcel = new parcelBaseModel();
parcel.height = 50;
parcel.length = 200;
parcel.width = 200;
parcel.weight = 1000;
customParcels.push(parcel);
shipmentBaseInfo.parcels = customParcels;
console.log(shipmentBaseInfo);
console.log(shipmentBaseInfo);
const customRates = await sms.fetchRates(shipmentBaseInfo);
console.log(customRates);
const customRate = sms.getBestRate(rates, carrierIds);
console.log(customRate);
// const orderId = myorder.name.substring(1);
// const shipmentCreationData = await sms.createShipment(orderId, customRate.carrier.smsid, customRate.rateId, shipmentBaseInfo);
// // Book a pickup for this shipment
// const pickupDate = new Date(); // Today
// pickupDate.setDate(sms.getPickupDate(pickupDate).getDate());
// console.log(pickupDate);
// // forcing pickup date to today
// const customPickupDate = new Date();
// customPickupDate.setHours(15);
// customPickupDate.setMinutes(30);
// console.log(customPickupDate);
// const pickupConfirmation = await sms.bookPickup(customRate.carrier.smsid, shipmentBaseInfo, customPickupDate);
// console.log(pickupConfirmation);
});
it('picking list pdf', async () => {
const order = myorder;
order.partner = await partnerModel.findById(order.partnerId);
const warehouseAddress = {
email: 'matteo.pedrotti@deltainformatica.eu',
};
const parcels = await sms.createParcels(myorder);
const pdf = pdf.generatePickingListPdf(order, parcels, false);
// pdf is a stream so you can pipe it to the file system
const fs = require('fs');
pdf.pipe(fs.createWriteStream('warehouse_order.pdf'));
pdf.end();
});
it('picking mail', async () => {
const order = myorder;
order.partner = await partnerModel.findById(order.partnerId);
const warehouseAddress = {
email: 'matteo.pedrotti@deltainformatica.eu',
};
const parcels = await sms.createParcels(myorder);
mail.sendPickingEmail(warehouseAddress.email, order, parcels);
});
it('parcel models', async () => {
const parcel = new parcelModel();
const box = new boxModel();
box.maxWeight = 5000;
box.length = 400;
box.height = 400;
box.width = 400;
parcel.setBox(box);
const item = new orderItemModel();
item.name = 'my item';
item.weight = 125;
parcel.addItem(item);
parcel.addItem(item);
const parcelBase = new parcelBaseModel(parcel);
console.log(parcel);
console.log(parcelBase);
});
/**
* Creates a boxModel with the given parameters
* @param {*} name
* @param {*} height
* @param {*} length
* @param {*} width
* @param {*} maxWeight grams
* @param {*} weight grams
* @returns a boxModel
*/
function createBox(name, height, length, width, maxWeight, weight) {
const box = new boxModel();
box.name = name;
box.height = height;
box.length = length;
box.width = width;
box.maxWeight = maxWeight; // grams
box.weight = weight; // box intrinsic weight
return box;
}
/**
* Creates a an orderItemModel with the minimum set of required parameters
* @param {*} name
* @param {*} quantity
* @param {*} weight grams
* @returns an orderItemModel
*/
function createItem(name, quantity, weight) {
const item = new orderItemModel();
item.name = name;
item.quantity = quantity;
item.weight = weight;
return item;
}
function computeWaste(parcels) {
let waste = 0;
for (const parcel of parcels) {
if (parcel.box) {
const parcelWaste = parcel.box.maxWeight - parcel.weight;
waste += parcelWaste;
console.log(`- parcel box ${parcel.box.name} (${parcelWaste})`);
for (const item of parcel.items) {
console.log(`-- item ${item.name} ${item.weight}`);
}
}
}
return waste;
}
// randomize array order
function shuffle(array) {
let currentIndex = array.length; let
randomIndex;
// While there remain elements to shuffle...
while (currentIndex !== 0) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}
it('compute parcels', () => {
// available boxes
const box1 = createBox('small', 350, 250, 150, 2500, 150);
const box2 = createBox('medium', 400, 300, 200, 5000, 200);
const box3 = createBox('big', 450, 350, 250, 7500, 250);
const box4 = createBox('huge', 500, 400, 300, 10000, 300);
const boxes = [];
boxes.push(box2);
boxes.push(box4);
boxes.push(box3);
boxes.push(box1);
// sample items
const item1 = createItem('big boozy bottle', 4, 1150);
const item2 = createItem('cheecky cheesy cheddar', 3, 4330);
const item3 = createItem('special spicy soup', 2, 3932);
const item4 = createItem('hefty half honey', 5, 4579);
const items = [];
items.push(item1);
items.push(item3);
items.push(item4);
items.push(item2);
// first of all ensure the boxes are sorted ascending by maxWeight
// we can do this, ahead of the logic to reduce load
sms.sortBoxes(boxes);
// Default offline algorithm
{
const parcels = sms.estimateParcels(items, boxes);
const waste = computeWaste(parcels);
console.log(`> defined order items: parcels ${parcels.length} waste ${waste}`);
}
// Sorted weight ascending
{
const sortedItems = sms.sortItems(items, 'ASC');
// console.log(sortedItems);
const parcels = sms.estimateParcels(sortedItems, boxes);
const waste = computeWaste(parcels);
console.log(`> sorted ascending items: parcels ${parcels.length} waste ${waste}`);
}
// Sorced weight descending
{
// This is the best solution for a first fit offline algorithm
const sortedItems = sms.sortItems(items, 'DESC');
// console.log(sortedItems);
const parcels = sms.estimateParcels(sortedItems, boxes);
const waste = computeWaste(parcels);
console.log(`> sorted descending items: parcels ${parcels.length} waste ${waste}`);
}
// Random check
{
const shuffledItems = shuffle(items);
const parcels = sms.estimateParcels(shuffledItems, boxes);
const waste = computeWaste(parcels);
console.log(`> random parcels ${parcels.length} waste ${waste}`);
}
console.log('bye');
});
});