Your IP : 216.73.216.220


Current Path : /proc/thread-self/root/home/deltalab/PMS/partner-manager-backend/test/
Upload File :
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');
  });
});