From ab70b6e11e58a4d5c43de6ce2ef78842b95b2540 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Fri, 6 Mar 2026 21:14:15 +0000 Subject: [PATCH] Implemented sales order calculations. --- .../schemas/inventory/orderitem.schema.js | 53 +++++---- .../schemas/inventory/shipment.schema.js | 13 ++- .../schemas/sales/salesorder.schema.js | 109 +++++++++++++++++- 3 files changed, 148 insertions(+), 27 deletions(-) diff --git a/src/database/schemas/inventory/orderitem.schema.js b/src/database/schemas/inventory/orderitem.schema.js index 3cb62ff..0d3a46c 100644 --- a/src/database/schemas/inventory/orderitem.schema.js +++ b/src/database/schemas/inventory/orderitem.schema.js @@ -1,5 +1,6 @@ import mongoose from 'mongoose'; import { purchaseOrderModel } from './purchaseorder.schema.js'; +import { salesOrderModel } from '../sales/salesorder.schema.js'; import { taxRateModel } from '../management/taxrate.schema.js'; import { aggregateRollups, @@ -78,8 +79,7 @@ orderItemSchema.statics.history = async function (from, to) { }; orderItemSchema.statics.recalculate = async function (orderItem, user) { - // Only purchase orders are supported for now - if (orderItem.orderType !== 'purchaseOrder') { + if (orderItem.orderType !== 'purchaseOrder' && orderItem.orderType !== 'salesOrder') { return; } @@ -144,14 +144,15 @@ orderItemSchema.statics.recalculate = async function (orderItem, user) { const totalAmount = totals.totalAmount.sum?.toFixed(2) || 0; const totalAmountWithTax = totals.totalAmountWithTax.sum?.toFixed(2) || 0; - const purchaseOrder = await getObject({ - model: purchaseOrderModel, + const orderModel = orderItem.orderType === 'purchaseOrder' ? purchaseOrderModel : salesOrderModel; + const order = await getObject({ + model: orderModel, id: orderId, cached: true, }); const grandTotalAmount = - parseFloat(totalAmountWithTax || 0) + parseFloat(purchaseOrder.shippingAmountWithTax || 0); + parseFloat(totalAmountWithTax || 0) + parseFloat(order.shippingAmountWithTax || 0); var updateData = { totalAmount: parseFloat(totalAmount).toFixed(2), @@ -164,24 +165,36 @@ orderItemSchema.statics.recalculate = async function (orderItem, user) { const shippedCount = rollupResults.shipped.count || 0; const receivedCount = rollupResults.received.count || 0; - if (shippedCount > 0 && shippedCount < overallCount) { - updateData = { ...updateData, state: { type: 'partiallyShipped' } }; - } - - if (shippedCount > 0 && shippedCount == overallCount) { - updateData = { ...updateData, state: { type: 'shipped' } }; - } - - if (receivedCount > 0 && receivedCount < overallCount) { - updateData = { ...updateData, state: { type: 'partiallyReceived' } }; - } - - if (receivedCount > 0 && receivedCount == overallCount) { - updateData = { ...updateData, state: { type: 'received' } }; + if (orderItem.orderType === 'purchaseOrder') { + if (shippedCount > 0 && shippedCount < overallCount) { + updateData = { ...updateData, state: { type: 'partiallyShipped' } }; + } + if (shippedCount > 0 && shippedCount == overallCount) { + updateData = { ...updateData, state: { type: 'shipped' } }; + } + if (receivedCount > 0 && receivedCount < overallCount) { + updateData = { ...updateData, state: { type: 'partiallyReceived' } }; + } + if (receivedCount > 0 && receivedCount == overallCount) { + updateData = { ...updateData, state: { type: 'received' } }; + } + } else { + if (shippedCount > 0 && shippedCount < overallCount) { + updateData = { ...updateData, state: { type: 'partiallyShipped' } }; + } + if (shippedCount > 0 && shippedCount == overallCount) { + updateData = { ...updateData, state: { type: 'shipped' } }; + } + if (receivedCount > 0 && receivedCount < overallCount) { + updateData = { ...updateData, state: { type: 'partiallyDelivered' } }; + } + if (receivedCount > 0 && receivedCount == overallCount) { + updateData = { ...updateData, state: { type: 'delivered' } }; + } } await editObject({ - model: purchaseOrderModel, + model: orderModel, id: orderId, updateData: updateData, user, diff --git a/src/database/schemas/inventory/shipment.schema.js b/src/database/schemas/inventory/shipment.schema.js index 6abb147..1391501 100644 --- a/src/database/schemas/inventory/shipment.schema.js +++ b/src/database/schemas/inventory/shipment.schema.js @@ -2,6 +2,7 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; const { Schema } = mongoose; import { purchaseOrderModel } from './purchaseorder.schema.js'; +import { salesOrderModel } from '../sales/salesorder.schema.js'; import { taxRateModel } from '../management/taxrate.schema.js'; import { aggregateRollups, editObject, getObject } from '../../database.js'; @@ -34,8 +35,7 @@ const shipmentSchema = new Schema( ); shipmentSchema.statics.recalculate = async function (shipment, user) { - // Only purchase orders are supported for now - if (shipment.orderType !== 'purchaseOrder') { + if (shipment.orderType !== 'purchaseOrder' && shipment.orderType !== 'salesOrder') { return; } @@ -90,16 +90,17 @@ shipmentSchema.statics.recalculate = async function (shipment, user) { const totalShippingAmount = totals.amount.sum?.toFixed(2) || 0; const totalShippingAmountWithTax = totals.amountWithTax.sum?.toFixed(2) || 0; - const purchaseOrder = await getObject({ - model: purchaseOrderModel, + const orderModel = shipment.orderType === 'purchaseOrder' ? purchaseOrderModel : salesOrderModel; + const order = await getObject({ + model: orderModel, id: orderId, cached: true, }); const grandTotalAmount = - parseFloat(purchaseOrder.totalAmountWithTax || 0) + parseFloat(totalShippingAmountWithTax || 0); + parseFloat(order.totalAmountWithTax || 0) + parseFloat(totalShippingAmountWithTax || 0); await editObject({ - model: purchaseOrderModel, + model: orderModel, id: orderId, updateData: { shippingAmount: parseFloat(totalShippingAmount).toFixed(2), diff --git a/src/database/schemas/sales/salesorder.schema.js b/src/database/schemas/sales/salesorder.schema.js index 2874d69..20f18c8 100644 --- a/src/database/schemas/sales/salesorder.schema.js +++ b/src/database/schemas/sales/salesorder.schema.js @@ -1,7 +1,11 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; const { Schema } = mongoose; -import { aggregateRollups, aggregateRollupsHistory } from '../../database.js'; +import { + aggregateRollups, + aggregateRollupsHistory, + editObject, +} from '../../database.js'; const salesOrderSchema = new Schema( { @@ -95,6 +99,109 @@ salesOrderSchema.statics.history = async function (from, to) { return results; }; +salesOrderSchema.statics.recalculate = async function (salesOrder, user) { + const orderId = salesOrder._id || salesOrder; + if (!orderId) { + return; + } + + const orderItemModel = mongoose.model('orderItem'); + const shipmentModel = mongoose.model('shipment'); + + const orderIdObj = new mongoose.Types.ObjectId(orderId); + const baseFilter = { order: orderIdObj, orderType: 'salesOrder' }; + + const orderItemRollupResults = await aggregateRollups({ + model: orderItemModel, + baseFilter, + rollupConfigs: [ + { + name: 'orderTotals', + rollups: [ + { name: 'totalAmount', property: 'totalAmount', operation: 'sum' }, + { name: 'totalAmountWithTax', property: 'totalAmountWithTax', operation: 'sum' }, + ], + }, + { + name: 'overallCount', + rollups: [{ name: 'overallCount', property: '_id', operation: 'count' }], + }, + { + name: 'shipped', + filter: { 'state.type': 'shipped' }, + rollups: [{ name: 'shipped', property: 'state.type', operation: 'count' }], + }, + { + name: 'received', + filter: { 'state.type': 'received' }, + rollups: [{ name: 'received', property: 'state.type', operation: 'count' }], + }, + ], + }); + + const shipmentRollupResults = await aggregateRollups({ + model: shipmentModel, + baseFilter, + rollupConfigs: [ + { + name: 'shipmentTotals', + rollups: [ + { name: 'amount', property: 'amount', operation: 'sum' }, + { name: 'amountWithTax', property: 'amountWithTax', operation: 'sum' }, + ], + }, + ], + }); + + const orderTotals = orderItemRollupResults.orderTotals || {}; + const totalAmount = orderTotals.totalAmount?.sum?.toFixed(2) || 0; + const totalAmountWithTax = orderTotals.totalAmountWithTax?.sum?.toFixed(2) || 0; + + const shipmentTotals = shipmentRollupResults.shipmentTotals || {}; + const totalShippingAmount = shipmentTotals.amount?.sum?.toFixed(2) || 0; + const totalShippingAmountWithTax = shipmentTotals.amountWithTax?.sum?.toFixed(2) || 0; + + const grandTotalAmount = + parseFloat(totalAmountWithTax || 0) + parseFloat(totalShippingAmountWithTax || 0); + + const overallCount = orderItemRollupResults.overallCount?.count || 0; + const shippedCount = orderItemRollupResults.shipped?.count || 0; + const receivedCount = orderItemRollupResults.received?.count || 0; + + let updateData = { + totalAmount: parseFloat(totalAmount).toFixed(2), + totalAmountWithTax: parseFloat(totalAmountWithTax).toFixed(2), + totalTaxAmount: parseFloat((totalAmountWithTax - totalAmount).toFixed(2)), + shippingAmount: parseFloat(totalShippingAmount).toFixed(2), + shippingAmountWithTax: parseFloat(totalShippingAmountWithTax).toFixed(2), + grandTotalAmount: parseFloat(grandTotalAmount).toFixed(2), + }; + + if (shippedCount > 0 && shippedCount < overallCount) { + updateData = { ...updateData, state: { type: 'partiallyShipped' } }; + } + + if (shippedCount > 0 && shippedCount === overallCount) { + updateData = { ...updateData, state: { type: 'shipped' } }; + } + + if (receivedCount > 0 && receivedCount < overallCount) { + updateData = { ...updateData, state: { type: 'partiallyDelivered' } }; + } + + if (receivedCount > 0 && receivedCount === overallCount) { + updateData = { ...updateData, state: { type: 'delivered' } }; + } + + await editObject({ + model: this, + id: orderId, + updateData, + user, + recalculate: false, + }); +}; + // Add virtual id getter salesOrderSchema.virtual('id').get(function () { return this._id;