Compare commits
No commits in common. "b2c854bce9f6489eea763ef0dfe15b7d656a9f1b" and "d1dbbe2b112622cb6601e16515ca1cfee3f31ef6" have entirely different histories.
b2c854bce9
...
d1dbbe2b11
2
.gitignore
vendored
2
.gitignore
vendored
@ -137,5 +137,3 @@ test-results.xml
|
|||||||
|
|
||||||
DS_STORE
|
DS_STORE
|
||||||
**/DS_Store
|
**/DS_Store
|
||||||
|
|
||||||
test-results.xml
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ const filamentStockSchema = new Schema(
|
|||||||
net: { type: Number, required: true },
|
net: { type: Number, required: true },
|
||||||
gross: { type: Number, required: true },
|
gross: { type: Number, required: true },
|
||||||
},
|
},
|
||||||
filamentSku: { type: mongoose.Schema.Types.ObjectId, ref: 'filamentSku', required: true },
|
filament: { type: mongoose.Schema.Types.ObjectId, ref: 'filament', required: true },
|
||||||
},
|
},
|
||||||
{ timestamps: true }
|
{ timestamps: true }
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,12 +2,6 @@ import mongoose from 'mongoose';
|
|||||||
import { purchaseOrderModel } from './purchaseorder.schema.js';
|
import { purchaseOrderModel } from './purchaseorder.schema.js';
|
||||||
import { salesOrderModel } from '../sales/salesorder.schema.js';
|
import { salesOrderModel } from '../sales/salesorder.schema.js';
|
||||||
import { taxRateModel } from '../management/taxrate.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 {
|
import {
|
||||||
aggregateRollups,
|
aggregateRollups,
|
||||||
aggregateRollupsHistory,
|
aggregateRollupsHistory,
|
||||||
@ -17,18 +11,6 @@ import {
|
|||||||
import { generateId } from '../../utils.js';
|
import { generateId } from '../../utils.js';
|
||||||
const { Schema } = mongoose;
|
const { Schema } = mongoose;
|
||||||
|
|
||||||
const skuModelsByItemType = {
|
|
||||||
filament: filamentSkuModel,
|
|
||||||
part: partSkuModel,
|
|
||||||
product: productSkuModel,
|
|
||||||
};
|
|
||||||
|
|
||||||
const parentModelsByItemType = {
|
|
||||||
filament: filamentModel,
|
|
||||||
part: partModel,
|
|
||||||
product: productModel,
|
|
||||||
};
|
|
||||||
|
|
||||||
const orderItemSchema = new Schema(
|
const orderItemSchema = new Schema(
|
||||||
{
|
{
|
||||||
_reference: { type: String, default: () => generateId()() },
|
_reference: { type: String, default: () => generateId()() },
|
||||||
@ -39,16 +21,7 @@ const orderItemSchema = new Schema(
|
|||||||
},
|
},
|
||||||
order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
|
order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
|
||||||
itemType: { type: String, required: true },
|
itemType: { type: String, required: true },
|
||||||
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: false },
|
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true },
|
||||||
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 },
|
syncAmount: { type: String, required: false, default: null },
|
||||||
itemAmount: { type: Number, required: true },
|
itemAmount: { type: Number, required: true },
|
||||||
quantity: { type: Number, required: true },
|
quantity: { type: Number, required: true },
|
||||||
@ -115,55 +88,9 @@ orderItemSchema.statics.recalculate = async function (orderItem, user) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If SKU present and syncAmount is set, check if override is on for the price mode and use that price instead
|
var taxRate = orderItem.taxRate;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let taxRate = orderItem.taxRate;
|
if (orderItem.taxRate?._id && Object.keys(orderItem.taxRate).length == 1) {
|
||||||
if (orderItem.taxRate?._id && Object.keys(orderItem.taxRate).length === 1) {
|
|
||||||
taxRate = await getObject({
|
taxRate = await getObject({
|
||||||
model: taxRateModel,
|
model: taxRateModel,
|
||||||
id: orderItem.taxRate._id,
|
id: orderItem.taxRate._id,
|
||||||
@ -171,25 +98,18 @@ orderItemSchema.statics.recalculate = async function (orderItem, user) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderTotalAmount = effectiveItemAmount * orderItem.quantity;
|
const orderTotalAmount = orderItem.itemAmount * orderItem.quantity;
|
||||||
const orderTotalAmountWithTax = orderTotalAmount * (1 + (taxRate?.rate || 0) / 100);
|
const orderTotalAmountWithTax = orderTotalAmount * (1 + (taxRate?.rate || 0) / 100);
|
||||||
|
await editObject({
|
||||||
const orderItemUpdateData = {
|
model: orderItemModel,
|
||||||
totalAmount: orderTotalAmount,
|
id: orderItem._id,
|
||||||
totalAmountWithTax: orderTotalAmountWithTax,
|
updateData: {
|
||||||
invoicedAmountRemaining: orderTotalAmount - orderItem.invoicedAmount,
|
invoicedAmountRemaining: orderTotalAmount - orderItem.invoicedAmount,
|
||||||
invoicedAmountWithTaxRemaining: orderTotalAmountWithTax - orderItem.invoicedAmountWithTax,
|
invoicedAmountWithTaxRemaining: orderTotalAmountWithTax - orderItem.invoicedAmountWithTax,
|
||||||
invoicedQuantityRemaining: orderItem.quantity - orderItem.invoicedQuantity,
|
invoicedQuantityRemaining: orderItem.quantity - orderItem.invoicedQuantity,
|
||||||
};
|
totalAmount: orderTotalAmount,
|
||||||
if (effectiveItemAmount !== orderItem.itemAmount) {
|
totalAmountWithTax: orderTotalAmountWithTax,
|
||||||
orderItemUpdateData.itemAmount = effectiveItemAmount;
|
},
|
||||||
orderItem.itemAmount = effectiveItemAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
await editObject({
|
|
||||||
model: this,
|
|
||||||
id: orderItem._id,
|
|
||||||
updateData: orderItemUpdateData,
|
|
||||||
user,
|
user,
|
||||||
recalculate: false,
|
recalculate: false,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,7 +11,7 @@ const partStockSchema = new Schema(
|
|||||||
type: { type: String, required: true },
|
type: { type: String, required: true },
|
||||||
progress: { type: Number, required: false },
|
progress: { type: Number, required: false },
|
||||||
},
|
},
|
||||||
partSku: { type: mongoose.Schema.Types.ObjectId, ref: 'partSku', required: true },
|
part: { type: mongoose.Schema.Types.ObjectId, ref: 'part', required: true },
|
||||||
currentQuantity: { type: Number, required: true },
|
currentQuantity: { type: Number, required: true },
|
||||||
sourceType: { type: String, required: true },
|
sourceType: { type: String, required: true },
|
||||||
source: { type: Schema.Types.ObjectId, refPath: 'sourceType', required: true },
|
source: { type: Schema.Types.ObjectId, refPath: 'sourceType', required: true },
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
|||||||
|
|
||||||
const partStockUsageSchema = new Schema({
|
const partStockUsageSchema = new Schema({
|
||||||
partStock: { type: Schema.Types.ObjectId, ref: 'partStock', required: false },
|
partStock: { type: Schema.Types.ObjectId, ref: 'partStock', required: false },
|
||||||
partSku: { type: Schema.Types.ObjectId, ref: 'partSku', required: true },
|
part: { type: Schema.Types.ObjectId, ref: 'part', required: true },
|
||||||
quantity: { type: Number, required: true },
|
quantity: { type: Number, required: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ const productStockSchema = new Schema(
|
|||||||
progress: { type: Number, required: false },
|
progress: { type: Number, required: false },
|
||||||
},
|
},
|
||||||
postedAt: { type: Date, required: false },
|
postedAt: { type: Date, required: false },
|
||||||
productSku: { type: mongoose.Schema.Types.ObjectId, ref: 'productSku', required: true },
|
product: { type: mongoose.Schema.Types.ObjectId, ref: 'product', required: true },
|
||||||
currentQuantity: { type: Number, required: true },
|
currentQuantity: { type: Number, required: true },
|
||||||
partStocks: [partStockUsageSchema],
|
partStocks: [partStockUsageSchema],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,21 +2,24 @@ import mongoose from 'mongoose';
|
|||||||
import { generateId } from '../../utils.js';
|
import { generateId } from '../../utils.js';
|
||||||
const { Schema } = mongoose;
|
const { Schema } = mongoose;
|
||||||
|
|
||||||
// Filament base - cost and tax; color and cost override at FilamentSKU
|
|
||||||
const filamentSchema = new mongoose.Schema({
|
const filamentSchema = new mongoose.Schema({
|
||||||
_reference: { type: String, default: () => generateId()() },
|
_reference: { type: String, default: () => generateId()() },
|
||||||
name: { required: true, type: String },
|
name: { required: true, type: String },
|
||||||
barcode: { required: false, type: String },
|
barcode: { required: false, type: String },
|
||||||
url: { required: false, type: String },
|
url: { required: false, type: String },
|
||||||
image: { required: false, type: Buffer },
|
image: { required: false, type: Buffer },
|
||||||
material: { type: Schema.Types.ObjectId, ref: 'material', required: true },
|
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 },
|
diameter: { required: true, type: Number },
|
||||||
density: { required: true, type: Number },
|
density: { required: true, type: Number },
|
||||||
|
createdAt: { required: true, type: Date },
|
||||||
|
updatedAt: { required: true, type: Date },
|
||||||
emptySpoolWeight: { required: true, type: Number },
|
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 () {
|
filamentSchema.virtual('id').get(function () {
|
||||||
return this._id;
|
return this._id;
|
||||||
@ -24,21 +27,4 @@ filamentSchema.virtual('id').get(function () {
|
|||||||
|
|
||||||
filamentSchema.set('toJSON', { virtuals: true });
|
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);
|
export const filamentModel = mongoose.model('filament', filamentSchema);
|
||||||
|
|||||||
@ -1,48 +0,0 @@
|
|||||||
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);
|
|
||||||
@ -1,15 +1,13 @@
|
|||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import { generateId } from '../../utils.js';
|
import { generateId } from '../../utils.js';
|
||||||
|
|
||||||
const materialSchema = new mongoose.Schema(
|
const materialSchema = new mongoose.Schema({
|
||||||
{
|
|
||||||
_reference: { type: String, default: () => generateId()() },
|
_reference: { type: String, default: () => generateId()() },
|
||||||
name: { required: true, type: String },
|
name: { required: true, type: String },
|
||||||
url: { required: false, type: String },
|
url: { required: false, type: String },
|
||||||
|
image: { required: false, type: Buffer },
|
||||||
tags: [{ type: String }],
|
tags: [{ type: String }],
|
||||||
},
|
});
|
||||||
{ timestamps: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
materialSchema.virtual('id').get(function () {
|
materialSchema.virtual('id').get(function () {
|
||||||
return this._id;
|
return this._id;
|
||||||
|
|||||||
@ -2,22 +2,22 @@ import mongoose from 'mongoose';
|
|||||||
import { generateId } from '../../utils.js';
|
import { generateId } from '../../utils.js';
|
||||||
const { Schema } = mongoose;
|
const { Schema } = mongoose;
|
||||||
|
|
||||||
// Define the main part schema - cost/price and tax; override at PartSku
|
// Define the main part schema
|
||||||
const partSchema = new Schema(
|
const partSchema = new Schema(
|
||||||
{
|
{
|
||||||
_reference: { type: String, default: () => generateId()() },
|
_reference: { type: String, default: () => generateId()() },
|
||||||
name: { type: String, required: true },
|
name: { type: String, required: true },
|
||||||
fileName: { type: String, required: false },
|
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' },
|
priceMode: { type: String, default: 'margin' },
|
||||||
|
price: { type: Number, required: true },
|
||||||
|
cost: { type: Number, required: true },
|
||||||
margin: { type: Number, required: false },
|
margin: { type: Number, required: false },
|
||||||
amount: { type: Number, required: false },
|
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
|
||||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
file: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', required: false },
|
||||||
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||||
costWithTax: { type: Number, required: false },
|
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||||
priceWithTax: { type: Number, required: false },
|
priceWithTax: { type: Number, required: false },
|
||||||
|
costWithTax: { type: Number, required: false },
|
||||||
},
|
},
|
||||||
{ timestamps: true }
|
{ timestamps: true }
|
||||||
);
|
);
|
||||||
@ -30,22 +30,5 @@ partSchema.virtual('id').get(function () {
|
|||||||
// Configure JSON serialization to include virtuals
|
// Configure JSON serialization to include virtuals
|
||||||
partSchema.set('toJSON', { virtuals: true });
|
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
|
// Create and export the model
|
||||||
export const partModel = mongoose.model('part', partSchema);
|
export const partModel = mongoose.model('part', partSchema);
|
||||||
|
|||||||
@ -1,54 +0,0 @@
|
|||||||
import mongoose from 'mongoose';
|
|
||||||
import { generateId } from '../../utils.js';
|
|
||||||
const { Schema } = mongoose;
|
|
||||||
|
|
||||||
// Define the main part SKU schema - pricing lives at SKU level
|
|
||||||
const partSkuSchema = new Schema(
|
|
||||||
{
|
|
||||||
_reference: { type: String, default: () => generateId()() },
|
|
||||||
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 },
|
|
||||||
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
|
||||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
|
||||||
priceWithTax: { type: Number, required: false },
|
|
||||||
costWithTax: { type: Number, required: false },
|
|
||||||
},
|
|
||||||
{ timestamps: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add virtual id getter
|
|
||||||
partSkuSchema.virtual('id').get(function () {
|
|
||||||
return this._id;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
@ -2,6 +2,11 @@ import mongoose from 'mongoose';
|
|||||||
import { generateId } from '../../utils.js';
|
import { generateId } from '../../utils.js';
|
||||||
const { Schema } = mongoose;
|
const { Schema } = mongoose;
|
||||||
|
|
||||||
|
const partSchema = new Schema({
|
||||||
|
part: { type: Schema.Types.ObjectId, ref: 'part', required: true },
|
||||||
|
quantity: { type: Number, required: true },
|
||||||
|
});
|
||||||
|
|
||||||
// Define the main product schema
|
// Define the main product schema
|
||||||
const productSchema = new Schema(
|
const productSchema = new Schema(
|
||||||
{
|
{
|
||||||
@ -9,16 +14,13 @@ const productSchema = new Schema(
|
|||||||
name: { type: String, required: true },
|
name: { type: String, required: true },
|
||||||
tags: [{ type: String }],
|
tags: [{ type: String }],
|
||||||
version: { 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' },
|
priceMode: { type: String, default: 'margin' },
|
||||||
margin: { type: Number, required: false },
|
margin: { type: Number, required: false },
|
||||||
amount: { type: Number, required: false },
|
amount: { type: Number, required: false },
|
||||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
|
||||||
|
parts: [partSchema],
|
||||||
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||||
costWithTax: { type: Number, required: false },
|
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||||
priceWithTax: { type: Number, required: false },
|
|
||||||
},
|
},
|
||||||
{ timestamps: true }
|
{ timestamps: true }
|
||||||
);
|
);
|
||||||
@ -30,22 +32,5 @@ productSchema.virtual('id').get(function () {
|
|||||||
// Configure JSON serialization to include virtuals
|
// Configure JSON serialization to include virtuals
|
||||||
productSchema.set('toJSON', { virtuals: true });
|
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
|
// Create and export the model
|
||||||
export const productModel = mongoose.model('product', productSchema);
|
export const productModel = mongoose.model('product', productSchema);
|
||||||
|
|||||||
@ -2,31 +2,14 @@ import mongoose from 'mongoose';
|
|||||||
import { generateId } from '../../utils.js';
|
import { generateId } from '../../utils.js';
|
||||||
const { Schema } = mongoose;
|
const { Schema } = mongoose;
|
||||||
|
|
||||||
const partSkuUsageSchema = new Schema({
|
|
||||||
partSku: { type: Schema.Types.ObjectId, ref: 'partSku', required: true },
|
|
||||||
quantity: { type: Number, required: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Define the main product SKU schema
|
// Define the main product SKU schema
|
||||||
const productSkuSchema = new Schema(
|
const productSkuSchema = new Schema(
|
||||||
{
|
{
|
||||||
_reference: { type: String, default: () => generateId()() },
|
_reference: { type: String, default: () => generateId()() },
|
||||||
barcode: { type: String, required: false },
|
sku: { type: String, required: true },
|
||||||
product: { type: Schema.Types.ObjectId, ref: 'product', required: true },
|
product: { type: Schema.Types.ObjectId, ref: 'product', required: true },
|
||||||
name: { type: String, required: true },
|
name: { type: String, required: false },
|
||||||
description: { type: String, required: false },
|
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 },
|
|
||||||
parts: [partSkuUsageSchema],
|
|
||||||
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
|
||||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
|
||||||
priceWithTax: { type: Number, required: false },
|
|
||||||
costWithTax: { type: Number, required: false },
|
|
||||||
},
|
},
|
||||||
{ timestamps: true }
|
{ timestamps: true }
|
||||||
);
|
);
|
||||||
@ -39,22 +22,5 @@ productSkuSchema.virtual('id').get(function () {
|
|||||||
// Configure JSON serialization to include virtuals
|
// Configure JSON serialization to include virtuals
|
||||||
productSkuSchema.set('toJSON', { virtuals: true });
|
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
|
// Create and export the model
|
||||||
export const productSkuModel = mongoose.model('productSku', productSkuSchema);
|
export const productSkuModel = mongoose.model('productSku', productSkuSchema);
|
||||||
|
|||||||
@ -2,14 +2,11 @@ import { jobModel } from './production/job.schema.js';
|
|||||||
import { subJobModel } from './production/subjob.schema.js';
|
import { subJobModel } from './production/subjob.schema.js';
|
||||||
import { printerModel } from './production/printer.schema.js';
|
import { printerModel } from './production/printer.schema.js';
|
||||||
import { filamentModel } from './management/filament.schema.js';
|
import { filamentModel } from './management/filament.schema.js';
|
||||||
import { filamentSkuModel } from './management/filamentsku.schema.js';
|
|
||||||
import { gcodeFileModel } from './production/gcodefile.schema.js';
|
import { gcodeFileModel } from './production/gcodefile.schema.js';
|
||||||
import { partModel } from './management/part.schema.js';
|
import { partModel } from './management/part.schema.js';
|
||||||
import { partSkuModel } from './management/partsku.schema.js';
|
|
||||||
import { productModel } from './management/product.schema.js';
|
import { productModel } from './management/product.schema.js';
|
||||||
import { productSkuModel } from './management/productsku.schema.js';
|
import { productSkuModel } from './management/productsku.schema.js';
|
||||||
import { vendorModel } from './management/vendor.schema.js';
|
import { vendorModel } from './management/vendor.schema.js';
|
||||||
import { materialModel } from './management/material.schema.js';
|
|
||||||
import { filamentStockModel } from './inventory/filamentstock.schema.js';
|
import { filamentStockModel } from './inventory/filamentstock.schema.js';
|
||||||
import { purchaseOrderModel } from './inventory/purchaseorder.schema.js';
|
import { purchaseOrderModel } from './inventory/purchaseorder.schema.js';
|
||||||
import { orderItemModel } from './inventory/orderitem.schema.js';
|
import { orderItemModel } from './inventory/orderitem.schema.js';
|
||||||
@ -55,13 +52,6 @@ export const models = {
|
|||||||
referenceField: '_reference',
|
referenceField: '_reference',
|
||||||
label: 'Filament',
|
label: 'Filament',
|
||||||
},
|
},
|
||||||
FSU: {
|
|
||||||
model: filamentSkuModel,
|
|
||||||
idField: '_id',
|
|
||||||
type: 'filamentSku',
|
|
||||||
referenceField: '_reference',
|
|
||||||
label: 'Filament SKU',
|
|
||||||
},
|
|
||||||
GCF: {
|
GCF: {
|
||||||
model: gcodeFileModel,
|
model: gcodeFileModel,
|
||||||
idField: '_id',
|
idField: '_id',
|
||||||
@ -77,13 +67,6 @@ export const models = {
|
|||||||
referenceField: '_reference',
|
referenceField: '_reference',
|
||||||
label: 'Part',
|
label: 'Part',
|
||||||
},
|
},
|
||||||
PSU: {
|
|
||||||
model: partSkuModel,
|
|
||||||
idField: '_id',
|
|
||||||
type: 'partSku',
|
|
||||||
referenceField: '_reference',
|
|
||||||
label: 'Part SKU',
|
|
||||||
},
|
|
||||||
PRD: {
|
PRD: {
|
||||||
model: productModel,
|
model: productModel,
|
||||||
idField: '_id',
|
idField: '_id',
|
||||||
@ -91,7 +74,7 @@ export const models = {
|
|||||||
referenceField: '_reference',
|
referenceField: '_reference',
|
||||||
label: 'Product',
|
label: 'Product',
|
||||||
},
|
},
|
||||||
SKU: {
|
PSK: {
|
||||||
model: productSkuModel,
|
model: productSkuModel,
|
||||||
idField: '_id',
|
idField: '_id',
|
||||||
type: 'productSku',
|
type: 'productSku',
|
||||||
@ -105,13 +88,6 @@ export const models = {
|
|||||||
referenceField: '_reference',
|
referenceField: '_reference',
|
||||||
label: 'Vendor',
|
label: 'Vendor',
|
||||||
},
|
},
|
||||||
MAT: {
|
|
||||||
model: materialModel,
|
|
||||||
idField: '_id',
|
|
||||||
type: 'material',
|
|
||||||
referenceField: '_reference',
|
|
||||||
label: 'Material',
|
|
||||||
},
|
|
||||||
SJB: {
|
SJB: {
|
||||||
model: subJobModel,
|
model: subJobModel,
|
||||||
idField: '_id',
|
idField: '_id',
|
||||||
|
|||||||
@ -13,7 +13,7 @@ const gcodeFileSchema = new mongoose.Schema(
|
|||||||
name: { required: true, type: String },
|
name: { required: true, type: String },
|
||||||
gcodeFileName: { required: false, type: String },
|
gcodeFileName: { required: false, type: String },
|
||||||
size: { type: Number, required: false },
|
size: { type: Number, required: false },
|
||||||
filamentSku: { type: Schema.Types.ObjectId, ref: 'filamentSku', required: true },
|
filament: { type: Schema.Types.ObjectId, ref: 'filament', required: true },
|
||||||
parts: [partSchema],
|
parts: [partSchema],
|
||||||
file: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', required: false },
|
file: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', required: false },
|
||||||
cost: { type: Number, required: false },
|
cost: { type: Number, required: false },
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user