From 67f929e3692a60a520f7b5719dcf7777b0b21e3b Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Sun, 26 Jul 2026 16:10:38 +0100 Subject: [PATCH] Refactor inventory schemas to remove redundant stock event calculations - Removed the `getStockEventTotal` function and associated `recalculate` methods from filamentStock, partStock, and productStock schemas to streamline code and reduce redundancy. - Updated stockEvent schema to include a new `recalculate` method that centralizes stock recalculation logic for improved maintainability. - Enhanced the stockEvent schema with additional utility functions for building update data and recalculating parent stock based on events. --- .../schemas/inventory/filamentstock.schema.js | 44 +--------- .../schemas/inventory/partstock.schema.js | 36 +------- .../schemas/inventory/productstock.schema.js | 36 +------- .../schemas/inventory/stockevent.schema.js | 84 +++++++++++++++++++ 4 files changed, 87 insertions(+), 113 deletions(-) diff --git a/src/database/schemas/inventory/filamentstock.schema.js b/src/database/schemas/inventory/filamentstock.schema.js index cd2e0a1..55ac461 100644 --- a/src/database/schemas/inventory/filamentstock.schema.js +++ b/src/database/schemas/inventory/filamentstock.schema.js @@ -1,26 +1,7 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; const { Schema } = mongoose; -import { aggregateRollups, aggregateRollupsHistory, editObject } from '../../database.js'; -import { stockEventModel } from './stockevent.schema.js'; - -const getStockEventTotal = async (stock, parentType) => { - const stockId = stock?._id; - if (!stockId) return null; - - const parentId = - stockId instanceof mongoose.Types.ObjectId ? stockId : new mongoose.Types.ObjectId(stockId); - - const [result] = await stockEventModel.aggregate([ - { $match: { parent: parentId, parentType } }, - { $group: { _id: null, total: { $sum: '$value' }, count: { $sum: 1 } } }, - ]); - - return { - total: result?.total ?? 0, - count: result?.count ?? 0, - }; -}; +import { aggregateRollups, aggregateRollupsHistory } from '../../database.js'; // Define the main filamentStock schema const filamentStockSchema = new Schema( @@ -91,29 +72,6 @@ filamentStockSchema.statics.history = async function (from, to) { return results; }; -filamentStockSchema.statics.recalculate = async function (filamentStock, user) { - const events = await getStockEventTotal(filamentStock, this.modelName); - if (!events?.count) return; - - const net = events.total; - const startingNet = filamentStock.startingWeight?.net ?? 0; - const startingGross = filamentStock.startingWeight?.gross ?? 0; - const gross = startingNet > 0 ? (startingGross * net) / startingNet : net; - - await editObject({ - model: this, - id: filamentStock._id, - updateData: { - currentWeight: { - net, - gross, - }, - }, - user, - recalculate: false, - }); -}; - // Add virtual id getter filamentStockSchema.virtual('id').get(function () { return this._id; diff --git a/src/database/schemas/inventory/partstock.schema.js b/src/database/schemas/inventory/partstock.schema.js index 1f4baba..0d8235d 100644 --- a/src/database/schemas/inventory/partstock.schema.js +++ b/src/database/schemas/inventory/partstock.schema.js @@ -1,26 +1,7 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; const { Schema } = mongoose; -import { aggregateRollups, aggregateRollupsHistory, editObject } from '../../database.js'; -import { stockEventModel } from './stockevent.schema.js'; - -const getStockEventTotal = async (stock, parentType) => { - const stockId = stock?._id; - if (!stockId) return null; - - const parentId = - stockId instanceof mongoose.Types.ObjectId ? stockId : new mongoose.Types.ObjectId(stockId); - - const [result] = await stockEventModel.aggregate([ - { $match: { parent: parentId, parentType } }, - { $group: { _id: null, total: { $sum: '$value' }, count: { $sum: 1 } } }, - ]); - - return { - total: result?.total ?? 0, - count: result?.count ?? 0, - }; -}; +import { aggregateRollups, aggregateRollupsHistory } from '../../database.js'; // Define the main partStock schema const partStockSchema = new Schema( @@ -74,21 +55,6 @@ partStockSchema.statics.history = async function (from, to) { return results; }; -partStockSchema.statics.recalculate = async function (partStock, user) { - const events = await getStockEventTotal(partStock, this.modelName); - if (!events?.count) return; - - await editObject({ - model: this, - id: partStock._id, - updateData: { - currentQuantity: events.total, - }, - user, - recalculate: false, - }); -}; - // Add virtual id getter partStockSchema.virtual('id').get(function () { return this._id; diff --git a/src/database/schemas/inventory/productstock.schema.js b/src/database/schemas/inventory/productstock.schema.js index f9741a1..25983c7 100644 --- a/src/database/schemas/inventory/productstock.schema.js +++ b/src/database/schemas/inventory/productstock.schema.js @@ -1,26 +1,7 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; const { Schema } = mongoose; -import { aggregateRollups, aggregateRollupsHistory, editObject } from '../../database.js'; -import { stockEventModel } from './stockevent.schema.js'; - -const getStockEventTotal = async (stock, parentType) => { - const stockId = stock?._id; - if (!stockId) return null; - - const parentId = - stockId instanceof mongoose.Types.ObjectId ? stockId : new mongoose.Types.ObjectId(stockId); - - const [result] = await stockEventModel.aggregate([ - { $match: { parent: parentId, parentType } }, - { $group: { _id: null, total: { $sum: '$value' }, count: { $sum: 1 } } }, - ]); - - return { - total: result?.total ?? 0, - count: result?.count ?? 0, - }; -}; +import { aggregateRollups, aggregateRollupsHistory } from '../../database.js'; const partStockUsageSchema = new Schema({ partStock: { type: Schema.Types.ObjectId, ref: 'partStock', required: false }, @@ -89,21 +70,6 @@ productStockSchema.statics.history = async function (from, to) { return results; }; -productStockSchema.statics.recalculate = async function (productStock, user) { - const events = await getStockEventTotal(productStock, this.modelName); - if (!events?.count) return; - - await editObject({ - model: this, - id: productStock._id, - updateData: { - currentQuantity: events.total, - }, - user, - recalculate: false, - }); -}; - // Add virtual id getter productStockSchema.virtual('id').get(function () { return this._id; diff --git a/src/database/schemas/inventory/stockevent.schema.js b/src/database/schemas/inventory/stockevent.schema.js index 48c5e2d..680fe12 100644 --- a/src/database/schemas/inventory/stockevent.schema.js +++ b/src/database/schemas/inventory/stockevent.schema.js @@ -1,7 +1,85 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; +import { getObject, editObject } from '../../database.js'; const { Schema } = mongoose; +const parentStockModelNames = { + filamentStock: 'filamentStock', + partStock: 'partStock', + productStock: 'productStock', +}; + +const initialStockStates = { + filamentStock: 'unconsumed', + partStock: 'new', +}; + +const getStockEventTotal = async (parentId, parentType) => { + if (!parentId) return null; + + const objectId = + parentId instanceof mongoose.Types.ObjectId ? parentId : new mongoose.Types.ObjectId(parentId); + + const [result] = await mongoose.model('stockEvent').aggregate([ + { $match: { parent: objectId, parentType } }, + { $group: { _id: null, total: { $sum: '$value' }, count: { $sum: 1 } } }, + ]); + + return { + total: result?.total ?? 0, + count: result?.count ?? 0, + }; +}; + +const buildParentUpdateData = (parentType, parentStock, events) => { + const updateData = {}; + + if (parentType === 'filamentStock') { + const net = events.total; + const startingNet = parentStock.startingWeight?.net ?? 0; + const startingGross = parentStock.startingWeight?.gross ?? 0; + const gross = startingNet > 0 ? (startingGross * net) / startingNet : net; + updateData.currentWeight = { net, gross }; + } else { + updateData.currentQuantity = events.total; + } + + if (parentStock.state?.type !== 'draft') { + const initialState = initialStockStates[parentType]; + if (initialState && parentStock.state?.type === initialState) { + updateData.state = { ...parentStock.state, type: 'used' }; + } + } + + return updateData; +}; + +const recalculateParentStock = async (parentType, parentId, user) => { + if (!parentType || !parentId) return; + + const modelName = parentStockModelNames[parentType]; + if (!modelName) return; + + const parentModel = mongoose.model(modelName); + const parentStock = await getObject({ + model: parentModel, + id: parentId, + cached: true, + }); + if (!parentStock || parentStock.error) return; + + const events = await getStockEventTotal(parentId, parentType); + if (!events?.count) return; + + await editObject({ + model: parentModel, + id: parentStock._id, + updateData: buildParentUpdateData(parentType, parentStock, events), + user, + recalculate: false, + }); +}; + const stockEventSchema = new Schema( { _reference: { type: String, default: () => generateId()() }, @@ -34,6 +112,12 @@ const stockEventSchema = new Schema( stockEventSchema.index({ parentType: 'text', ownerType: 'text', unit: 'text' }); +stockEventSchema.statics.recalculate = async function (stockEvent, user) { + const parentType = stockEvent.parentType; + const parentId = stockEvent.parent?._id || stockEvent.parent; + await recalculateParentStock(parentType, parentId, user); +}; + // Add virtual id getter stockEventSchema.virtual('id').get(function () { return this._id;