Enhance inventory schemas and introduce stock audit level management
Some checks failed
farmcontrol/farmcontrol-ws/pipeline/head There was a failure building this commit
Some checks failed
farmcontrol/farmcontrol-ws/pipeline/head There was a failure building this commit
- Added `stockAuditLevelModel` and its schema to manage stock audit levels, including normalization functions for audit lines. - Updated `filamentStock`, `partStock`, and `productStock` schemas to integrate stock audit calculations, ensuring accurate stock quantity tracking. - Introduced a `recalculate` method in the stock audit schema to handle stock quantity updates based on audit levels. - Removed the obsolete `stockEvent` schema to streamline inventory management. - Enhanced existing schemas with new fields and methods for improved inventory auditing and reporting capabilities.
This commit is contained in:
parent
ffcc7cd0aa
commit
5349538046
@ -2,6 +2,13 @@ import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
||||
import { updateDraftStockAuditCurrents } from './stockaudit.schema.js';
|
||||
|
||||
const toId = (value) => {
|
||||
if (value == null) return null;
|
||||
if (typeof value === 'object' && value._id) return String(value._id);
|
||||
return String(value);
|
||||
};
|
||||
|
||||
// Define the main filamentStock schema
|
||||
const filamentStockSchema = new Schema(
|
||||
@ -96,6 +103,19 @@ filamentStockSchema.statics.history = async function (from, to) {
|
||||
return results;
|
||||
};
|
||||
|
||||
filamentStockSchema.statics.recalculate = async function (filamentStock, user) {
|
||||
const itemSkuId = toId(filamentStock?.filamentSku);
|
||||
const stockLocationId = toId(filamentStock?.stockLocation);
|
||||
if (!itemSkuId || !stockLocationId) return;
|
||||
|
||||
await updateDraftStockAuditCurrents({
|
||||
itemType: 'filament',
|
||||
itemSkuId,
|
||||
stockLocationId,
|
||||
user,
|
||||
});
|
||||
};
|
||||
|
||||
// Add virtual id getter
|
||||
filamentStockSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
import { aggregateRollups, aggregateRollupsHistory, editObject } from '../../database.js';
|
||||
import { updateDraftStockAuditCurrents } from './stockaudit.schema.js';
|
||||
|
||||
const toId = (value) => {
|
||||
if (value == null) return null;
|
||||
if (typeof value === 'object' && value._id) return String(value._id);
|
||||
return String(value);
|
||||
};
|
||||
|
||||
// Define the main partStock schema
|
||||
const partStockSchema = new mongoose.Schema(
|
||||
@ -89,6 +96,18 @@ partStockSchema.statics.history = async function (from, to) {
|
||||
|
||||
partStockSchema.statics.recalculate = async function (partStock, user) {
|
||||
if (!partStock?._id) return;
|
||||
|
||||
const itemSkuId = toId(partStock.partSku);
|
||||
const stockLocationId = toId(partStock.stockLocation);
|
||||
if (itemSkuId && stockLocationId) {
|
||||
await updateDraftStockAuditCurrents({
|
||||
itemType: 'part',
|
||||
itemSkuId,
|
||||
stockLocationId,
|
||||
user,
|
||||
});
|
||||
}
|
||||
|
||||
if (partStock.state?.type === 'draft' || partStock.state?.type === 'consumed') return;
|
||||
if ((Number(partStock.currentQuantity) || 0) > 0) return;
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory, editObject } from '../../database.js';
|
||||
import { updateDraftStockAuditCurrents } from './stockaudit.schema.js';
|
||||
|
||||
const partStockListItemSchema = new Schema({
|
||||
part: { type: Schema.Types.ObjectId, ref: 'part', required: true },
|
||||
@ -122,6 +123,17 @@ productStockSchema.statics.history = async function (from, to) {
|
||||
};
|
||||
|
||||
productStockSchema.statics.recalculate = async function (productStock, user) {
|
||||
const productSkuId = toId(productStock?.productSku);
|
||||
const stockLocationId = toId(productStock?.stockLocation);
|
||||
if (productSkuId && stockLocationId) {
|
||||
await updateDraftStockAuditCurrents({
|
||||
itemType: 'product',
|
||||
itemSkuId: productSkuId,
|
||||
stockLocationId,
|
||||
user,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
productStock?._id &&
|
||||
productStock.state?.type !== 'draft' &&
|
||||
@ -139,8 +151,6 @@ productStockSchema.statics.recalculate = async function (productStock, user) {
|
||||
});
|
||||
}
|
||||
|
||||
const productSkuId = toId(productStock?.productSku);
|
||||
const stockLocationId = toId(productStock?.stockLocation);
|
||||
if (!productSkuId || !stockLocationId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,42 +1,311 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
import { editObject, getObject } from '../../database.js';
|
||||
import { stockAuditLevelModel, normalizeAuditLevelLine } from '../management/stockauditlevel.schema.js';
|
||||
import { filamentModel } from '../management/filament.schema.js';
|
||||
import { filamentSkuModel } from '../management/filamentsku.schema.js';
|
||||
import { partModel } from '../management/part.schema.js';
|
||||
import { partSkuModel } from '../management/partsku.schema.js';
|
||||
import { productModel } from '../management/product.schema.js';
|
||||
import { productSkuModel } from '../management/productsku.schema.js';
|
||||
|
||||
const { Schema } = mongoose;
|
||||
|
||||
const stockAuditItemSchema = new Schema({
|
||||
type: { type: String, enum: ['filament', 'part'], required: true },
|
||||
stock: { type: Schema.Types.ObjectId, required: true },
|
||||
expectedQuantity: { type: Number, required: true },
|
||||
actualQuantity: { type: Number, required: true },
|
||||
notes: { type: String },
|
||||
});
|
||||
const itemModelsByType = {
|
||||
filament: filamentModel,
|
||||
part: partModel,
|
||||
product: productModel,
|
||||
};
|
||||
|
||||
const skuModelsByType = {
|
||||
filament: filamentSkuModel,
|
||||
part: partSkuModel,
|
||||
product: productSkuModel,
|
||||
};
|
||||
|
||||
const parentFieldByType = {
|
||||
filament: 'filament',
|
||||
part: 'part',
|
||||
product: 'product',
|
||||
};
|
||||
|
||||
const toId = (value) => {
|
||||
if (value == null) return null;
|
||||
if (typeof value === 'object' && value._id != null) return String(value._id);
|
||||
return String(value);
|
||||
};
|
||||
|
||||
const stockAuditLineSchema = new Schema(
|
||||
{
|
||||
itemType: {
|
||||
type: String,
|
||||
enum: ['filament', 'part', 'product'],
|
||||
required: true,
|
||||
},
|
||||
item: { type: Schema.Types.ObjectId, refPath: 'auditLines.itemType', required: true },
|
||||
itemSku: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: function () {
|
||||
return ['filament', 'part', 'product'].includes(this.itemType)
|
||||
? this.itemType + 'Sku'
|
||||
: null;
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
current: { type: Number, required: true, default: 0 },
|
||||
actual: { type: Number, required: true, default: 0 },
|
||||
new: { type: Number, required: true, default: 0 },
|
||||
},
|
||||
{ _id: true }
|
||||
);
|
||||
|
||||
const stockAuditSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
type: { type: String, required: true },
|
||||
status: {
|
||||
type: String,
|
||||
enum: ['pending', 'in_progress', 'completed', 'cancelled'],
|
||||
default: 'pending',
|
||||
state: {
|
||||
type: { type: String, required: true, default: 'draft' },
|
||||
progress: { type: Number, required: false },
|
||||
},
|
||||
auditLevel: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'stockAuditLevel',
|
||||
required: true,
|
||||
},
|
||||
notes: { type: String },
|
||||
items: [stockAuditItemSchema],
|
||||
createdBy: { type: Schema.Types.ObjectId, ref: 'user', required: true },
|
||||
completedAt: { type: Date },
|
||||
stockLocation: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'stockLocation',
|
||||
required: true,
|
||||
},
|
||||
postedAt: { type: Date, required: false },
|
||||
auditLines: { type: [stockAuditLineSchema], default: [] },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
stockAuditSchema.index({ type: 'text', status: 'text', notes: 'text' });
|
||||
stockAuditSchema.index({ 'state.type': 'text' });
|
||||
|
||||
stockAuditSchema.statics.stats = async function () {
|
||||
const [draft, complete] = await Promise.all([
|
||||
this.countDocuments({ 'state.type': 'draft' }),
|
||||
this.countDocuments({ 'state.type': 'complete' }),
|
||||
]);
|
||||
return {
|
||||
draft: { count: draft },
|
||||
complete: { count: complete },
|
||||
};
|
||||
};
|
||||
|
||||
stockAuditSchema.statics.history = async function () {
|
||||
return [];
|
||||
};
|
||||
|
||||
async function fetchItemsForLevelLine(levelLine) {
|
||||
const itemType = levelLine.itemType;
|
||||
const itemModel = itemModelsByType[itemType];
|
||||
if (!itemModel) return [];
|
||||
|
||||
if (levelLine.allItems) {
|
||||
return itemModel.find().select('_id').lean();
|
||||
}
|
||||
|
||||
const itemId = toId(levelLine.item);
|
||||
if (!itemId) return [];
|
||||
return [{ _id: itemId }];
|
||||
}
|
||||
|
||||
async function fetchSkusForLevelLine(levelLine, itemId) {
|
||||
const itemType = levelLine.itemType;
|
||||
const skuModel = skuModelsByType[itemType];
|
||||
const parentField = parentFieldByType[itemType];
|
||||
if (!skuModel || !parentField) return [];
|
||||
|
||||
if (levelLine.allSkus) {
|
||||
return skuModel.find({ [parentField]: itemId }).select('_id').lean();
|
||||
}
|
||||
|
||||
const skuId = toId(levelLine.itemSku);
|
||||
if (!skuId) return [];
|
||||
return [{ _id: skuId }];
|
||||
}
|
||||
|
||||
export async function getCurrentQuantityAtLocation(itemType, itemSkuId, stockLocationId) {
|
||||
const locationId = toId(stockLocationId);
|
||||
const skuId = toId(itemSkuId);
|
||||
if (!locationId || !skuId) return 0;
|
||||
|
||||
if (itemType === 'filament') {
|
||||
const stocks = await mongoose
|
||||
.model('filamentStock')
|
||||
.find({ filamentSku: skuId, stockLocation: locationId })
|
||||
.select('currentWeight.net')
|
||||
.lean();
|
||||
return stocks.reduce((sum, stock) => sum + (Number(stock.currentWeight?.net) || 0), 0);
|
||||
}
|
||||
|
||||
if (itemType === 'part') {
|
||||
const stocks = await mongoose
|
||||
.model('partStock')
|
||||
.find({ partSku: skuId, stockLocation: locationId })
|
||||
.select('currentQuantity')
|
||||
.lean();
|
||||
return stocks.reduce((sum, stock) => sum + (Number(stock.currentQuantity) || 0), 0);
|
||||
}
|
||||
|
||||
if (itemType === 'product') {
|
||||
const stocks = await mongoose
|
||||
.model('productStock')
|
||||
.find({ productSku: skuId, stockLocation: locationId })
|
||||
.select('currentQuantity')
|
||||
.lean();
|
||||
return stocks.reduce((sum, stock) => sum + (Number(stock.currentQuantity) || 0), 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function buildAuditLineQuantities(current, actual) {
|
||||
const currentVal = Number(current) || 0;
|
||||
const actualVal = Number(actual) || 0;
|
||||
return {
|
||||
current: currentVal,
|
||||
actual: actualVal,
|
||||
new: actualVal,
|
||||
};
|
||||
}
|
||||
|
||||
function getExistingActual(line) {
|
||||
if (line?.actual != null) return Number(line.actual);
|
||||
if (line?.actualQuantity != null) return Number(line.actualQuantity);
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildAuditLineKey(itemType, itemId, itemSkuId) {
|
||||
return `${itemType}:${toId(itemId)}:${toId(itemSkuId)}`;
|
||||
}
|
||||
|
||||
async function expandLevelLinesToAuditLines(levelLines, stockLocationId, existingLines = []) {
|
||||
const existingByKey = new Map();
|
||||
for (const line of existingLines) {
|
||||
existingByKey.set(
|
||||
buildAuditLineKey(line.itemType, line.item, line.itemSku),
|
||||
line
|
||||
);
|
||||
}
|
||||
|
||||
const auditLines = [];
|
||||
|
||||
for (const levelLine of levelLines || []) {
|
||||
const items = await fetchItemsForLevelLine(levelLine);
|
||||
for (const item of items) {
|
||||
const itemId = toId(item._id);
|
||||
const skus = await fetchSkusForLevelLine(levelLine, itemId);
|
||||
for (const sku of skus) {
|
||||
const itemSkuId = toId(sku._id);
|
||||
const current = await getCurrentQuantityAtLocation(
|
||||
levelLine.itemType,
|
||||
itemSkuId,
|
||||
stockLocationId
|
||||
);
|
||||
const key = buildAuditLineKey(levelLine.itemType, itemId, itemSkuId);
|
||||
const existing = existingByKey.get(key);
|
||||
const existingActual = getExistingActual(existing);
|
||||
const actual = existingActual != null ? existingActual : current;
|
||||
|
||||
auditLines.push({
|
||||
itemType: levelLine.itemType,
|
||||
item: itemId,
|
||||
itemSku: itemSkuId,
|
||||
...buildAuditLineQuantities(current, actual),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return auditLines;
|
||||
}
|
||||
|
||||
stockAuditSchema.statics.recalculate = async function (stockAudit, user) {
|
||||
if (stockAudit?.state?.type !== 'draft') return;
|
||||
|
||||
const auditLevelId = toId(stockAudit.auditLevel?._id ?? stockAudit.auditLevel);
|
||||
const stockLocationId = toId(stockAudit.stockLocation?._id ?? stockAudit.stockLocation);
|
||||
if (!auditLevelId || !stockLocationId) return;
|
||||
|
||||
const auditLevel = await getObject({
|
||||
model: stockAuditLevelModel,
|
||||
id: auditLevelId,
|
||||
populate: [
|
||||
{ path: 'auditLines.item' },
|
||||
{ path: 'auditLines.itemSku' },
|
||||
],
|
||||
});
|
||||
|
||||
if (!auditLevel || auditLevel.error) return;
|
||||
|
||||
const auditLines = await expandLevelLinesToAuditLines(
|
||||
(auditLevel.auditLines || []).map((line) => normalizeAuditLevelLine(line)),
|
||||
stockLocationId,
|
||||
stockAudit.auditLines
|
||||
);
|
||||
|
||||
await editObject({
|
||||
model: this,
|
||||
id: stockAudit._id,
|
||||
updateData: { auditLines },
|
||||
user,
|
||||
recalculate: false,
|
||||
});
|
||||
};
|
||||
|
||||
// Add virtual id getter
|
||||
stockAuditSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
});
|
||||
|
||||
// Configure JSON serialization to include virtuals
|
||||
stockAuditSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
// Create and export the model
|
||||
export const stockAuditModel = mongoose.model('stockAudit', stockAuditSchema);
|
||||
|
||||
export async function updateDraftStockAuditCurrents({
|
||||
itemType,
|
||||
itemSkuId,
|
||||
stockLocationId,
|
||||
user,
|
||||
}) {
|
||||
const skuId = toId(itemSkuId);
|
||||
const locationId = toId(stockLocationId);
|
||||
if (!itemType || !skuId || !locationId) return;
|
||||
|
||||
const current = await getCurrentQuantityAtLocation(itemType, skuId, locationId);
|
||||
|
||||
const draftAudits = await stockAuditModel
|
||||
.find({
|
||||
'state.type': 'draft',
|
||||
stockLocation: locationId,
|
||||
})
|
||||
.lean();
|
||||
|
||||
for (const audit of draftAudits) {
|
||||
let changed = false;
|
||||
const auditLines = (audit.auditLines || []).map((line) => {
|
||||
if (line.itemType !== itemType || toId(line.itemSku) !== skuId) {
|
||||
return line;
|
||||
}
|
||||
const lineCurrent = Number(line.current) || 0;
|
||||
if (lineCurrent === current) {
|
||||
return line;
|
||||
}
|
||||
changed = true;
|
||||
return { ...line, current };
|
||||
});
|
||||
|
||||
if (!changed) continue;
|
||||
|
||||
await editObject({
|
||||
model: stockAuditModel,
|
||||
id: audit._id,
|
||||
updateData: { auditLines },
|
||||
user,
|
||||
recalculate: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
const stockEventSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
value: { type: Number, required: true },
|
||||
unit: { type: String, required: true },
|
||||
parent: {
|
||||
type: Schema.Types.ObjectId,
|
||||
refPath: 'parentType',
|
||||
required: true,
|
||||
},
|
||||
parentType: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: ['filamentStock', 'partStock', 'productStock'], // Add other models as needed
|
||||
},
|
||||
owner: {
|
||||
type: Schema.Types.ObjectId,
|
||||
refPath: 'ownerType',
|
||||
required: true,
|
||||
},
|
||||
ownerType: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: ['user', 'subJob', 'stockAudit'],
|
||||
},
|
||||
timestamp: { type: Date, default: Date.now },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
// Add virtual id getter
|
||||
stockEventSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
});
|
||||
|
||||
// Configure JSON serialization to include virtuals
|
||||
stockEventSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
// Create and export the model
|
||||
export const stockEventModel = mongoose.model('stockEvent', stockEventSchema);
|
||||
108
src/database/schemas/management/stockauditlevel.schema.js
Normal file
108
src/database/schemas/management/stockauditlevel.schema.js
Normal file
@ -0,0 +1,108 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
import { editObject } from '../../database.js';
|
||||
|
||||
const { Schema } = mongoose;
|
||||
|
||||
const toId = (value) => {
|
||||
if (value == null) return null;
|
||||
if (typeof value === 'object' && value._id != null) return String(value._id);
|
||||
return String(value);
|
||||
};
|
||||
|
||||
export function normalizeAuditLevelLine(line) {
|
||||
const allItems = Boolean(line?.allItems);
|
||||
const allSkus = allItems ? true : Boolean(line?.allSkus);
|
||||
const item = allItems ? null : line?.item?._id ?? line?.item ?? null;
|
||||
const itemSku = allItems || allSkus ? null : line?.itemSku?._id ?? line?.itemSku ?? null;
|
||||
|
||||
return {
|
||||
_id: line?._id,
|
||||
itemType: line?.itemType,
|
||||
allItems,
|
||||
allSkus,
|
||||
item,
|
||||
itemSku,
|
||||
};
|
||||
}
|
||||
|
||||
function auditLevelLineChanged(before, after) {
|
||||
return (
|
||||
Boolean(before?.allItems) !== Boolean(after.allItems) ||
|
||||
Boolean(before?.allSkus) !== Boolean(after.allSkus) ||
|
||||
toId(before?.item) !== toId(after.item) ||
|
||||
toId(before?.itemSku) !== toId(after.itemSku)
|
||||
);
|
||||
}
|
||||
|
||||
const stockAuditLevelLineSchema = new Schema(
|
||||
{
|
||||
itemType: {
|
||||
type: String,
|
||||
enum: ['filament', 'part', 'product'],
|
||||
required: true,
|
||||
},
|
||||
allItems: { type: Boolean, default: false },
|
||||
item: { type: Schema.Types.ObjectId, refPath: 'auditLines.itemType', required: false },
|
||||
allSkus: { type: Boolean, default: false },
|
||||
itemSku: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: function () {
|
||||
return ['filament', 'part', 'product'].includes(this.itemType)
|
||||
? this.itemType + 'Sku'
|
||||
: null;
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
{ _id: true }
|
||||
);
|
||||
|
||||
const stockAuditLevelSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
name: { type: String, required: true },
|
||||
tags: [{ type: String }],
|
||||
auditLines: { type: [stockAuditLevelLineSchema], default: [] },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
stockAuditLevelSchema.index({ name: 'text', tags: 'text' });
|
||||
|
||||
stockAuditLevelSchema.statics.stats = async function () {
|
||||
const count = await this.countDocuments();
|
||||
return { total: { count } };
|
||||
};
|
||||
|
||||
stockAuditLevelSchema.statics.history = async function () {
|
||||
return [];
|
||||
};
|
||||
|
||||
stockAuditLevelSchema.statics.recalculate = async function (stockAuditLevel, user) {
|
||||
if (!stockAuditLevel?._id) return;
|
||||
|
||||
const auditLines = stockAuditLevel.auditLines || [];
|
||||
const normalizedLines = auditLines.map((line) => normalizeAuditLevelLine(line));
|
||||
const changed = auditLines.some((line, index) =>
|
||||
auditLevelLineChanged(line, normalizedLines[index])
|
||||
);
|
||||
|
||||
if (!changed) return;
|
||||
|
||||
await editObject({
|
||||
model: this,
|
||||
id: stockAuditLevel._id,
|
||||
updateData: { auditLines: normalizedLines },
|
||||
user,
|
||||
recalculate: false,
|
||||
});
|
||||
};
|
||||
|
||||
stockAuditLevelSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
});
|
||||
|
||||
stockAuditLevelSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
export const stockAuditLevelModel = mongoose.model('stockAuditLevel', stockAuditLevelSchema);
|
||||
@ -18,6 +18,7 @@ import { purchaseOrderModel } from './inventory/purchaseorder.schema.js';
|
||||
import { orderItemModel } from './inventory/orderitem.schema.js';
|
||||
import { stockEventModel } from './inventory/stockevent.schema.js';
|
||||
import { stockAuditModel } from './inventory/stockaudit.schema.js';
|
||||
import { stockAuditLevelModel } from './management/stockauditlevel.schema.js';
|
||||
import { partStockModel } from './inventory/partstock.schema.js';
|
||||
import { productStockModel } from './inventory/productstock.schema.js';
|
||||
import { stockLocationModel } from './inventory/stocklocation.schema.js';
|
||||
@ -88,6 +89,7 @@ export const models = {
|
||||
FLS: modelEntry(() => filamentStockModel, 'filamentStock', 'Filament Stock'),
|
||||
SEV: modelEntry(() => stockEventModel, 'stockEvent', 'Stock Event'),
|
||||
SAU: modelEntry(() => stockAuditModel, 'stockAudit', 'Stock Audit'),
|
||||
SAL: modelEntry(() => stockAuditLevelModel, 'stockAuditLevel', 'Stock Audit Level'),
|
||||
PTS: modelEntry(() => partStockModel, 'partStock', 'Part Stock'),
|
||||
PDS: modelEntry(() => productStockModel, 'productStock', 'Product Stock'),
|
||||
SLN: modelEntry(() => stockLocationModel, 'stockLocation', 'Stock Location'),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user