diff --git a/src/database/schemas/inventory/purchaseorder.schema.js b/src/database/schemas/inventory/purchaseorder.schema.js index 7c96150..d88fe3e 100644 --- a/src/database/schemas/inventory/purchaseorder.schema.js +++ b/src/database/schemas/inventory/purchaseorder.schema.js @@ -6,7 +6,10 @@ const itemSchema = new Schema({ itemType: { type: String, required: true }, item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true }, quantity: { type: Number, required: true }, - price: { 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( diff --git a/src/database/schemas/management/part.schema.js b/src/database/schemas/management/part.schema.js index 0fca23a..4d84001 100644 --- a/src/database/schemas/management/part.schema.js +++ b/src/database/schemas/management/part.schema.js @@ -14,6 +14,10 @@ const partSchema = new Schema( margin: { type: Number, required: false }, vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true }, 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 } ); diff --git a/src/database/schemas/management/product.schema.js b/src/database/schemas/management/product.schema.js index 004c451..64dee0d 100644 --- a/src/database/schemas/management/product.schema.js +++ b/src/database/schemas/management/product.schema.js @@ -19,6 +19,8 @@ const productSchema = new Schema( amount: { type: Number, required: false }, 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 } ); diff --git a/src/database/schemas/management/taxrates.schema.js b/src/database/schemas/management/taxrates.schema.js new file mode 100644 index 0000000..898c3ca --- /dev/null +++ b/src/database/schemas/management/taxrates.schema.js @@ -0,0 +1,25 @@ +import mongoose from 'mongoose'; +import { generateId } from '../../utils.js'; + +const taxRateSchema = new mongoose.Schema( + { + _reference: { type: String, default: () => generateId()() }, + name: { required: true, type: String }, + rate: { required: true, type: Number }, + rateType: { required: true, type: String, enum: ['percentage', 'fixed'] }, + active: { required: true, type: Boolean, default: true }, + description: { required: false, type: String }, + country: { required: false, type: String }, + effectiveFrom: { required: false, type: Date }, + effectiveTo: { required: false, type: Date }, + }, + { timestamps: true } +); + +taxRateSchema.virtual('id').get(function () { + return this._id; +}); + +taxRateSchema.set('toJSON', { virtuals: true }); + +export const taxRateModel = mongoose.model('taxRate', taxRateSchema); diff --git a/src/database/schemas/management/taxrecord.schema.js b/src/database/schemas/management/taxrecord.schema.js new file mode 100644 index 0000000..3680196 --- /dev/null +++ b/src/database/schemas/management/taxrecord.schema.js @@ -0,0 +1,28 @@ +import mongoose from 'mongoose'; +import { generateId } from '../../utils.js'; +const { Schema } = mongoose; + +const taxRecordSchema = new Schema( + { + _reference: { type: String, default: () => generateId()() }, + taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: true }, + transactionType: { + type: String, + required: true, + enum: ['purchaseOrder', 'salesOrder', 'other'], + }, + transaction: { type: Schema.Types.ObjectId, refPath: 'transactionType', required: true }, + amount: { type: Number, required: true }, + taxAmount: { type: Number, required: true }, + transactionDate: { required: true, type: Date, default: Date.now }, + }, + { timestamps: true } +); + +taxRecordSchema.virtual('id').get(function () { + return this._id; +}); + +taxRecordSchema.set('toJSON', { virtuals: true }); + +export const taxRecordModel = mongoose.model('taxRecord', taxRecordSchema); diff --git a/src/database/schemas/models.js b/src/database/schemas/models.js new file mode 100644 index 0000000..17de5ac --- /dev/null +++ b/src/database/schemas/models.js @@ -0,0 +1,94 @@ +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 { gcodeFileModel } from './production/gcodefile.schema.js'; +import { partModel } from './management/part.schema.js'; +import { productModel } from './management/product.schema.js'; +import { vendorModel } from './management/vendor.schema.js'; +import { filamentStockModel } from './inventory/filamentstock.schema.js'; +import { purchaseOrderModel } from './inventory/purchaseorder.schema.js'; +import { stockEventModel } from './inventory/stockevent.schema.js'; +import { stockAuditModel } from './inventory/stockaudit.schema.js'; +import { partStockModel } from './inventory/partstock.schema.js'; +import { auditLogModel } from './management/auditlog.schema.js'; +import { userModel } from './management/user.schema.js'; +import { noteTypeModel } from './management/notetype.schema.js'; +import { noteModel } from './misc/note.schema.js'; +import { documentSizeModel } from './management/documentsize.schema.js'; +import { documentTemplateModel } from './management/documenttemplate.schema.js'; +import { hostModel } from './management/host.schema.js'; +import { documentPrinterModel } from './management/documentprinter.schema.js'; +import { documentJobModel } from './management/documentjob.schema.js'; +import { fileModel } from './management/file.schema.js'; +import { courierServiceModel } from './management/courierservice.schema.js'; +import { courierModel } from './management/courier.schema.js'; +import { taxRateModel } from './management/taxrates.schema.js'; +import { taxRecordModel } from './management/taxrecord.schema.js'; + +// Map prefixes to models and id fields +export const models = { + PRN: { model: printerModel, idField: '_id', type: 'printer', referenceField: '_reference' }, + FIL: { model: filamentModel, idField: '_id', type: 'filament', referenceField: '_reference' }, + GCF: { model: gcodeFileModel, idField: '_id', type: 'gcodeFile', referenceField: '_reference' }, + JOB: { model: jobModel, idField: '_id', type: 'job', referenceField: '_reference' }, + PRT: { model: partModel, idField: '_id', type: 'part', referenceField: '_reference' }, + PRD: { model: productModel, idField: '_id', type: 'product', referenceField: '_reference' }, + VEN: { model: vendorModel, idField: '_id', type: 'vendor', referenceField: '_reference' }, + SJB: { model: subJobModel, idField: '_id', type: 'subJob', referenceField: '_reference' }, + FLS: { + model: filamentStockModel, + idField: '_id', + type: 'filamentStock', + referenceField: '_reference', + }, + SEV: { model: stockEventModel, idField: '_id', type: 'stockEvent', referenceField: '_reference' }, + SAU: { model: stockAuditModel, idField: '_id', type: 'stockAudit', referenceField: '_reference' }, + PTS: { model: partStockModel, idField: '_id', type: 'partStock', referenceField: '_reference' }, + PDS: { model: null, idField: '_id', type: 'productStock', referenceField: '_reference' }, // No productStockModel found + ADL: { model: auditLogModel, idField: '_id', type: 'auditLog', referenceField: '_reference' }, + USR: { model: userModel, idField: '_id', type: 'user', referenceField: '_reference' }, + NTY: { model: noteTypeModel, idField: '_id', type: 'noteType', referenceField: '_reference' }, + NTE: { model: noteModel, idField: '_id', type: 'note', referenceField: '_reference' }, + DSZ: { + model: documentSizeModel, + idField: '_id', + type: 'documentSize', + referenceField: '_reference', + }, + DTP: { + model: documentTemplateModel, + idField: '_id', + type: 'documentTemplate', + referenceField: '_reference', + }, + DPR: { + model: documentPrinterModel, + idField: '_id', + type: 'documentPrinter', + referenceField: '_reference', + }, + DJB: { + model: documentJobModel, + idField: '_id', + type: 'documentJob', + referenceField: '_reference', + }, + HST: { model: hostModel, idField: '_id', type: 'host', referenceField: '_reference' }, + FLE: { model: fileModel, idField: '_id', type: 'file', referenceField: '_reference' }, + POR: { + model: purchaseOrderModel, + idField: '_id', + type: 'purchaseOrder', + referenceField: '_reference', + }, + COS: { + model: courierServiceModel, + idField: '_id', + type: 'courierService', + referenceField: '_reference', + }, + COR: { model: courierModel, idField: '_id', type: 'courier', referenceField: '_reference' }, + TXR: { model: taxRateModel, idField: '_id', type: 'taxRate', referenceField: '_reference' }, + TXD: { model: taxRecordModel, idField: '_id', type: 'taxRecord', referenceField: '_reference' }, +}; diff --git a/src/utils.js b/src/utils.js index e617714..31e7a1c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -3,42 +3,16 @@ import { hostModel } from './database/schemas/management/host.schema.js'; import crypto from 'crypto'; import { nanoid } from 'nanoid'; import canonicalize from 'canonical-json'; +import { models } from './database/schemas/models.js'; import { loadConfig } from './config.js'; -import { userModel } from './database/schemas/management/user.schema.js'; -import { documentSizeModel } from './database/schemas/management/documentsize.schema.js'; -import { documentJobModel } from './database/schemas/management/documentjob.schema.js'; -import { documentTemplateModel } from './database/schemas/management/documenttemplate.schema.js'; -import { documentPrinterModel } from './database/schemas/management/documentprinter.schema.js'; -import { printerModel } from './database/schemas/production/printer.schema.js'; -import { subJobModel } from './database/schemas/production/subjob.schema.js'; -import { jobModel } from './database/schemas/production/job.schema.js'; -import { filamentStockModel } from './database/schemas/inventory/filamentstock.schema.js'; -import { fileModel } from './database/schemas/management/file.schema.js'; -import { gcodeFileModel } from './database/schemas/production/gcodefile.schema.js'; -import { stockEventModel } from './database/schemas/inventory/stockevent.schema.js'; -import { filamentModel } from './database/schemas/management/filament.schema.js'; - const config = loadConfig(); const authCodeLength = 64; -const modelList = [ - hostModel, - userModel, - documentSizeModel, - documentJobModel, - documentTemplateModel, - documentPrinterModel, - printerModel, - jobModel, - subJobModel, - fileModel, - gcodeFileModel, - filamentStockModel, - stockEventModel, - filamentModel -]; +const modelList = Object.values(models) + .map(model => model.model) + .filter(model => model != null); export async function generateHostOTP(id) { const otp = crypto.randomInt(0, 1000000).toString().padStart(6, '0'); // 0 to 999999