Add stock quantity calculation to listing variant schema and enhance tests

This commit introduces a new utility function, `toId`, to handle ID conversions in the `listingvarient.schema.js` file. The `recalculate` method is updated to compute and update the stock quantity for listing variants based on product SKU and stock location. Additionally, a new test case is added in `stockQuantity.recalculate.test.js` to verify the correct behavior of stock quantity calculations before rolling up, ensuring comprehensive test coverage for this functionality.
This commit is contained in:
Tom Butcher 2026-08-24 18:33:10 +01:00
parent e0f2870af3
commit 8cd8ee6f94
2 changed files with 93 additions and 0 deletions

View File

@ -39,6 +39,7 @@ describe('listingVarient.recalculate', () => {
beforeEach(() => { beforeEach(() => {
aggregateRollups.mockReset(); aggregateRollups.mockReset();
editObject.mockReset(); editObject.mockReset();
jest.restoreAllMocks();
}); });
it('sums sibling listing varient stock quantities onto the listing', async () => { it('sums sibling listing varient stock quantities onto the listing', async () => {
@ -61,6 +62,52 @@ describe('listingVarient.recalculate', () => {
recalculate: false, recalculate: false,
}); });
}); });
it('writes the product sku stock total onto the listing varient before rolling up', async () => {
jest.spyOn(listingVarientModel, 'exists').mockResolvedValue({ _id: varientId });
aggregateRollups.mockImplementation(async ({ model }) => {
if (model === productStockModel) {
return { stockQuantity: { sum: 9 } };
}
return { stockQuantity: { sum: 12 } };
});
editObject.mockResolvedValue({});
await listingVarientModel.recalculate(
{
_id: varientId,
listing: { _id: listingId, stockLocation: stockLocationId, product: productId },
product: productId,
productSku: productSkuId,
stockQuantity: 0,
},
'user-1'
);
expect(aggregateRollups).toHaveBeenCalledWith(
expect.objectContaining({
model: productStockModel,
baseFilter: {
productSku: productSkuId,
stockLocation: stockLocationId,
},
})
);
expect(editObject).toHaveBeenCalledWith({
model: listingVarientModel,
id: varientId,
updateData: { stockQuantity: 9 },
user: 'user-1',
recalculate: false,
});
expect(editObject).toHaveBeenCalledWith({
model: listingModel,
id: listingId,
updateData: { stockQuantity: 12 },
user: 'user-1',
recalculate: false,
});
});
}); });
describe('productStock.recalculate', () => { describe('productStock.recalculate', () => {

View File

@ -3,6 +3,12 @@ import { generateId } from '../../utils.js';
import { aggregateRollups, editObject } from '../../database.js'; import { aggregateRollups, editObject } from '../../database.js';
const { Schema } = mongoose; const { Schema } = mongoose;
const toId = (value) => {
if (value == null) return null;
if (typeof value === 'object' && value._id) return String(value._id);
return String(value);
};
const listingVarientSchema = new Schema( const listingVarientSchema = new Schema(
{ {
_reference: { type: String, default: () => generateId()() }, _reference: { type: String, default: () => generateId()() },
@ -48,6 +54,46 @@ listingVarientSchema.set('toJSON', {
listingVarientSchema.statics.recalculate = async function (listingVarient, user) { listingVarientSchema.statics.recalculate = async function (listingVarient, user) {
const listingId = listingVarient?.listing?._id || listingVarient?.listing; const listingId = listingVarient?.listing?._id || listingVarient?.listing;
const varientId = listingVarient?._id;
const productSkuId = toId(listingVarient?.productSku);
if (varientId && productSkuId && (await this.exists({ _id: varientId }))) {
let listing = listingVarient.listing;
if (!listing?.stockLocation) {
listing = await mongoose
.model('listing')
.findById(listingId)
.select('stockLocation product')
.lean();
}
const stockLocationId = toId(listing?.stockLocation);
if (stockLocationId) {
const stockRollup = await aggregateRollups({
model: mongoose.model('productStock'),
baseFilter: {
productSku: new mongoose.Types.ObjectId(productSkuId),
stockLocation: new mongoose.Types.ObjectId(stockLocationId),
},
rollupConfigs: [
{
name: 'stockQuantity',
rollups: [{ name: 'stockQuantity', property: 'currentQuantity', operation: 'sum' }],
},
],
});
const stockQuantity = stockRollup.stockQuantity?.sum || 0;
if (listingVarient.stockQuantity !== stockQuantity) {
await editObject({
model: this,
id: varientId,
updateData: { stockQuantity },
user,
recalculate: false,
});
}
}
}
if (!listingId) { if (!listingId) {
return; return;
} }