From c57641518efdbac94e112461a042696cd1c167c2 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Mon, 24 Aug 2026 22:54:09 +0100 Subject: [PATCH] Enhance inventory schemas with additional rollup configurations for stock types This commit adds new rollup configurations to the `filamentstock`, `partstock`, and `productstock` schemas to track the counts of different stock states: 'unconsumed', 'used', and 'consumed'. Additionally, the `stockevent` schema is updated to include rollup statistics for various stock types, improving the overall inventory management capabilities. Tests are also updated to mock new aggregate functions, ensuring comprehensive coverage of the new functionalities. --- .../schemas/inventory/filamentstock.schema.js | 15 +++++++ .../schemas/inventory/partstock.schema.js | 15 +++++++ .../schemas/inventory/productstock.schema.js | 10 +++++ .../schemas/inventory/stockevent.schema.js | 40 ++++++++++++++++++- .../__tests__/filamentstocks.test.js | 6 +++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/database/schemas/inventory/filamentstock.schema.js b/src/database/schemas/inventory/filamentstock.schema.js index bfbc16c..21ba3f4 100644 --- a/src/database/schemas/inventory/filamentstock.schema.js +++ b/src/database/schemas/inventory/filamentstock.schema.js @@ -58,6 +58,21 @@ const rollupConfigs = [ filter: {}, rollups: [{ name: 'totalCurrentWeight', property: 'currentWeight.net', operation: 'sum' }], }, + { + name: 'unconsumed', + filter: { 'state.type': 'unconsumed' }, + rollups: [{ name: 'unconsumed', property: 'state.type', operation: 'count' }], + }, + { + name: 'used', + filter: { 'state.type': 'used' }, + rollups: [{ name: 'used', property: 'state.type', operation: 'count' }], + }, + { + name: 'consumed', + filter: { 'state.type': 'consumed' }, + rollups: [{ name: 'consumed', property: 'state.type', operation: 'count' }], + }, ]; filamentStockSchema.statics.stats = async function () { diff --git a/src/database/schemas/inventory/partstock.schema.js b/src/database/schemas/inventory/partstock.schema.js index 5de8d41..4d2aaa6 100644 --- a/src/database/schemas/inventory/partstock.schema.js +++ b/src/database/schemas/inventory/partstock.schema.js @@ -46,6 +46,21 @@ const rollupConfigs = [ filter: {}, rollups: [{ name: 'totalCurrentQuantity', property: 'currentQuantity', operation: 'sum' }], }, + { + name: 'new', + filter: { 'state.type': 'new' }, + rollups: [{ name: 'new', property: 'state.type', operation: 'count' }], + }, + { + name: 'used', + filter: { 'state.type': 'used' }, + rollups: [{ name: 'used', property: 'state.type', operation: 'count' }], + }, + { + name: 'consumed', + filter: { 'state.type': 'consumed' }, + rollups: [{ name: 'consumed', property: 'state.type', operation: 'count' }], + }, ]; partStockSchema.statics.stats = async function () { diff --git a/src/database/schemas/inventory/productstock.schema.js b/src/database/schemas/inventory/productstock.schema.js index c635642..aa21f56 100644 --- a/src/database/schemas/inventory/productstock.schema.js +++ b/src/database/schemas/inventory/productstock.schema.js @@ -89,6 +89,16 @@ const rollupConfigs = [ filter: { 'state.type': 'new' }, rollups: [{ name: 'new', property: 'state.type', operation: 'count' }], }, + { + name: 'used', + filter: { 'state.type': 'used' }, + rollups: [{ name: 'used', property: 'state.type', operation: 'count' }], + }, + { + name: 'consumed', + filter: { 'state.type': 'consumed' }, + rollups: [{ name: 'consumed', property: 'state.type', operation: 'count' }], + }, ]; productStockSchema.statics.stats = async function () { diff --git a/src/database/schemas/inventory/stockevent.schema.js b/src/database/schemas/inventory/stockevent.schema.js index 0f570af..10f3b7c 100644 --- a/src/database/schemas/inventory/stockevent.schema.js +++ b/src/database/schemas/inventory/stockevent.schema.js @@ -1,6 +1,6 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; -import { getObject, editObject } from '../../database.js'; +import { getObject, editObject, aggregateRollups, aggregateRollupsHistory } from '../../database.js'; const { Schema } = mongoose; const parentStockModelNames = { @@ -239,6 +239,44 @@ const stockEventSchema = new Schema( stockEventSchema.index({ parentType: 'text', ownerType: 'text', unit: 'text' }); +const rollupConfigs = [ + { + name: 'partStock', + filter: { parentType: 'partStock' }, + rollups: [{ name: 'partStock', property: 'parentType', operation: 'count' }], + }, + { + name: 'filamentStock', + filter: { parentType: 'filamentStock' }, + rollups: [{ name: 'filamentStock', property: 'parentType', operation: 'count' }], + }, + { + name: 'productStock', + filter: { parentType: 'productStock' }, + rollups: [{ name: 'productStock', property: 'parentType', operation: 'count' }], + }, +]; + +stockEventSchema.statics.stats = async function () { + const results = await aggregateRollups({ + model: this, + rollupConfigs: rollupConfigs, + }); + + return results; +}; + +stockEventSchema.statics.history = async function (from, to) { + const results = await aggregateRollupsHistory({ + model: this, + startDate: from, + endDate: to, + rollupConfigs: rollupConfigs, + }); + + return results; +}; + stockEventSchema.statics.recalculate = async function (stockEvent, user) { const history = stockEvent.history || []; const lastEntry = history.at(-1); diff --git a/src/services/inventory/__tests__/filamentstocks.test.js b/src/services/inventory/__tests__/filamentstocks.test.js index e55bedb..ea8012b 100644 --- a/src/services/inventory/__tests__/filamentstocks.test.js +++ b/src/services/inventory/__tests__/filamentstocks.test.js @@ -13,12 +13,18 @@ jest.unstable_mockModule('../../../database/database.js', () => ({ getModelStats: jest.fn(), getModelHistory: jest.fn(), getObjectNeighbors: jest.fn(), + aggregateRollups: jest.fn(), + aggregateRollupsHistory: jest.fn(), })); jest.unstable_mockModule('../../../database/schemas/inventory/filamentstock.schema.js', () => ({ filamentStockModel: { modelName: 'FilamentStock' }, })); +jest.unstable_mockModule('../../../database/schemas/inventory/stockevent.schema.js', () => ({ + stockEventModel: { modelName: 'StockEvent' }, +})); + jest.unstable_mockModule('log4js', () => ({ default: { getLogger: () => ({