Your IP : 216.73.216.43


Current Path : /proc/thread-self/root/home/deltalab/PMS/partner-manager-backend/rest/routes/
Upload File :
Current File : //proc/thread-self/root/home/deltalab/PMS/partner-manager-backend/rest/routes/orders.js

/* eslint-disable no-await-in-loop */
/* eslint-disable no-use-before-define */
/* eslint-disable max-len */
const express = require('express');
const { productModel } = require('../../models/mongoose/product');
const { orderModel } = require('../../models/mongoose/order');
const { partnerModel } = require('../../models/mongoose/partner');
const { warehouseJournalModel } = require('../../models/mongoose/warehouse-journal');
const { taxQuery } = require('../queries');
const oms = require('../../services/oms');

const router = express.Router();
// TODO: controllo sul channel
router.get('/summary/admin/:partnerId/:channelId/:year/:month/:day', async (req, res) => {
  try {
    const monthlyList = {};
    const orders = await orderModel.find({
      partnerId: req.params.partnerId,
      createdAt: {
        $gte: new Date(req.params.year, req.params.month - 1, 1),
        $lt: new Date(req.params.year, req.params.month - 1, 31),
      },
    });
    for (let i = 0; i < orders.length; i++) {
      let orderTotal = 0.0;
      for (let j = 0; j < orders[i].items.length; j++) {
        const product = await productModel.findOne({ sku: orders[i].items[j].sku });
        if (!product) {
          console.log('continuo perchè il prodotto non esiste');
          continue; // The only case this should occur is with test orders with products that do not exist anymore
        }
        if (!product || !product.channelId.equals(req.params.channelId)) {
          break;
        }
        const date = new Date(orders[i].createdAt);
        const year = date.getFullYear();
        const month = date.toLocaleString('it-IT', {
          month: 'long',
        }); // date.getMonth() + 1;

        const tax = await getTaxCode(product.imsTaxCode, req.params.channelId);
        const day = date.getDate();

        if (!monthlyList[year]) {
          monthlyList[year] = {};
        }
        if (!monthlyList[year][month]) {
          monthlyList[year][month] = {};
        }
        if (!monthlyList[year][month][day]) {
          monthlyList[year][month][day] = {};
        }
        if (!monthlyList[year][month][day][tax]) {
          monthlyList[year][month][day][tax] = {};
          monthlyList[year][month][day][tax].amount = 0.0;
        }
        monthlyList[year][month][day][tax].amount += (Math.round((orders[i].items[j].totalPriceSet.amount + Number.EPSILON) * 100) / 100);
        orderTotal += orders[i].items[j].totalPriceSet.amount;
        if (j === orders[i].items.length - 1) {
          if (orderTotal < orders[i].totalPriceSet.amount) {
            const baseVat = await getTaxCode(2, req.params.channelId);
            if (!monthlyList[year][month][day][baseVat]) {
              monthlyList[year][month][day][baseVat] = {};
              monthlyList[year][month][day][baseVat].amount = 0.0;
            }
            monthlyList[year][month][day][baseVat].amount += (Math.round((orders[i].totalPriceSet.amount - orderTotal + Number.EPSILON) * 100) / 100);
          }
        }
      }
    }

    const monthlyListArray = [];
    const years = Object.keys(monthlyList);
    for (let i = 0; i < years.length; i++) {
      const months = Object.keys(monthlyList[years[i]]);
      for (let j = 0; j < months.length; j++) {
        const days = Object.keys(monthlyList[years[i]][months[j]]);
        for (let k = 0; k < days.length; k++) {
          const aliquote = Object.keys(monthlyList[years[i]][months[j]][days[k]]);
          for (let x = 0; x < aliquote.length; x++) {
            const { amount } = monthlyList[years[i]][months[j]][days[k]][aliquote[x]];
            const tax = await getTaxIdFromTaxClass(aliquote[x], req.params.channelId);
            const taxRate = await getTaxRate(tax);
            monthlyListArray.push({
              year: years[i],
              month: months[j],
              day: days[k],
              tax: aliquote[x],
              netAmount: amount / (1 + taxRate),
              taxAmount: amount - (amount / (1 + taxRate)),
            });
          }
        }
      }
    }
    return res.status(200).json({ success: true, data: monthlyListArray });
  } catch (error) {
    console.log(error.message);
    return res.status(400).send({ success: false, message: 'Error reading orders for the period', error: error.message });
  }
});

router.get('/summary/:partnerId/:channelId', async (req, res) => {
  try {
    const soldProducts = [];
    const orders = await orderModel.find();
    for (let i = 0; i < orders.length; i++) {
      for (let j = 0; j < orders[i].items.length; j++) {
        const product = await productModel.findOne({ sku: orders[i].items[j].sku });
        if (product && product.partnerId.equals(req.params.partnerId)) {
          soldProducts.push({
            product, quantity: orders[i].items[j].quantity, createdAt: orders[i].createdAt, totalPrice: orders[i].items[j].totalPriceSet.amount, totalPriceCurrency: orders[i].items[j].totalPriceSet.currencyCode,
          });
        }
      }
    }
    return res.status(200).json({ success: true, data: soldProducts });
  } catch (error) {
    console.log(error.message);
    return res.status(400).send({ success: false, message: 'Error reading attribute sets', error: error.message });
  }
});

router.get('/summary/:partnerId/:channelId/:year/:month/:day', async (req, res) => {
  try {
    const soldProducts = [];
    const orders = await orderModel.find({
      createdAt: {
        $gte: new Date(req.params.year, req.params.month - 1, 1),
        $lt: new Date(req.params.year, req.params.month - 1, 31),
      },
    });
    for (let i = 0; i < orders.length; i++) {
      for (let j = 0; j < orders[i].items.length; j++) {
        const product = await productModel.findOne({ sku: orders[i].items[j].sku });
        if (product && product.partnerId.equals(req.params.partnerId)) {
          soldProducts.push({
            product, quantity: orders[i].items[j].quantity, createdAt: orders[i].createdAt, totalPrice: orders[i].items[j].totalPriceSet.amount, totalPriceCurrency: orders[i].items[j].totalPriceSet.currencyCode,
          });
        }
      }
    }
    return res.status(200).json({ success: true, data: soldProducts });
  } catch (error) {
    console.log(error.message);
    return res.status(400).send({ success: false, message: 'Error reading attribute sets', error: error.message });
  }
});

// class SalesEntry {
// id = "";
// customer,
// customerEmail,
// itemName,
// quantity,
// price,
// priceCurrency,
// value,
// valueCurrency,
// totalPartnerCost,

// //subtotal
// boxes,
// refrigeratedWeight,
// totalItems,
// bottles,
// fragile,
// totalRevenue,
// totalCosts,

// }

// TODO: ADMIN?
router.get('/summary/details/admin/:partnerId/:channelId/:year/:month/:day', async (req, res) => {
  try {
    const rows = [];
    const orders = await orderModel.find({
      partnerId: req.params.partnerId,
      createdAt: {
        $gte: new Date(req.params.year, req.params.month - 1, 1),
        $lt: new Date(req.params.year, req.params.month - 1, 31),
      },
    });
    for (let i = 0; i < orders.length; i++) {
      // total cost calculation
      const boxes = 1;
      const boxCost = 2.9;
      const firstRowRate = 1.15;
      const subsequentRowsRate = 0.35;
      const fragileRate = 0.12;
      const bottleRate = 1.23;
      // retrieving data contained in items, needed before looping them
      const metadata = await getItemsMetaData(orders[i].items);
      const refrigeratedRate = 1.55;
      const totalValue = orders[i].totalPriceSet.amount;
      const shipmentPercentage = 0.125;
      // set 25 to totalvalue if order has no shipment (Da adattare sulla base della tabella prezzi);
      const shipmentFraction = metadata.itemTotal === totalValue ? getShipmentValueFromTable(orders[i]) * shipmentPercentage : 0;
      const totalCost = (boxes * boxCost) + (refrigeratedRate * (metadata.refrigeratedWeight / 1000)) + firstRowRate + (subsequentRowsRate * (orders[i].items.length - 1)) + shipmentFraction;
      console.log(`Total cost: ${boxes}*${boxCost} + ${refrigeratedRate}*${metadata.refrigeratedCount} + ${firstRowRate} + ${subsequentRowsRate}*${orders[i].items.length - 1} + ${shipmentFraction}`);
      for (let j = 0; j < orders[i].items.length; j++) {
        const row = {};
        row.id = orders[i].omsgid;

        row.customer = orders[i].customer.displayName;
        row.customerEmail = orders[i].customer.email;
        row.createdAt = new Date(orders[i].createdAt);
        const item = orders[i].items[j];
        row.itemName = item.name;
        const product = await productModel.findOne({ sku: item.sku });
        if (product) {
          const tax = await getTaxCode(product.imsTaxCode, req.params.channelId);
          const taxRate = await getTaxRate(product.imsTaxCode);
          const partner = await partnerModel.findOne({ _id: product.partnerId });
          if (partner) {
            row.partner = partner.companyName;
          }
          row.sku = item.sku;
          row.quantity = item.quantity;
          row.price = item.unitPriceSet.amount;
          row.priceCurrency = item.unitPriceSet.currencyCode;
          row.netValue = item.totalPriceSet.amount / (1 + taxRate);
          row.valueCurrency = item.totalPriceSet.currencyCode;
          row.taxValue = item.totalPriceSet.amount - row.netValue;
          row.productTax = tax;
          row.fragileRate = product.fragile ? fragileRate * item.quantity : 0;
          row.bottleRate = product.bottle ? bottleRate * item.quantity : 0;
          row.refrigeratedRate = product.refrigerated ? refrigeratedRate * (item.quantity * (item.weight / 1000)) : 0;
          row.shipmentFraction = shipmentFraction * (item.totalPriceSet.amount / metadata.itemTotal);
          console.log(`shipmentFraction = ${shipmentFraction}*(${item.totalPriceSet.amount / metadata.itemTotal})`);
          // row.totalRowCost = totalCost * ((row.netValue + row.taxValue + row.shipmentFraction) / totalValue);
          const paidShipment = shipmentFraction === 0 ? orders[i].totalPriceSet.amount - metadata.itemTotal : 0;
          row.totalRowCost = totalCost * ((row.netValue + row.taxValue) / (totalValue - paidShipment));
          row.totalPartnerCost = row.totalRowCost + row.fragileRate + row.bottleRate;
        }
        rows.push(row);
      }
      // Riga relativa alla spedizione
      const shipmentRow = {};
      shipmentRow.id = orders[i].omsgid;
      shipmentRow.createdAt = new Date(orders[i].createdAt);
      shipmentRow.itemName = 'Spedizione';
      shipmentRow.customer = orders[i].customer.displayName;
      shipmentRow.customerEmail = orders[i].customer.email;
      shipmentRow.totalValue = orders[i].totalPriceSet.amount - metadata.itemTotal;
      rows.push(shipmentRow);

      const recapRow = {};
      recapRow.id = orders[i].omsgid;
      recapRow.createdAt = new Date(orders[i].createdAt);
      recapRow.boxes = boxes;
      recapRow.itemName = 'Riepilogo';
      // recapRow.netValue = totalValue - metadata.itemTotal;
      recapRow.refrigeratedWeight = metadata.refrigeratedWeight;
      recapRow.items = metadata.totalQuantity;
      recapRow.totalValue = totalValue;
      recapRow.totalCost = totalCost;
      rows.push(recapRow);
    }
    return res.status(200).json({ success: true, data: rows });
  } catch (error) {
    console.log(error.message);
    return res.status(400).send({ success: false, message: 'Error reading orders for the period', error: error.message });
  }
});

// updating vendor's orders setting proper status
router.get('/update/:partnerId/', async (req, res) => {
  try {
    console.log('update orders');
    const omsorders = await oms.fetchOrdersRest()
      .catch((error) => {
        throw Error(error);
      });
    const orders = await orderModel.find({ partnerId: req.params.partnerId });

    console.log(`found ${orders.length} orders...`);
    for (let i = 0; i < orders.length; i++) {
      const order = orders[i];
      for (let j = 0; j < omsorders.length; j++) {
        if (order.omsgid === omsorders[j].omsgid) {
          console.log(`${order.omsgid} - ${omsorders[j].omsgid}`);
          console.log(`${order.status} - ${omsorders[j].status}`);
          if (order.status !== omsorders[j].status) {
            console.log(`Set status ${omsorders[j].status} over ${order.status} of order ${order.omsgid}`);
            order.status = omsorders[j].status;
            order.save();
          }
        }
      }
    }

    return res.status(200).json({ success: true, data: orders });
  } catch (error) {
    console.log(error.message);
    return res.status(400).send({ success: false, message: 'Error updating order', error: error.message });
  }
});
// updating vendor's orders setting proper status
router.get('/all/:partnerId/', async (req, res) => {
  console.log('get all orders');
  try {
    const orders = await orderModel.find({
      partnerId: req.params.partnerId,
    });
    return res.status(200).json({ success: true, data: orders });
  } catch (error) {
    console.log(error.message);
    return res.status(400).send({ success: false, message: 'Error reading orders', error: error.message });
  }
});

// updating vendor's orders setting proper status
router.get('/open/:partnerId/', async (req, res) => {
  try {
    const orders = await orderModel.find({
      partnerId: req.params.partnerId,
      fulfilled: false,
    });
    return res.status(200).json({ success: true, data: orders });
  } catch (error) {
    console.log(error.message);
    return res.status(400).send({ success: false, message: 'Error reading open orders', error: error.message });
  }
});


// updating vendor's orders setting proper status
router.post('/retry', async (req, res) => {
  try {
    const order = req.body;
    const persistentOrder = await orderModel.findOne({ omsgid: order.omsgid, instanceId: order.instanceId, storeName: order.storeName });
    await oms.checkOrder(persistentOrder, persistentOrder.instanceId, persistentOrder.storeName);
    return res.status(200).json({ success: true });
  } catch (error) {
    console.log(error.message);
    return res.status(400).send({ success: false, message: 'Error reading attribute sets', error: error.message });
  }
});

async function getItemsMetaData(items) {
  let refrigeratedCount = 0;
  let refrigeratedWeight = 0.0;
  let itemTotal = 0.0;
  let totalQuantity = 0;
  for (let i = 0; i < items.length; i++) {
    totalQuantity += items[i].quantity;
    const product = await productModel.findOne({ sku: items[i].sku });
    if (product) {
      if (product.refrigerated) {
        refrigeratedCount++;
        refrigeratedWeight += items[i].quantity * items[i].weight;
      }
      itemTotal += items[i].totalPriceSet.amount;
    }
  }
  return {
    refrigeratedCount, refrigeratedWeight, totalQuantity, itemTotal,
  };
}

async function getTaxCode(productTaxCode, channelId) {
  const taxes = await taxQuery.readMany('all', channelId);
  for (let i = 0; i < taxes.items.length; i++) {
    if (taxes.items[i].class_id.toString() === productTaxCode.toString() && taxes.items[i].class_type === 'PRODUCT') {
      return taxes.items[i].class_name;
    }
  }
  return '';
}

async function getTaxIdFromTaxClass(taxClass, channelId) {
  const taxes = await taxQuery.readMany('all', channelId);
  for (let i = 0; i < taxes.items.length; i++) {
    if (taxes.items[i].class_name.toString() === taxClass && taxes.items[i].class_type === 'PRODUCT') {
      return taxes.items[i].class_id.toString();
    }
  }
}

async function getTaxRate(tax) {
  switch (tax) {
    case '2':
      return 0.22;
    case '4':
      return 0.10;
    case '5':
      return 0.04;
    default:
      console.log('IVA default');
      return 0.22;
  }
}

function getShipmentValueFromTable(order) {
  return 25;
}

module.exports = router;