Implemented Part SKUs.

This commit is contained in:
Tom Butcher 2026-03-07 23:34:17 +00:00
parent 41c221c477
commit bea9e45cd4
7 changed files with 66 additions and 26 deletions

View File

@ -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 },
}, },
part: { type: mongoose.Schema.Types.ObjectId, ref: 'part', required: true }, partSku: { type: mongoose.Schema.Types.ObjectId, ref: 'partSku', 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 },

View File

@ -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 },
part: { type: Schema.Types.ObjectId, ref: 'part', required: true }, partSku: { type: Schema.Types.ObjectId, ref: 'partSku', 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 },
product: { type: mongoose.Schema.Types.ObjectId, ref: 'product', required: true }, productSku: { type: mongoose.Schema.Types.ObjectId, ref: 'productSku', required: true },
currentQuantity: { type: Number, required: true }, currentQuantity: { type: Number, required: true },
partStocks: [partStockUsageSchema], partStocks: [partStockUsageSchema],
}, },

View File

@ -2,22 +2,13 @@ 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 // Define the main part schema - pricing moved to PartSku
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 },
priceMode: { type: String, default: 'margin' },
price: { type: Number, required: true },
cost: { type: Number, required: true },
margin: { type: Number, required: false },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
file: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', required: false }, file: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', 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 } { timestamps: true }
); );

View File

@ -0,0 +1,36 @@
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()() },
sku: { type: String, required: true },
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 },
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 },
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 });
// Create and export the model
export const partSkuModel = mongoose.model('partSku', partSkuSchema);

View File

@ -2,11 +2,6 @@ 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(
{ {
@ -14,13 +9,7 @@ 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 },
priceMode: { type: String, default: 'margin' },
margin: { type: Number, required: false },
amount: { type: Number, required: false },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true }, vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
parts: [partSchema],
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
}, },
{ timestamps: true } { timestamps: true }
); );

View File

@ -2,14 +2,30 @@ 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()() },
sku: { type: String, required: true }, 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: false }, name: { type: String, required: true },
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 },
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 },
priceWithTax: { type: Number, required: false },
costWithTax: { type: Number, required: false },
}, },
{ timestamps: true } { timestamps: true }
); );

View File

@ -4,6 +4,7 @@ import { printerModel } from './production/printer.schema.js';
import { filamentModel } from './management/filament.schema.js'; import { filamentModel } from './management/filament.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';
@ -67,6 +68,13 @@ 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',
@ -74,7 +82,7 @@ export const models = {
referenceField: '_reference', referenceField: '_reference',
label: 'Product', label: 'Product',
}, },
PSK: { SKU: {
model: productSkuModel, model: productSkuModel,
idField: '_id', idField: '_id',
type: 'productSku', type: 'productSku',