Added missing SKUs.
This commit is contained in:
parent
73fbb50b34
commit
7eb774a297
@ -19,7 +19,7 @@ const filamentStockSchema = new Schema(
|
||||
net: { type: Number, required: true },
|
||||
gross: { type: Number, required: true },
|
||||
},
|
||||
filament: { type: mongoose.Schema.Types.ObjectId, ref: 'filament', required: true },
|
||||
filamentSku: { type: mongoose.Schema.Types.ObjectId, ref: 'filamentSku', required: true },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
@ -2,6 +2,12 @@ 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 { 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';
|
||||
import {
|
||||
aggregateRollups,
|
||||
aggregateRollupsHistory,
|
||||
@ -11,6 +17,18 @@ import {
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
const skuModelsByItemType = {
|
||||
filament: filamentSkuModel,
|
||||
part: partSkuModel,
|
||||
product: productSkuModel,
|
||||
};
|
||||
|
||||
const parentModelsByItemType = {
|
||||
filament: filamentModel,
|
||||
part: partModel,
|
||||
product: productModel,
|
||||
};
|
||||
|
||||
const orderItemSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
@ -21,7 +39,16 @@ const orderItemSchema = new Schema(
|
||||
},
|
||||
order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
|
||||
itemType: { type: String, required: true },
|
||||
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true },
|
||||
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: false },
|
||||
sku: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: function () {
|
||||
return ['filament', 'part', 'product'].includes(this.itemType)
|
||||
? this.itemType + 'Sku'
|
||||
: null;
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
syncAmount: { type: String, required: false, default: null },
|
||||
itemAmount: { type: Number, required: true },
|
||||
quantity: { type: Number, required: true },
|
||||
@ -88,9 +115,55 @@ orderItemSchema.statics.recalculate = async function (orderItem, user) {
|
||||
return;
|
||||
}
|
||||
|
||||
var taxRate = orderItem.taxRate;
|
||||
// If SKU present and syncAmount is set, check if override is on for the price mode and use that price instead
|
||||
let effectiveItemAmount = orderItem.itemAmount;
|
||||
const syncAmount = orderItem.syncAmount;
|
||||
const skuId = orderItem.sku?._id || orderItem.sku;
|
||||
const itemType = orderItem.itemType;
|
||||
if (syncAmount && skuId && itemType && ['filament', 'part', 'product'].includes(itemType)) {
|
||||
const skuModel = skuModelsByItemType[itemType];
|
||||
const parentModel = parentModelsByItemType[itemType];
|
||||
if (skuModel && parentModel) {
|
||||
const sku = await getObject({
|
||||
model: skuModel,
|
||||
id: skuId,
|
||||
cached: true,
|
||||
});
|
||||
if (sku) {
|
||||
const parentId = sku.part?._id || sku.part || sku.product?._id || sku.product || sku.filament?._id || sku.filament;
|
||||
if (syncAmount === 'itemCost') {
|
||||
if (sku.overrideCost && sku.cost != null) {
|
||||
effectiveItemAmount = sku.cost;
|
||||
} else if (parentId) {
|
||||
const parent = await getObject({
|
||||
model: parentModel,
|
||||
id: parentId,
|
||||
cached: true,
|
||||
});
|
||||
if (parent && parent.cost != null) {
|
||||
effectiveItemAmount = parent.cost;
|
||||
}
|
||||
}
|
||||
} else if (syncAmount === 'itemPrice' && itemType !== 'filament') {
|
||||
if (sku.overridePrice && sku.price != null) {
|
||||
effectiveItemAmount = sku.price;
|
||||
} else if (parentId) {
|
||||
const parent = await getObject({
|
||||
model: parentModel,
|
||||
id: parentId,
|
||||
cached: true,
|
||||
});
|
||||
if (parent && parent.price != null) {
|
||||
effectiveItemAmount = parent.price;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (orderItem.taxRate?._id && Object.keys(orderItem.taxRate).length == 1) {
|
||||
let taxRate = orderItem.taxRate;
|
||||
if (orderItem.taxRate?._id && Object.keys(orderItem.taxRate).length === 1) {
|
||||
taxRate = await getObject({
|
||||
model: taxRateModel,
|
||||
id: orderItem.taxRate._id,
|
||||
@ -98,18 +171,25 @@ orderItemSchema.statics.recalculate = async function (orderItem, user) {
|
||||
});
|
||||
}
|
||||
|
||||
const orderTotalAmount = orderItem.itemAmount * orderItem.quantity;
|
||||
const orderTotalAmount = effectiveItemAmount * orderItem.quantity;
|
||||
const orderTotalAmountWithTax = orderTotalAmount * (1 + (taxRate?.rate || 0) / 100);
|
||||
await editObject({
|
||||
model: orderItemModel,
|
||||
id: orderItem._id,
|
||||
updateData: {
|
||||
|
||||
const orderItemUpdateData = {
|
||||
totalAmount: orderTotalAmount,
|
||||
totalAmountWithTax: orderTotalAmountWithTax,
|
||||
invoicedAmountRemaining: orderTotalAmount - orderItem.invoicedAmount,
|
||||
invoicedAmountWithTaxRemaining: orderTotalAmountWithTax - orderItem.invoicedAmountWithTax,
|
||||
invoicedQuantityRemaining: orderItem.quantity - orderItem.invoicedQuantity,
|
||||
totalAmount: orderTotalAmount,
|
||||
totalAmountWithTax: orderTotalAmountWithTax,
|
||||
},
|
||||
};
|
||||
if (effectiveItemAmount !== orderItem.itemAmount) {
|
||||
orderItemUpdateData.itemAmount = effectiveItemAmount;
|
||||
orderItem.itemAmount = effectiveItemAmount;
|
||||
}
|
||||
|
||||
await editObject({
|
||||
model: this,
|
||||
id: orderItem._id,
|
||||
updateData: orderItemUpdateData,
|
||||
user,
|
||||
recalculate: false,
|
||||
});
|
||||
|
||||
@ -2,24 +2,21 @@ import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
// Filament base - cost and tax; color and cost override at FilamentSKU
|
||||
const filamentSchema = new mongoose.Schema({
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
name: { required: true, type: String },
|
||||
barcode: { required: false, type: String },
|
||||
url: { required: false, type: String },
|
||||
image: { required: false, type: Buffer },
|
||||
color: { required: true, type: String },
|
||||
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
|
||||
type: { required: true, type: String },
|
||||
cost: { required: true, type: Number },
|
||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: true },
|
||||
costWithTax: { required: true, type: Number },
|
||||
diameter: { required: true, type: Number },
|
||||
density: { required: true, type: Number },
|
||||
createdAt: { required: true, type: Date },
|
||||
updatedAt: { required: true, type: Date },
|
||||
emptySpoolWeight: { required: true, type: Number },
|
||||
});
|
||||
cost: { type: Number, required: false },
|
||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
costWithTax: { type: Number, required: false },
|
||||
}, { timestamps: true });
|
||||
|
||||
filamentSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
@ -27,4 +24,21 @@ filamentSchema.virtual('id').get(function () {
|
||||
|
||||
filamentSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
filamentSchema.statics.recalculate = async function (filament, user) {
|
||||
const orderItemModel = mongoose.model('orderItem');
|
||||
const itemId = filament._id;
|
||||
const draftOrderItems = await orderItemModel
|
||||
.find({
|
||||
'state.type': 'draft',
|
||||
itemType: 'filament',
|
||||
item: itemId,
|
||||
})
|
||||
.populate('order')
|
||||
.lean();
|
||||
|
||||
for (const orderItem of draftOrderItems) {
|
||||
await orderItemModel.recalculate(orderItem, user);
|
||||
}
|
||||
};
|
||||
|
||||
export const filamentModel = mongoose.model('filament', filamentSchema);
|
||||
|
||||
48
src/database/schemas/management/filamentsku.schema.js
Normal file
48
src/database/schemas/management/filamentsku.schema.js
Normal file
@ -0,0 +1,48 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
// Define the main filament SKU schema - color and cost live at SKU level
|
||||
const filamentSkuSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
barcode: { type: String, required: false },
|
||||
filament: { type: Schema.Types.ObjectId, ref: 'filament', required: true },
|
||||
name: { type: String, required: true },
|
||||
description: { type: String, required: false },
|
||||
color: { type: String, required: true },
|
||||
cost: { type: Number, required: false },
|
||||
overrideCost: { type: Boolean, default: false },
|
||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
costWithTax: { type: Number, required: false },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
// Add virtual id getter
|
||||
filamentSkuSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
});
|
||||
|
||||
// Configure JSON serialization to include virtuals
|
||||
filamentSkuSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
filamentSkuSchema.statics.recalculate = async function (filamentSku, user) {
|
||||
const orderItemModel = mongoose.model('orderItem');
|
||||
const skuId = filamentSku._id;
|
||||
const draftOrderItems = await orderItemModel
|
||||
.find({
|
||||
'state.type': 'draft',
|
||||
itemType: 'filament',
|
||||
sku: skuId,
|
||||
})
|
||||
.populate('order')
|
||||
.lean();
|
||||
|
||||
for (const orderItem of draftOrderItems) {
|
||||
await orderItemModel.recalculate(orderItem, user);
|
||||
}
|
||||
};
|
||||
|
||||
// Create and export the model
|
||||
export const filamentSkuModel = mongoose.model('filamentSku', filamentSkuSchema);
|
||||
@ -2,13 +2,22 @@ import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
// Define the main part schema - pricing moved to PartSku
|
||||
// Define the main part schema - cost/price and tax; override at PartSku
|
||||
const partSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
name: { type: String, required: true },
|
||||
fileName: { type: String, required: false },
|
||||
file: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', required: false },
|
||||
cost: { type: Number, required: false },
|
||||
price: { type: Number, required: false },
|
||||
priceMode: { type: String, default: 'margin' },
|
||||
margin: { type: Number, required: false },
|
||||
amount: { type: Number, required: false },
|
||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
costWithTax: { type: Number, required: false },
|
||||
priceWithTax: { type: Number, required: false },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
@ -21,5 +30,22 @@ partSchema.virtual('id').get(function () {
|
||||
// Configure JSON serialization to include virtuals
|
||||
partSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
partSchema.statics.recalculate = async function (part, user) {
|
||||
const orderItemModel = mongoose.model('orderItem');
|
||||
const itemId = part._id;
|
||||
const draftOrderItems = await orderItemModel
|
||||
.find({
|
||||
'state.type': 'draft',
|
||||
itemType: 'part',
|
||||
item: itemId,
|
||||
})
|
||||
.populate('order')
|
||||
.lean();
|
||||
|
||||
for (const orderItem of draftOrderItems) {
|
||||
await orderItemModel.recalculate(orderItem, user);
|
||||
}
|
||||
};
|
||||
|
||||
// Create and export the model
|
||||
export const partModel = mongoose.model('part', partSchema);
|
||||
|
||||
@ -6,16 +6,17 @@ const { Schema } = mongoose;
|
||||
const partSkuSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
sku: { type: String, required: true },
|
||||
barcode: { type: String, required: false },
|
||||
part: { type: Schema.Types.ObjectId, ref: 'part', required: true },
|
||||
name: { type: String, required: true },
|
||||
description: { type: String, required: false },
|
||||
priceMode: { type: String, default: 'margin' },
|
||||
price: { type: Number, required: false },
|
||||
cost: { type: Number, required: false },
|
||||
overrideCost: { type: Boolean, default: false },
|
||||
overridePrice: { type: Boolean, default: false },
|
||||
margin: { type: Number, required: false },
|
||||
amount: { type: Number, required: false },
|
||||
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: false },
|
||||
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
priceWithTax: { type: Number, required: false },
|
||||
@ -32,5 +33,22 @@ partSkuSchema.virtual('id').get(function () {
|
||||
// Configure JSON serialization to include virtuals
|
||||
partSkuSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
partSkuSchema.statics.recalculate = async function (partSku, user) {
|
||||
const orderItemModel = mongoose.model('orderItem');
|
||||
const skuId = partSku._id;
|
||||
const draftOrderItems = await orderItemModel
|
||||
.find({
|
||||
'state.type': 'draft',
|
||||
itemType: 'part',
|
||||
sku: skuId,
|
||||
})
|
||||
.populate('order')
|
||||
.lean();
|
||||
|
||||
for (const orderItem of draftOrderItems) {
|
||||
await orderItemModel.recalculate(orderItem, user);
|
||||
}
|
||||
};
|
||||
|
||||
// Create and export the model
|
||||
export const partSkuModel = mongoose.model('partSku', partSkuSchema);
|
||||
|
||||
@ -10,6 +10,15 @@ const productSchema = new Schema(
|
||||
tags: [{ type: String }],
|
||||
version: { type: String },
|
||||
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
|
||||
cost: { type: Number, required: false },
|
||||
price: { type: Number, required: false },
|
||||
priceMode: { type: String, default: 'margin' },
|
||||
margin: { type: Number, required: false },
|
||||
amount: { type: Number, required: false },
|
||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
costWithTax: { type: Number, required: false },
|
||||
priceWithTax: { type: Number, required: false },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
@ -21,5 +30,22 @@ productSchema.virtual('id').get(function () {
|
||||
// Configure JSON serialization to include virtuals
|
||||
productSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
productSchema.statics.recalculate = async function (product, user) {
|
||||
const orderItemModel = mongoose.model('orderItem');
|
||||
const itemId = product._id;
|
||||
const draftOrderItems = await orderItemModel
|
||||
.find({
|
||||
'state.type': 'draft',
|
||||
itemType: 'product',
|
||||
item: itemId,
|
||||
})
|
||||
.populate('order')
|
||||
.lean();
|
||||
|
||||
for (const orderItem of draftOrderItems) {
|
||||
await orderItemModel.recalculate(orderItem, user);
|
||||
}
|
||||
};
|
||||
|
||||
// Create and export the model
|
||||
export const productModel = mongoose.model('product', productSchema);
|
||||
|
||||
@ -11,16 +11,17 @@ const partSkuUsageSchema = new Schema({
|
||||
const productSkuSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
sku: { type: String, required: true },
|
||||
barcode: { type: String, required: false },
|
||||
product: { type: Schema.Types.ObjectId, ref: 'product', required: true },
|
||||
name: { type: String, required: true },
|
||||
description: { type: String, required: false },
|
||||
priceMode: { type: String, default: 'margin' },
|
||||
price: { type: Number, required: false },
|
||||
cost: { type: Number, required: false },
|
||||
overrideCost: { type: Boolean, default: false },
|
||||
overridePrice: { type: Boolean, default: false },
|
||||
margin: { type: Number, required: false },
|
||||
amount: { type: Number, required: false },
|
||||
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: false },
|
||||
parts: [partSkuUsageSchema],
|
||||
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
@ -38,5 +39,22 @@ productSkuSchema.virtual('id').get(function () {
|
||||
// Configure JSON serialization to include virtuals
|
||||
productSkuSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
productSkuSchema.statics.recalculate = async function (productSku, user) {
|
||||
const orderItemModel = mongoose.model('orderItem');
|
||||
const skuId = productSku._id;
|
||||
const draftOrderItems = await orderItemModel
|
||||
.find({
|
||||
'state.type': 'draft',
|
||||
itemType: 'product',
|
||||
sku: skuId,
|
||||
})
|
||||
.populate('order')
|
||||
.lean();
|
||||
|
||||
for (const orderItem of draftOrderItems) {
|
||||
await orderItemModel.recalculate(orderItem, user);
|
||||
}
|
||||
};
|
||||
|
||||
// Create and export the model
|
||||
export const productSkuModel = mongoose.model('productSku', productSkuSchema);
|
||||
|
||||
@ -2,6 +2,7 @@ import { jobModel } from './production/job.schema.js';
|
||||
import { subJobModel } from './production/subjob.schema.js';
|
||||
import { printerModel } from './production/printer.schema.js';
|
||||
import { filamentModel } from './management/filament.schema.js';
|
||||
import { filamentSkuModel } from './management/filamentsku.schema.js';
|
||||
import { gcodeFileModel } from './production/gcodefile.schema.js';
|
||||
import { partModel } from './management/part.schema.js';
|
||||
import { partSkuModel } from './management/partsku.schema.js';
|
||||
@ -53,6 +54,13 @@ export const models = {
|
||||
referenceField: '_reference',
|
||||
label: 'Filament',
|
||||
},
|
||||
FSU: {
|
||||
model: filamentSkuModel,
|
||||
idField: '_id',
|
||||
type: 'filamentSku',
|
||||
referenceField: '_reference',
|
||||
label: 'Filament SKU',
|
||||
},
|
||||
GCF: {
|
||||
model: gcodeFileModel,
|
||||
idField: '_id',
|
||||
|
||||
@ -13,7 +13,7 @@ const gcodeFileSchema = new mongoose.Schema(
|
||||
name: { required: true, type: String },
|
||||
gcodeFileName: { required: false, type: String },
|
||||
size: { type: Number, required: false },
|
||||
filament: { type: Schema.Types.ObjectId, ref: 'filament', required: true },
|
||||
filamentSku: { type: Schema.Types.ObjectId, ref: 'filamentSku', required: true },
|
||||
parts: [partSchema],
|
||||
file: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', required: false },
|
||||
cost: { type: Number, required: false },
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
subJobRoutes,
|
||||
gcodeFileRoutes,
|
||||
filamentRoutes,
|
||||
filamentSkuRoutes,
|
||||
spotlightRoutes,
|
||||
partRoutes,
|
||||
partSkuRoutes,
|
||||
@ -133,6 +134,7 @@ app.use('/jobs', jobRoutes);
|
||||
app.use('/subjobs', subJobRoutes);
|
||||
app.use('/gcodefiles', gcodeFileRoutes);
|
||||
app.use('/filaments', filamentRoutes);
|
||||
app.use('/filamentskus', filamentSkuRoutes);
|
||||
app.use('/parts', partRoutes);
|
||||
app.use('/partskus', partSkuRoutes);
|
||||
app.use('/products', productRoutes);
|
||||
|
||||
@ -8,6 +8,7 @@ import jobRoutes from './production/jobs.js';
|
||||
import subJobRoutes from './production/subjobs.js';
|
||||
import gcodeFileRoutes from './production/gcodefiles.js';
|
||||
import filamentRoutes from './management/filaments.js';
|
||||
import filamentSkuRoutes from './management/filamentskus.js';
|
||||
import spotlightRoutes from './misc/spotlight.js';
|
||||
import partRoutes from './management/parts.js';
|
||||
import partSkuRoutes from './management/partskus.js';
|
||||
@ -55,6 +56,7 @@ export {
|
||||
subJobRoutes,
|
||||
gcodeFileRoutes,
|
||||
filamentRoutes,
|
||||
filamentSkuRoutes,
|
||||
spotlightRoutes,
|
||||
partRoutes,
|
||||
partSkuRoutes,
|
||||
|
||||
@ -18,14 +18,14 @@ import {
|
||||
// list of filament stocks
|
||||
router.get('/', isAuthenticated, (req, res) => {
|
||||
const { page, limit, property, search, sort, order } = req.query;
|
||||
const allowedFilters = ['filament', 'state', 'startingWeight', 'currentWeight', 'filament._id'];
|
||||
const allowedFilters = ['filamentSku', 'state', 'startingWeight', 'currentWeight', 'filamentSku._id'];
|
||||
const filter = getFilter(req.query, allowedFilters);
|
||||
listFilamentStocksRouteHandler(req, res, page, limit, property, filter, search, sort, order);
|
||||
});
|
||||
|
||||
router.get('/properties', isAuthenticated, (req, res) => {
|
||||
let properties = convertPropertiesString(req.query.properties);
|
||||
const allowedFilters = ['filament', 'state.type'];
|
||||
const allowedFilters = ['filamentSku', 'state.type'];
|
||||
const filter = getFilter(req.query, allowedFilters, false);
|
||||
var masterFilter = {};
|
||||
if (req.query.masterFilter) {
|
||||
|
||||
59
src/routes/management/filamentskus.js
Normal file
59
src/routes/management/filamentskus.js
Normal file
@ -0,0 +1,59 @@
|
||||
import express from 'express';
|
||||
import { isAuthenticated } from '../../keycloak.js';
|
||||
import { getFilter, convertPropertiesString } from '../../utils.js';
|
||||
|
||||
const router = express.Router();
|
||||
import {
|
||||
listFilamentSkusRouteHandler,
|
||||
getFilamentSkuRouteHandler,
|
||||
editFilamentSkuRouteHandler,
|
||||
newFilamentSkuRouteHandler,
|
||||
deleteFilamentSkuRouteHandler,
|
||||
listFilamentSkusByPropertiesRouteHandler,
|
||||
getFilamentSkuStatsRouteHandler,
|
||||
getFilamentSkuHistoryRouteHandler,
|
||||
} from '../../services/management/filamentskus.js';
|
||||
|
||||
router.get('/', isAuthenticated, (req, res) => {
|
||||
const { page, limit, property, search, sort, order } = req.query;
|
||||
const allowedFilters = ['_id', 'barcode', 'filament', 'filament._id', 'name', 'color', 'cost'];
|
||||
const filter = getFilter(req.query, allowedFilters);
|
||||
listFilamentSkusRouteHandler(req, res, page, limit, property, filter, search, sort, order);
|
||||
});
|
||||
|
||||
router.get('/properties', isAuthenticated, (req, res) => {
|
||||
let properties = convertPropertiesString(req.query.properties);
|
||||
const allowedFilters = ['filament', 'filament._id'];
|
||||
const filter = getFilter(req.query, allowedFilters, false);
|
||||
let masterFilter = {};
|
||||
if (req.query.masterFilter) {
|
||||
masterFilter = JSON.parse(req.query.masterFilter);
|
||||
}
|
||||
listFilamentSkusByPropertiesRouteHandler(req, res, properties, filter, masterFilter);
|
||||
});
|
||||
|
||||
router.post('/', isAuthenticated, (req, res) => {
|
||||
newFilamentSkuRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getFilamentSkuStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getFilamentSkuHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getFilamentSkuRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.put('/:id', isAuthenticated, async (req, res) => {
|
||||
editFilamentSkuRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.delete('/:id', isAuthenticated, async (req, res) => {
|
||||
deleteFilamentSkuRouteHandler(req, res);
|
||||
});
|
||||
|
||||
export default router;
|
||||
@ -16,7 +16,7 @@ import {
|
||||
|
||||
router.get('/', isAuthenticated, (req, res) => {
|
||||
const { page, limit, property, search, sort, order } = req.query;
|
||||
const allowedFilters = ['_id', 'sku', 'part', 'part._id', 'name', 'cost', 'price'];
|
||||
const allowedFilters = ['_id', 'barcode', 'part', 'part._id', 'name', 'cost', 'price'];
|
||||
const filter = getFilter(req.query, allowedFilters);
|
||||
listPartSkusRouteHandler(req, res, page, limit, property, filter, search, sort, order);
|
||||
});
|
||||
|
||||
@ -16,7 +16,7 @@ import {
|
||||
|
||||
router.get('/', isAuthenticated, (req, res) => {
|
||||
const { page, limit, property, search, sort, order } = req.query;
|
||||
const allowedFilters = ['_id', 'sku', 'product', 'product._id', 'name', 'cost', 'price'];
|
||||
const allowedFilters = ['_id', 'barcode', 'product', 'product._id', 'name', 'cost', 'price'];
|
||||
const filter = getFilter(req.query, allowedFilters);
|
||||
listProductSkusRouteHandler(req, res, page, limit, property, filter, search, sort, order);
|
||||
});
|
||||
|
||||
@ -36,7 +36,7 @@ export const listFilamentStocksRouteHandler = async (
|
||||
search,
|
||||
sort,
|
||||
order,
|
||||
populate: [{ path: 'filament' }],
|
||||
populate: [{ path: 'filamentSku' }],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -60,7 +60,7 @@ export const listFilamentStocksByPropertiesRouteHandler = async (
|
||||
model: filamentStockModel,
|
||||
properties,
|
||||
filter,
|
||||
populate: ['filament'],
|
||||
populate: ['filamentSku'],
|
||||
masterFilter,
|
||||
});
|
||||
|
||||
@ -79,7 +79,7 @@ export const getFilamentStockRouteHandler = async (req, res) => {
|
||||
const result = await getObject({
|
||||
model: filamentStockModel,
|
||||
id,
|
||||
populate: [{ path: 'filament' }],
|
||||
populate: [{ path: 'filamentSku' }],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`Filament Stock not found with supplied id.`);
|
||||
@ -146,7 +146,7 @@ export const newFilamentStockRouteHandler = async (req, res) => {
|
||||
updatedAt: new Date(),
|
||||
startingWeight: req.body.startingWeight,
|
||||
currentWeight: req.body.currentWeight,
|
||||
filament: req.body.filament,
|
||||
filamentSku: req.body.filamentSku,
|
||||
state: req.body.state,
|
||||
};
|
||||
const result = await newObject({
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import config from '../../config.js';
|
||||
import { orderItemModel } from '../../database/schemas/inventory/orderitem.schema.js';
|
||||
import { getModelByName } from '../misc/model.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -50,11 +51,39 @@ export const listOrderItemsRouteHandler = async (
|
||||
},
|
||||
{
|
||||
path: 'item',
|
||||
populate: { path: 'costTaxRate', strictPopulate: false },
|
||||
populate: [
|
||||
{ path: 'costTaxRate', strictPopulate: false },
|
||||
{ path: 'priceTaxRate', strictPopulate: false },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'item',
|
||||
populate: { path: 'priceTaxRate', strictPopulate: false },
|
||||
path: 'sku',
|
||||
strictPopulate: false,
|
||||
populate: [
|
||||
{
|
||||
path: 'filament',
|
||||
populate: { path: 'costTaxRate', strictPopulate: false },
|
||||
strictPopulate: false,
|
||||
},
|
||||
{
|
||||
path: 'part',
|
||||
populate: [
|
||||
{ path: 'costTaxRate', strictPopulate: false },
|
||||
{ path: 'priceTaxRate', strictPopulate: false },
|
||||
],
|
||||
strictPopulate: false,
|
||||
},
|
||||
{
|
||||
path: 'product',
|
||||
populate: [
|
||||
{ path: 'costTaxRate', strictPopulate: false },
|
||||
{ path: 'priceTaxRate', strictPopulate: false },
|
||||
],
|
||||
strictPopulate: false,
|
||||
},
|
||||
{ path: 'costTaxRate', strictPopulate: false },
|
||||
{ path: 'priceTaxRate', strictPopulate: false },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -109,14 +138,41 @@ export const getOrderItemRouteHandler = async (req, res) => {
|
||||
},
|
||||
{
|
||||
path: 'item',
|
||||
populate: [
|
||||
{ path: 'costTaxRate', strictPopulate: false },
|
||||
{ path: 'priceTaxRate', strictPopulate: false },
|
||||
],
|
||||
strictPopulate: false,
|
||||
},
|
||||
{
|
||||
path: 'sku',
|
||||
strictPopulate: false,
|
||||
populate: [
|
||||
{
|
||||
path: 'filament',
|
||||
populate: { path: 'costTaxRate', strictPopulate: false },
|
||||
strictPopulate: false,
|
||||
},
|
||||
{
|
||||
path: 'item',
|
||||
populate: { path: 'priceTaxRate', strictPopulate: false },
|
||||
path: 'part',
|
||||
populate: [
|
||||
{ path: 'costTaxRate', strictPopulate: false },
|
||||
{ path: 'priceTaxRate', strictPopulate: false },
|
||||
],
|
||||
strictPopulate: false,
|
||||
},
|
||||
{
|
||||
path: 'product',
|
||||
populate: [
|
||||
{ path: 'costTaxRate', strictPopulate: false },
|
||||
{ path: 'priceTaxRate', strictPopulate: false },
|
||||
],
|
||||
strictPopulate: false,
|
||||
},
|
||||
{ path: 'costTaxRate', strictPopulate: false },
|
||||
{ path: 'priceTaxRate', strictPopulate: false },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
if (result?.error) {
|
||||
@ -133,11 +189,39 @@ export const editOrderItemRouteHandler = async (req, res) => {
|
||||
|
||||
logger.trace(`Order Item with ID: ${id}`);
|
||||
|
||||
const skuType =
|
||||
req.body.sku && req.body.itemType ? req.body.itemType + 'Sku' : null;
|
||||
|
||||
let name = req.body.name;
|
||||
if (!name && req.body.sku && skuType) {
|
||||
const skuEntry = getModelByName(skuType);
|
||||
if (skuEntry?.model) {
|
||||
const sku = await getObject({
|
||||
model: skuEntry.model,
|
||||
id: req.body.sku,
|
||||
cached: true,
|
||||
});
|
||||
name = sku?.name;
|
||||
}
|
||||
}
|
||||
if (!name && req.body.item && req.body.itemType) {
|
||||
const itemEntry = getModelByName(req.body.itemType);
|
||||
if (itemEntry?.model) {
|
||||
const item = await getObject({
|
||||
model: itemEntry.model,
|
||||
id: req.body.item,
|
||||
cached: true,
|
||||
});
|
||||
name = item?.name;
|
||||
}
|
||||
}
|
||||
|
||||
const updateData = {
|
||||
updatedAt: new Date(),
|
||||
name: req.body.name,
|
||||
name: req.body.name ?? name,
|
||||
itemType: req.body.itemType,
|
||||
item: req.body.item,
|
||||
sku: req.body.sku,
|
||||
orderType: req.body.orderType,
|
||||
order: req.body.order,
|
||||
syncAmount: req.body.syncAmount,
|
||||
@ -158,7 +242,7 @@ export const editOrderItemRouteHandler = async (req, res) => {
|
||||
|
||||
if (result.error) {
|
||||
logger.error('Error editing order item:', result.error);
|
||||
res.status(result).send(result);
|
||||
res.status(result.code || 500).send(result);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -173,6 +257,7 @@ export const editMultipleOrderItemsRouteHandler = async (req, res) => {
|
||||
name: update.name,
|
||||
itemType: update.itemType,
|
||||
item: update.item,
|
||||
sku: update.sku,
|
||||
orderType: update.orderType,
|
||||
order: update.order,
|
||||
syncAmount: update.syncAmount,
|
||||
@ -206,13 +291,41 @@ export const editMultipleOrderItemsRouteHandler = async (req, res) => {
|
||||
};
|
||||
|
||||
export const newOrderItemRouteHandler = async (req, res) => {
|
||||
const skuType =
|
||||
req.body.sku && req.body.itemType ? req.body.itemType + 'Sku' : null;
|
||||
|
||||
let name = req.body.name;
|
||||
if (!name && req.body.sku && skuType) {
|
||||
const skuEntry = getModelByName(skuType);
|
||||
if (skuEntry?.model) {
|
||||
const sku = await getObject({
|
||||
model: skuEntry.model,
|
||||
id: req.body.sku,
|
||||
cached: true,
|
||||
});
|
||||
name = sku?.name;
|
||||
}
|
||||
}
|
||||
if (!name && req.body.item && req.body.itemType) {
|
||||
const itemEntry = getModelByName(req.body.itemType);
|
||||
if (itemEntry?.model) {
|
||||
const item = await getObject({
|
||||
model: itemEntry.model,
|
||||
id: req.body.item,
|
||||
cached: true,
|
||||
});
|
||||
name = item?.name;
|
||||
}
|
||||
}
|
||||
|
||||
const newData = {
|
||||
updatedAt: new Date(),
|
||||
name: req.body.name,
|
||||
name: name || 'Order Item',
|
||||
purchaseOrder: req.body.purchaseOrder,
|
||||
state: { type: 'draft' },
|
||||
itemType: req.body.itemType,
|
||||
item: req.body.item,
|
||||
sku: req.body.sku,
|
||||
orderType: req.body.orderType,
|
||||
order: req.body.order,
|
||||
syncAmount: req.body.syncAmount,
|
||||
|
||||
@ -36,7 +36,7 @@ export const listFilamentsRouteHandler = async (
|
||||
search,
|
||||
sort,
|
||||
order,
|
||||
populate: ['vendor', 'costTaxRate'],
|
||||
populate: ['costTaxRate'],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -59,16 +59,7 @@ export const listFilamentsByPropertiesRouteHandler = async (
|
||||
model: filamentModel,
|
||||
properties,
|
||||
filter,
|
||||
populate: [
|
||||
{
|
||||
path: 'vendor',
|
||||
from: 'vendors',
|
||||
},
|
||||
{
|
||||
path: 'costTaxRate',
|
||||
from: 'taxrates',
|
||||
},
|
||||
],
|
||||
populate: [],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -86,7 +77,7 @@ export const getFilamentRouteHandler = async (req, res) => {
|
||||
const result = await getObject({
|
||||
model: filamentModel,
|
||||
id,
|
||||
populate: ['vendor', 'costTaxRate'],
|
||||
populate: ['costTaxRate'],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`Filament not found with supplied id.`);
|
||||
@ -108,15 +99,13 @@ export const editFilamentRouteHandler = async (req, res) => {
|
||||
barcode: req.body.barcode,
|
||||
url: req.body.url,
|
||||
image: req.body.image,
|
||||
color: req.body.color,
|
||||
vendor: req.body.vendor,
|
||||
type: req.body.type,
|
||||
cost: req.body.cost,
|
||||
costTaxRate: req.body.costTaxRate,
|
||||
costWithTax: req.body.costWithTax,
|
||||
diameter: req.body.diameter,
|
||||
density: req.body.density,
|
||||
emptySpoolWeight: req.body.emptySpoolWeight,
|
||||
cost: req.body?.cost,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
};
|
||||
const result = await editObject({
|
||||
model: filamentModel,
|
||||
@ -143,15 +132,13 @@ export const editMultipleFilamentsRouteHandler = async (req, res) => {
|
||||
barcode: update.barcode,
|
||||
url: update.url,
|
||||
image: update.image,
|
||||
color: update.color,
|
||||
vendor: update.vendor,
|
||||
type: update.type,
|
||||
cost: update.cost,
|
||||
costTaxRate: update.costTaxRate,
|
||||
costWithTax: update.costWithTax,
|
||||
diameter: update.diameter,
|
||||
density: update.density,
|
||||
emptySpoolWeight: update.emptySpoolWeight,
|
||||
cost: update.cost,
|
||||
costTaxRate: update.costTaxRate,
|
||||
costWithTax: update.costWithTax,
|
||||
}));
|
||||
|
||||
if (!Array.isArray(updates)) {
|
||||
@ -183,15 +170,13 @@ export const newFilamentRouteHandler = async (req, res) => {
|
||||
barcode: req.body.barcode,
|
||||
url: req.body.url,
|
||||
image: req.body.image,
|
||||
color: req.body.color,
|
||||
vendor: req.body.vendor,
|
||||
type: req.body.type,
|
||||
cost: req.body.cost,
|
||||
costTaxRate: req.body.costTaxRate,
|
||||
costWithTax: req.body.costWithTax,
|
||||
diameter: req.body.diameter,
|
||||
density: req.body.density,
|
||||
emptySpoolWeight: req.body.emptySpoolWeight,
|
||||
cost: req.body?.cost,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
};
|
||||
|
||||
const result = await newObject({
|
||||
|
||||
196
src/services/management/filamentskus.js
Normal file
196
src/services/management/filamentskus.js
Normal file
@ -0,0 +1,196 @@
|
||||
import config from '../../config.js';
|
||||
import { filamentSkuModel } from '../../database/schemas/management/filamentsku.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
deleteObject,
|
||||
listObjects,
|
||||
getObject,
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
const logger = log4js.getLogger('Filament SKUs');
|
||||
logger.level = config.server.logLevel;
|
||||
|
||||
export const listFilamentSkusRouteHandler = async (
|
||||
req,
|
||||
res,
|
||||
page = 1,
|
||||
limit = 25,
|
||||
property = '',
|
||||
filter = {},
|
||||
search = '',
|
||||
sort = '',
|
||||
order = 'ascend'
|
||||
) => {
|
||||
const result = await listObjects({
|
||||
model: filamentSkuModel,
|
||||
page,
|
||||
limit,
|
||||
property,
|
||||
filter,
|
||||
search,
|
||||
sort,
|
||||
order,
|
||||
populate: [{ path: 'filament', populate: 'costTaxRate' }, 'costTaxRate'],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
logger.error('Error listing filament SKUs.');
|
||||
res.status(result.code).send(result);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(`List of filament SKUs (Page ${page}, Limit ${limit}). Count: ${result.length}.`);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const listFilamentSkusByPropertiesRouteHandler = async (
|
||||
req,
|
||||
res,
|
||||
properties = '',
|
||||
filter = {},
|
||||
masterFilter = {}
|
||||
) => {
|
||||
const result = await listObjectsByProperties({
|
||||
model: filamentSkuModel,
|
||||
properties,
|
||||
filter,
|
||||
populate: ['costTaxRate'],
|
||||
masterFilter,
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
logger.error('Error listing filament SKUs.');
|
||||
res.status(result.code).send(result);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(`List of filament SKUs. Count: ${result.length}`);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getFilamentSkuRouteHandler = async (req, res) => {
|
||||
const id = req.params.id;
|
||||
const result = await getObject({
|
||||
model: filamentSkuModel,
|
||||
id,
|
||||
populate: [{ path: 'filament', populate: 'costTaxRate' }, 'costTaxRate'],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`Filament SKU not found with supplied id.`);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.debug(`Retrieved filament SKU with ID: ${id}`);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const editFilamentSkuRouteHandler = async (req, res) => {
|
||||
const id = new mongoose.Types.ObjectId(req.params.id);
|
||||
|
||||
logger.trace(`Filament SKU with ID: ${id}`);
|
||||
|
||||
const overrideCost = req.body?.overrideCost;
|
||||
|
||||
const updateData = {
|
||||
updatedAt: new Date(),
|
||||
barcode: req.body?.barcode,
|
||||
filament: req.body?.filament,
|
||||
name: req.body?.name,
|
||||
description: req.body?.description,
|
||||
color: req.body?.color,
|
||||
cost: overrideCost ? req.body?.cost : null,
|
||||
overrideCost,
|
||||
costTaxRate: overrideCost ? req.body?.costTaxRate : null,
|
||||
costWithTax: overrideCost ? req.body?.costWithTax : null,
|
||||
};
|
||||
|
||||
const result = await editObject({
|
||||
model: filamentSkuModel,
|
||||
id,
|
||||
updateData,
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
logger.error('Error editing filament SKU:', result.error);
|
||||
res.status(result.code || 500).send(result);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(`Edited filament SKU with ID: ${id}`);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const newFilamentSkuRouteHandler = async (req, res) => {
|
||||
const overrideCost = req.body?.overrideCost;
|
||||
|
||||
const newData = {
|
||||
barcode: req.body?.barcode,
|
||||
filament: req.body?.filament,
|
||||
name: req.body?.name,
|
||||
description: req.body?.description,
|
||||
color: req.body?.color,
|
||||
cost: overrideCost ? req.body?.cost : null,
|
||||
overrideCost,
|
||||
costTaxRate: overrideCost ? req.body?.costTaxRate : null,
|
||||
costWithTax: overrideCost ? req.body?.costWithTax : null,
|
||||
};
|
||||
|
||||
const result = await newObject({
|
||||
model: filamentSkuModel,
|
||||
newData,
|
||||
user: req.user,
|
||||
});
|
||||
if (result.error) {
|
||||
logger.error('No filament SKU created:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
|
||||
logger.debug(`New filament SKU with ID: ${result._id}`);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const deleteFilamentSkuRouteHandler = async (req, res) => {
|
||||
const id = new mongoose.Types.ObjectId(req.params.id);
|
||||
|
||||
logger.trace(`Filament SKU with ID: ${id}`);
|
||||
|
||||
const result = await deleteObject({
|
||||
model: filamentSkuModel,
|
||||
id,
|
||||
user: req.user,
|
||||
});
|
||||
if (result.error) {
|
||||
logger.error('No filament SKU deleted:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
|
||||
logger.debug(`Deleted filament SKU with ID: ${id}`);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getFilamentSkuStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: filamentSkuModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching filament SKU stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Filament SKU stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getFilamentSkuHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: filamentSkuModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching filament SKU history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Filament SKU history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
@ -35,7 +35,7 @@ export const listPartsRouteHandler = async (
|
||||
search,
|
||||
sort,
|
||||
order,
|
||||
populate: [],
|
||||
populate: ['costTaxRate', 'priceTaxRate'],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -71,7 +71,7 @@ export const getPartRouteHandler = async (req, res) => {
|
||||
const result = await getObject({
|
||||
model: partModel,
|
||||
id,
|
||||
populate: [],
|
||||
populate: ['costTaxRate', 'priceTaxRate'],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`Part not found with supplied id.`);
|
||||
@ -92,6 +92,14 @@ export const editPartRouteHandler = async (req, res) => {
|
||||
name: req.body?.name,
|
||||
fileName: req.body?.fileName,
|
||||
file: req.body?.file,
|
||||
cost: req.body?.cost,
|
||||
price: req.body?.price,
|
||||
priceMode: req.body?.priceMode,
|
||||
margin: req.body?.margin,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
priceTaxRate: req.body?.priceTaxRate,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
priceWithTax: req.body?.priceWithTax,
|
||||
};
|
||||
// Create audit log before updating
|
||||
const result = await editObject({
|
||||
@ -118,6 +126,14 @@ export const newPartRouteHandler = async (req, res) => {
|
||||
name: req.body?.name,
|
||||
fileName: req.body?.fileName,
|
||||
file: req.body?.file,
|
||||
cost: req.body?.cost,
|
||||
price: req.body?.price,
|
||||
priceMode: req.body?.priceMode,
|
||||
margin: req.body?.margin,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
priceTaxRate: req.body?.priceTaxRate,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
priceWithTax: req.body?.priceWithTax,
|
||||
};
|
||||
|
||||
const result = await newObject({
|
||||
|
||||
@ -35,7 +35,7 @@ export const listPartSkusRouteHandler = async (
|
||||
search,
|
||||
sort,
|
||||
order,
|
||||
populate: ['part', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
populate: ['priceTaxRate', 'costTaxRate'],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -59,7 +59,11 @@ export const listPartSkusByPropertiesRouteHandler = async (
|
||||
model: partSkuModel,
|
||||
properties,
|
||||
filter,
|
||||
populate: ['part', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
populate: [
|
||||
{ path: 'part', populate: ['costTaxRate', 'priceTaxRate'] },
|
||||
'priceTaxRate',
|
||||
'costTaxRate',
|
||||
],
|
||||
masterFilter,
|
||||
});
|
||||
|
||||
@ -78,7 +82,11 @@ export const getPartSkuRouteHandler = async (req, res) => {
|
||||
const result = await getObject({
|
||||
model: partSkuModel,
|
||||
id,
|
||||
populate: ['part', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
populate: [
|
||||
{ path: 'part', populate: ['costTaxRate', 'priceTaxRate'] },
|
||||
'priceTaxRate',
|
||||
'costTaxRate',
|
||||
],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`Part SKU not found with supplied id.`);
|
||||
@ -93,22 +101,25 @@ export const editPartSkuRouteHandler = async (req, res) => {
|
||||
|
||||
logger.trace(`Part SKU with ID: ${id}`);
|
||||
|
||||
const overrideCost = req.body?.overrideCost;
|
||||
const overridePrice = req.body?.overridePrice;
|
||||
|
||||
const updateData = {
|
||||
updatedAt: new Date(),
|
||||
sku: req.body?.sku,
|
||||
barcode: req.body?.barcode,
|
||||
part: req.body?.part,
|
||||
name: req.body?.name,
|
||||
description: req.body?.description,
|
||||
priceMode: req.body?.priceMode,
|
||||
price: req.body?.price,
|
||||
cost: req.body?.cost,
|
||||
margin: req.body?.margin,
|
||||
amount: req.body?.amount,
|
||||
vendor: req.body?.vendor,
|
||||
priceTaxRate: req.body?.priceTaxRate,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
priceWithTax: req.body?.priceWithTax,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
price: overridePrice ? req.body?.price : null,
|
||||
cost: overrideCost ? req.body?.cost : null,
|
||||
overrideCost,
|
||||
overridePrice,
|
||||
margin: overridePrice ? req.body?.margin : null,
|
||||
priceTaxRate: overridePrice ? req.body?.priceTaxRate : null,
|
||||
costTaxRate: overrideCost ? req.body?.costTaxRate : null,
|
||||
priceWithTax: overridePrice ? req.body?.priceWithTax : null,
|
||||
costWithTax: overrideCost ? req.body?.costWithTax : null,
|
||||
};
|
||||
|
||||
const result = await editObject({
|
||||
@ -129,21 +140,24 @@ export const editPartSkuRouteHandler = async (req, res) => {
|
||||
};
|
||||
|
||||
export const newPartSkuRouteHandler = async (req, res) => {
|
||||
const overrideCost = req.body?.overrideCost;
|
||||
const overridePrice = req.body?.overridePrice;
|
||||
|
||||
const newData = {
|
||||
sku: req.body?.sku,
|
||||
barcode: req.body?.barcode,
|
||||
part: req.body?.part,
|
||||
name: req.body?.name,
|
||||
description: req.body?.description,
|
||||
priceMode: req.body?.priceMode,
|
||||
price: req.body?.price,
|
||||
cost: req.body?.cost,
|
||||
margin: req.body?.margin,
|
||||
amount: req.body?.amount,
|
||||
vendor: req.body?.vendor,
|
||||
priceTaxRate: req.body?.priceTaxRate,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
priceWithTax: req.body?.priceWithTax,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
price: overridePrice ? req.body?.price : null,
|
||||
cost: overrideCost ? req.body?.cost : null,
|
||||
overrideCost,
|
||||
overridePrice,
|
||||
margin: overridePrice ? req.body?.margin : null,
|
||||
priceTaxRate: overridePrice ? req.body?.priceTaxRate : null,
|
||||
costTaxRate: overrideCost ? req.body?.costTaxRate : null,
|
||||
priceWithTax: overridePrice ? req.body?.priceWithTax : null,
|
||||
costWithTax: overrideCost ? req.body?.costWithTax : null,
|
||||
};
|
||||
|
||||
const result = await newObject({
|
||||
|
||||
@ -35,7 +35,7 @@ export const listProductsRouteHandler = async (
|
||||
search,
|
||||
sort,
|
||||
order,
|
||||
populate: ['vendor'],
|
||||
populate: ['vendor', 'costTaxRate', 'priceTaxRate'],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -76,7 +76,7 @@ export const getProductRouteHandler = async (req, res) => {
|
||||
const result = await getObject({
|
||||
model: productModel,
|
||||
id,
|
||||
populate: ['vendor'],
|
||||
populate: ['vendor', 'costTaxRate', 'priceTaxRate'],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`Product not found with supplied id.`);
|
||||
@ -98,6 +98,14 @@ export const editProductRouteHandler = async (req, res) => {
|
||||
tags: req.body?.tags,
|
||||
version: req.body?.version,
|
||||
vendor: req.body.vendor,
|
||||
cost: req.body?.cost,
|
||||
price: req.body?.price,
|
||||
priceMode: req.body?.priceMode,
|
||||
margin: req.body?.margin,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
priceTaxRate: req.body?.priceTaxRate,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
priceWithTax: req.body?.priceWithTax,
|
||||
};
|
||||
// Create audit log before updating
|
||||
const result = await editObject({
|
||||
@ -125,6 +133,14 @@ export const newProductRouteHandler = async (req, res) => {
|
||||
tags: req.body?.tags,
|
||||
version: req.body?.version,
|
||||
vendor: req.body.vendor,
|
||||
cost: req.body?.cost,
|
||||
price: req.body?.price,
|
||||
priceMode: req.body?.priceMode,
|
||||
margin: req.body?.margin,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
priceTaxRate: req.body?.priceTaxRate,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
priceWithTax: req.body?.priceWithTax,
|
||||
};
|
||||
|
||||
const result = await newObject({
|
||||
|
||||
@ -35,7 +35,7 @@ export const listProductSkusRouteHandler = async (
|
||||
search,
|
||||
sort,
|
||||
order,
|
||||
populate: ['product', 'vendor', 'priceTaxRate', 'costTaxRate', 'parts.partSku'],
|
||||
populate: ['priceTaxRate', 'costTaxRate'],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -59,7 +59,12 @@ export const listProductSkusByPropertiesRouteHandler = async (
|
||||
model: productSkuModel,
|
||||
properties,
|
||||
filter,
|
||||
populate: ['product', 'vendor', 'priceTaxRate', 'costTaxRate', 'parts.partSku'],
|
||||
populate: [
|
||||
{ path: 'product', populate: ['costTaxRate', 'priceTaxRate'] },
|
||||
'priceTaxRate',
|
||||
'costTaxRate',
|
||||
'parts.partSku',
|
||||
],
|
||||
masterFilter,
|
||||
});
|
||||
|
||||
@ -78,7 +83,12 @@ export const getProductSkuRouteHandler = async (req, res) => {
|
||||
const result = await getObject({
|
||||
model: productSkuModel,
|
||||
id,
|
||||
populate: ['product', 'vendor', 'priceTaxRate', 'costTaxRate', 'parts.partSku'],
|
||||
populate: [
|
||||
{ path: 'product', populate: ['costTaxRate', 'priceTaxRate'] },
|
||||
'priceTaxRate',
|
||||
'costTaxRate',
|
||||
'parts.partSku',
|
||||
],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`Product SKU not found with supplied id.`);
|
||||
@ -93,23 +103,26 @@ export const editProductSkuRouteHandler = async (req, res) => {
|
||||
|
||||
logger.trace(`Product SKU with ID: ${id}`);
|
||||
|
||||
const overrideCost = req.body?.overrideCost;
|
||||
const overridePrice = req.body?.overridePrice;
|
||||
|
||||
const updateData = {
|
||||
updatedAt: new Date(),
|
||||
sku: req.body?.sku,
|
||||
barcode: req.body?.barcode,
|
||||
product: req.body?.product,
|
||||
name: req.body?.name,
|
||||
description: req.body?.description,
|
||||
priceMode: req.body?.priceMode,
|
||||
price: req.body?.price,
|
||||
cost: req.body?.cost,
|
||||
margin: req.body?.margin,
|
||||
amount: req.body?.amount,
|
||||
vendor: req.body?.vendor,
|
||||
price: overridePrice ? req.body?.price : null,
|
||||
cost: overrideCost ? req.body?.cost : null,
|
||||
overrideCost,
|
||||
overridePrice,
|
||||
margin: overridePrice ? req.body?.margin : null,
|
||||
parts: req.body?.parts,
|
||||
priceTaxRate: req.body?.priceTaxRate,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
priceWithTax: req.body?.priceWithTax,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
priceTaxRate: overridePrice ? req.body?.priceTaxRate : null,
|
||||
costTaxRate: overrideCost ? req.body?.costTaxRate : null,
|
||||
priceWithTax: overridePrice ? req.body?.priceWithTax : null,
|
||||
costWithTax: overrideCost ? req.body?.costWithTax : null,
|
||||
};
|
||||
|
||||
const result = await editObject({
|
||||
@ -130,22 +143,25 @@ export const editProductSkuRouteHandler = async (req, res) => {
|
||||
};
|
||||
|
||||
export const newProductSkuRouteHandler = async (req, res) => {
|
||||
const overrideCost = req.body?.overrideCost;
|
||||
const overridePrice = req.body?.overridePrice;
|
||||
|
||||
const newData = {
|
||||
sku: req.body?.sku,
|
||||
barcode: req.body?.barcode,
|
||||
product: req.body?.product,
|
||||
name: req.body?.name,
|
||||
description: req.body?.description,
|
||||
priceMode: req.body?.priceMode,
|
||||
price: req.body?.price,
|
||||
cost: req.body?.cost,
|
||||
margin: req.body?.margin,
|
||||
amount: req.body?.amount,
|
||||
vendor: req.body?.vendor,
|
||||
price: overridePrice ? req.body?.price : null,
|
||||
cost: overrideCost ? req.body?.cost : null,
|
||||
overrideCost,
|
||||
overridePrice,
|
||||
margin: overridePrice ? req.body?.margin : null,
|
||||
parts: req.body?.parts,
|
||||
priceTaxRate: req.body?.priceTaxRate,
|
||||
costTaxRate: req.body?.costTaxRate,
|
||||
priceWithTax: req.body?.priceWithTax,
|
||||
costWithTax: req.body?.costWithTax,
|
||||
priceTaxRate: overridePrice ? req.body?.priceTaxRate : null,
|
||||
costTaxRate: overrideCost ? req.body?.costTaxRate : null,
|
||||
priceWithTax: overridePrice ? req.body?.priceWithTax : null,
|
||||
costWithTax: overrideCost ? req.body?.costWithTax : null,
|
||||
};
|
||||
|
||||
const result = await newObject({
|
||||
|
||||
@ -62,13 +62,14 @@ function getModelFilterFields(objectType) {
|
||||
printer: ['host'],
|
||||
job: ['printer', 'gcodeFile'],
|
||||
subJob: ['job'],
|
||||
filamentStock: ['filament'],
|
||||
filamentStock: ['filamentSku'],
|
||||
filamentSku: ['filament', 'vendor', 'costTaxRate'],
|
||||
partStock: ['partSku'],
|
||||
partSku: ['part', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
productStock: ['productSku'],
|
||||
productSku: ['product', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
purchaseOrder: ['vendor'],
|
||||
orderItem: ['order._id', 'orderType', 'item._id', 'itemType', 'shipment._id'],
|
||||
orderItem: ['order._id', 'orderType', 'item._id', 'itemType', 'sku._id', 'shipment._id'],
|
||||
shipment: ['order._id', 'orderType', 'courierService._id'],
|
||||
stockEvent: ['parent._id', 'parentType', 'owner._id', 'ownerType'],
|
||||
stockAudit: ['filamentStock._id', 'partStock._id'],
|
||||
|
||||
@ -68,13 +68,14 @@ function getModelFilterFields(objectType) {
|
||||
printer: ['host'],
|
||||
job: ['printer', 'gcodeFile'],
|
||||
subJob: ['job'],
|
||||
filamentStock: ['filament'],
|
||||
filamentStock: ['filamentSku'],
|
||||
filamentSku: ['filament', 'vendor', 'costTaxRate'],
|
||||
partStock: ['partSku'],
|
||||
partSku: ['part', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
productStock: ['productSku'],
|
||||
productSku: ['product', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
purchaseOrder: ['vendor'],
|
||||
orderItem: ['order._id', 'orderType', 'item._id', 'itemType', 'shipment._id'],
|
||||
orderItem: ['order._id', 'orderType', 'item._id', 'itemType', 'sku._id', 'shipment._id'],
|
||||
shipment: ['order._id', 'orderType', 'courierService._id'],
|
||||
stockEvent: ['parent._id', 'parentType', 'owner._id', 'ownerType'],
|
||||
stockAudit: ['filamentStock._id', 'partStock._id'],
|
||||
|
||||
@ -342,13 +342,14 @@ function getModelFilterFields(objectType) {
|
||||
printer: ['host'],
|
||||
job: ['printer', 'gcodeFile'],
|
||||
subJob: ['job'],
|
||||
filamentStock: ['filament'],
|
||||
filamentStock: ['filamentSku'],
|
||||
filamentSku: ['filament', 'vendor', 'costTaxRate'],
|
||||
partStock: ['partSku'],
|
||||
partSku: ['part', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
productStock: ['productSku'],
|
||||
productSku: ['product', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
purchaseOrder: ['vendor'],
|
||||
orderItem: ['order._id', 'orderType', 'item._id', 'itemType', 'shipment._id'],
|
||||
orderItem: ['order._id', 'orderType', 'item._id', 'itemType', 'sku._id', 'shipment._id'],
|
||||
shipment: ['order._id', 'orderType', 'courierService._id'],
|
||||
stockEvent: ['parent._id', 'parentType', 'owner._id', 'ownerType'],
|
||||
stockAudit: ['filamentStock._id', 'partStock._id'],
|
||||
|
||||
@ -35,7 +35,7 @@ export const listGCodeFilesRouteHandler = async (
|
||||
search,
|
||||
sort,
|
||||
order,
|
||||
populate: ['filament'],
|
||||
populate: ['filamentSku'],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -58,7 +58,7 @@ export const listGCodeFilesByPropertiesRouteHandler = async (
|
||||
model: gcodeFileModel,
|
||||
properties,
|
||||
filter,
|
||||
populate: 'filament',
|
||||
populate: 'filamentSku',
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -76,7 +76,7 @@ export const getGCodeFileRouteHandler = async (req, res) => {
|
||||
const result = await getObject({
|
||||
model: gcodeFileModel,
|
||||
id,
|
||||
populate: ['filament', 'parts.part'],
|
||||
populate: ['filamentSku', 'parts.partSku'],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`GCodeFile not found with supplied id.`);
|
||||
@ -113,7 +113,7 @@ export const editGCodeFileRouteHandler = async (req, res) => {
|
||||
updatedAt: new Date(),
|
||||
name: req.body.name,
|
||||
file: req.body.file,
|
||||
filament: req.body.filament,
|
||||
filamentSku: req.body.filamentSku,
|
||||
parts: req.body.parts,
|
||||
};
|
||||
// Create audit log before updating
|
||||
@ -140,7 +140,7 @@ export const newGCodeFileRouteHandler = async (req, res) => {
|
||||
updatedAt: new Date(),
|
||||
name: req.body.name,
|
||||
file: req.body.file,
|
||||
filament: req.body.filament,
|
||||
filamentSku: req.body.filamentSku,
|
||||
parts: req.body.parts,
|
||||
};
|
||||
const result = await newObject({
|
||||
|
||||
@ -858,7 +858,10 @@ function buildDeepPopulateSpec(object, model, populated = new Set()) {
|
||||
const ref = directRef || arrayRef;
|
||||
if (!ref) return;
|
||||
|
||||
const refModel = model.db.model(ref);
|
||||
const refName = typeof ref === 'function' ? ref.call(object) : ref;
|
||||
if (!refName) return;
|
||||
|
||||
const refModel = model.db.model(refName);
|
||||
const childPopulate = buildDeepPopulateSpec(object, refModel, populated);
|
||||
|
||||
const id = object[pathname]?._id || object[pathname];
|
||||
@ -866,9 +869,9 @@ function buildDeepPopulateSpec(object, model, populated = new Set()) {
|
||||
if (id == null || !id) return;
|
||||
|
||||
if (childPopulate.length > 0) {
|
||||
populateSpec.push({ path: pathname, populate: childPopulate, ref: ref, _id: id });
|
||||
populateSpec.push({ path: pathname, populate: childPopulate, ref: refName, _id: id });
|
||||
} else {
|
||||
populateSpec.push({ path: pathname, ref: ref, _id: id });
|
||||
populateSpec.push({ path: pathname, ref: refName, _id: id });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user