Move schema location.

This commit is contained in:
Tom Butcher 2025-12-13 21:10:19 +00:00
parent 97bdf613c6
commit 08a7ecff38
35 changed files with 308 additions and 85 deletions

View File

@ -1,6 +1,7 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
const { Schema } = mongoose; const { Schema } = mongoose;
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
// Define the main filamentStock schema // Define the main filamentStock schema
const filamentStockSchema = new Schema( const filamentStockSchema = new Schema(
@ -23,6 +24,35 @@ const filamentStockSchema = new Schema(
{ timestamps: true } { timestamps: true }
); );
const rollupConfigs = [
{
name: 'totalCurrentWeight',
filter: {},
rollups: [{ name: 'totalCurrentWeight', property: 'currentWeight.net', operation: 'sum' }],
},
];
filamentStockSchema.statics.stats = async function () {
const results = await aggregateRollups({
model: this,
rollupConfigs: rollupConfigs,
});
return results;
};
filamentStockSchema.statics.history = async function (from, to) {
const results = await aggregateRollupsHistory({
model: this,
startDate: from,
endDate: to,
rollupConfigs: rollupConfigs,
});
// Return time-series data array
return results;
};
// Add virtual id getter // Add virtual id getter
filamentStockSchema.virtual('id').get(function () { filamentStockSchema.virtual('id').get(function () {
return this._id; return this._id;

View File

@ -0,0 +1,82 @@
import mongoose from 'mongoose';
import { purchaseOrderModel } from './purchaseorder.schema.js';
import { aggregateRollups, editObject } from '../../database.js';
import { generateId } from '../../utils.js';
const { Schema } = mongoose;
const orderItemSchema = new Schema(
{
_reference: { type: String, default: () => generateId()() },
orderType: { type: String, required: true },
order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
itemType: { type: String, required: true },
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true },
syncAmount: { type: String, required: true, default: null },
itemAmount: { type: Number, required: true },
quantity: { type: Number, required: true },
totalAmount: { type: Number, required: true },
taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
totalAmountWithTax: { type: Number, required: true },
timestamp: { type: Date, default: Date.now },
},
{ timestamps: true }
);
orderItemSchema.statics.recalculate = async function (orderItem, user) {
// Only purchase orders are supported for now
if (orderItem.orderType !== 'purchaseOrder') {
return;
}
const orderId = orderItem.order?._id || orderItem.order;
if (!orderId) {
return;
}
const rollupResults = await aggregateRollups({
model: this,
baseFilter: {
order: new mongoose.Types.ObjectId(orderId),
orderType: orderItem.orderType,
},
rollupConfigs: [
{
name: 'orderTotals',
rollups: [
{ name: 'totalAmount', property: 'totalAmount', operation: 'sum' },
{
name: 'totalAmountWithTax',
property: 'totalAmountWithTax',
operation: 'sum',
},
],
},
],
});
const totals = rollupResults.orderTotals || {};
const totalAmount = totals.totalAmount.sum?.toFixed(2) || 0;
const totalAmountWithTax = totals.totalAmountWithTax.sum?.toFixed(2) || 0;
await editObject({
model: purchaseOrderModel,
id: orderId,
updateData: {
totalAmount: parseFloat(totalAmount),
totalAmountWithTax: parseFloat(totalAmountWithTax),
totalTaxAmount: parseFloat(totalAmountWithTax - totalAmount),
},
user,
});
};
// Add virtual id getter
orderItemSchema.virtual('id').get(function () {
return this._id;
});
// Configure JSON serialization to include virtuals
orderItemSchema.set('toJSON', { virtuals: true });
// Create and export the model
export const orderItemModel = mongoose.model('orderItem', orderItemSchema);

View File

@ -1,6 +1,7 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
const { Schema } = mongoose; const { Schema } = mongoose;
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
// Define the main partStock schema // Define the main partStock schema
const partStockSchema = new Schema( const partStockSchema = new Schema(
@ -18,6 +19,35 @@ const partStockSchema = new Schema(
{ timestamps: true } { timestamps: true }
); );
const rollupConfigs = [
{
name: 'totalCurrentQuantity',
filter: {},
rollups: [{ name: 'totalCurrentQuantity', property: 'currentQuantity', operation: 'sum' }],
},
];
partStockSchema.statics.stats = async function () {
const results = await aggregateRollups({
model: this,
rollupConfigs: rollupConfigs,
});
return results;
};
partStockSchema.statics.history = async function (from, to) {
const results = await aggregateRollupsHistory({
model: this,
startDate: from,
endDate: to,
rollupConfigs: rollupConfigs,
});
// Return time-series data array
return results;
};
// Add virtual id getter // Add virtual id getter
partStockSchema.virtual('id').get(function () { partStockSchema.virtual('id').get(function () {
return this._id; return this._id;

View File

@ -2,21 +2,12 @@ import mongoose from 'mongoose';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
const { Schema } = mongoose; const { Schema } = mongoose;
const itemSchema = new Schema({
itemType: { type: String, required: true },
item: { type: Schema.Types.ObjectId, refPath: 'items.itemType', required: true },
quantity: { type: Number, required: true },
itemCost: { type: Number, required: true },
totalCost: { type: Number, required: true },
totalCostWithTax: { type: Number, required: true },
taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
});
const purchaseOrderSchema = new Schema( const purchaseOrderSchema = new Schema(
{ {
_reference: { type: String, default: () => generateId()() }, _reference: { type: String, default: () => generateId()() },
cost: { net: { type: Number, required: true }, gross: { type: Number, required: true } }, totalAmount: { type: Number, required: true },
items: [itemSchema], totalAmountWithTax: { type: Number, required: true },
totalTaxAmount: { type: Number, required: true },
timestamp: { type: Date, default: Date.now }, timestamp: { type: Date, default: Date.now },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true }, vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
state: { state: {

View File

@ -18,7 +18,8 @@ const documentJobSchema = new Schema(
}, },
state: { state: {
type: { type: String, required: true, default: 'queued' }, type: { type: String, required: true, default: 'queued' },
percent: { type: Number, required: false }, progress: { type: Number, required: false },
message: { type: String, required: false },
}, },
documentTemplate: { documentTemplate: {
type: Schema.Types.ObjectId, type: Schema.Types.ObjectId,

View File

@ -12,6 +12,8 @@ const filamentSchema = new mongoose.Schema({
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true }, vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
type: { required: true, type: String }, type: { required: true, type: String },
cost: { required: true, type: Number }, 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 }, createdAt: { required: true, type: Date },

View File

@ -8,6 +8,7 @@ import { productModel } from './management/product.schema.js';
import { vendorModel } from './management/vendor.schema.js'; import { vendorModel } from './management/vendor.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 { stockEventModel } from './inventory/stockevent.schema.js'; import { stockEventModel } from './inventory/stockevent.schema.js';
import { stockAuditModel } from './inventory/stockaudit.schema.js'; import { stockAuditModel } from './inventory/stockaudit.schema.js';
import { partStockModel } from './inventory/partstock.schema.js'; import { partStockModel } from './inventory/partstock.schema.js';
@ -82,6 +83,12 @@ export const models = {
type: 'purchaseOrder', type: 'purchaseOrder',
referenceField: '_reference', referenceField: '_reference',
}, },
ODI: {
model: orderItemModel,
idField: '_id',
type: 'orderItem',
referenceField: '_reference',
},
COS: { COS: {
model: courierServiceModel, model: courierServiceModel,
idField: '_id', idField: '_id',

View File

@ -0,0 +1,91 @@
import mongoose from 'mongoose';
import { generateId } from '../../utils.js';
const { Schema } = mongoose;
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
const jobSchema = new mongoose.Schema(
{
_reference: { type: String, default: () => generateId()() },
state: {
type: { required: true, type: String },
progress: { type: Number, required: false },
},
printers: [{ type: Schema.Types.ObjectId, ref: 'printer', required: false }],
createdAt: { required: true, type: Date },
updatedAt: { required: true, type: Date },
startedAt: { required: false, type: Date, default: null },
finishedAt: { required: false, type: Date, default: null },
gcodeFile: {
type: Schema.Types.ObjectId,
ref: 'gcodeFile',
required: false,
},
quantity: {
type: Number,
required: true,
default: 1,
min: 1,
},
subJobs: [{ type: Schema.Types.ObjectId, ref: 'subJob', required: false }],
notes: [{ type: Schema.Types.ObjectId, ref: 'note', required: false }],
},
{ timestamps: true }
);
const rollupConfigs = [
{
name: 'queued',
filter: { 'state.type': 'queued' },
rollups: [{ name: 'queued', property: 'state.type', operation: 'count' }],
},
{
name: 'printing',
filter: { 'state.type': 'printing' },
rollups: [{ name: 'printing', property: 'state.type', operation: 'count' }],
},
{
name: 'draft',
filter: { 'state.type': 'draft' },
rollups: [{ name: 'draft', property: 'state.type', operation: 'count' }],
},
{
name: 'complete',
filter: { 'state.type': 'complete' },
rollups: [{ name: 'complete', property: 'state.type', operation: 'count' }],
},
{
name: 'failed',
filter: { 'state.type': 'failed' },
rollups: [{ name: 'failed', property: 'state.type', operation: 'count' }],
},
];
jobSchema.statics.stats = async function () {
const results = await aggregateRollups({
model: this,
rollupConfigs: rollupConfigs,
});
// Transform the results to match the expected format
return results;
};
jobSchema.statics.history = async function (from, to) {
const results = await aggregateRollupsHistory({
model: this,
startDate: from,
endDate: to,
rollupConfigs: rollupConfigs,
});
// Return time-series data array
return results;
};
jobSchema.virtual('id').get(function () {
return this._id;
});
jobSchema.set('toJSON', { virtuals: true });
export const jobModel = mongoose.model('job', jobSchema);

View File

@ -1,6 +1,7 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
const { Schema } = mongoose; const { Schema } = mongoose;
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
// Define the moonraker connection schema // Define the moonraker connection schema
const moonrakerSchema = new Schema( const moonrakerSchema = new Schema(
@ -56,6 +57,59 @@ const printerSchema = new Schema(
{ timestamps: true } { timestamps: true }
); );
const rollupConfigs = [
{
name: 'standby',
filter: { 'state.type': 'standby' },
rollups: [{ name: 'standby', property: 'state.type', operation: 'count' }],
},
{
name: 'complete',
filter: { 'state.type': 'complete' },
rollups: [{ name: 'complete', property: 'state.type', operation: 'count' }],
},
{
name: 'printing',
filter: { 'state.type': 'printing' },
rollups: [{ name: 'printing', property: 'state.type', operation: 'count' }],
},
{
name: 'error',
filter: { 'state.type': 'error' },
rollups: [{ name: 'error', property: 'state.type', operation: 'count' }],
},
{
name: 'offline',
filter: { 'state.type': 'offline' },
rollups: [{ name: 'offline', property: 'state.type', operation: 'count' }],
},
];
printerSchema.statics.stats = async function () {
const results = await aggregateRollups({
model: this,
baseFilter: { active: true },
rollupConfigs: rollupConfigs,
});
console.log(results);
// Transform the results to match the expected format
return results;
};
printerSchema.statics.history = async function (from, to) {
const results = await aggregateRollupsHistory({
model: this,
startDate: from,
endDate: to,
rollupConfigs: rollupConfigs,
});
// Return time-series data array
return results;
};
// Add virtual id getter // Add virtual id getter
printerSchema.virtual('id').get(function () { printerSchema.virtual('id').get(function () {
return this._id; return this._id;

7
src/database/utils.js Normal file
View File

@ -0,0 +1,7 @@
import { customAlphabet } from 'nanoid';
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
export const generateId = () => {
// 10 characters
return customAlphabet(ALPHABET, 12);
};

View File

@ -1,32 +0,0 @@
import mongoose from 'mongoose';
import { generateId } from '../../utils.js';
const { Schema } = mongoose;
const orderItemSchema = new Schema(
{
_reference: { type: String, default: () => generateId()() },
orderType: { type: String, required: true },
order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
itemType: { type: String, required: true },
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true },
syncAmount: { type: String, required: true, default: null },
itemAmount: { type: Number, required: true },
quantity: { type: Number, required: true },
totalAmount: { type: Number, required: true },
taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
totalAmountWithTax: { type: Number, required: true },
timestamp: { type: Date, default: Date.now },
},
{ timestamps: true }
);
// Add virtual id getter
orderItemSchema.virtual('id').get(function () {
return this._id;
});
// Configure JSON serialization to include virtuals
orderItemSchema.set('toJSON', { virtuals: true });
// Create and export the model
export const orderItemModel = mongoose.model('orderItem', orderItemSchema);

View File

@ -1,40 +0,0 @@
import mongoose from 'mongoose';
import { generateId } from '../../utils.js';
const { Schema } = mongoose;
const jobSchema = new mongoose.Schema(
{
_reference: { type: String, default: () => generateId()() },
state: {
type: { required: true, type: String },
progress: { type: Number, required: false },
},
printers: [{ type: Schema.Types.ObjectId, ref: 'printer', required: false }],
createdAt: { required: true, type: Date },
updatedAt: { required: true, type: Date },
startedAt: { required: false, type: Date, default: null },
finishedAt: { required: false, type: Date, default: null },
gcodeFile: {
type: Schema.Types.ObjectId,
ref: 'gcodeFile',
required: false,
},
quantity: {
type: Number,
required: true,
default: 1,
min: 1,
},
subJobs: [{ type: Schema.Types.ObjectId, ref: 'subJob', required: false }],
notes: [{ type: Schema.Types.ObjectId, ref: 'note', required: false }],
},
{ timestamps: true }
);
jobSchema.virtual('id').get(function () {
return this._id;
});
jobSchema.set('toJSON', { virtuals: true });
export const jobModel = mongoose.model('job', jobSchema);