Compare commits

..

No commits in common. "0fb0493d99252773cb7452c64de4851c07117333" and "944ad34f891bda92f5e625a28854f5d50d897a1c" have entirely different histories.

17 changed files with 70 additions and 645 deletions

View File

@ -33,8 +33,6 @@ import {
documentJobsRoutes, documentJobsRoutes,
courierRoutes, courierRoutes,
courierServiceRoutes, courierServiceRoutes,
taxRateRoutes,
taxRecordRoutes,
} from './routes/index.js'; } from './routes/index.js';
import path from 'path'; import path from 'path';
import * as fs from 'fs'; import * as fs from 'fs';
@ -139,8 +137,6 @@ app.use('/documentprinters', documentPrintersRoutes);
app.use('/documentjobs', documentJobsRoutes); app.use('/documentjobs', documentJobsRoutes);
app.use('/couriers', courierRoutes); app.use('/couriers', courierRoutes);
app.use('/courierservices', courierServiceRoutes); app.use('/courierservices', courierServiceRoutes);
app.use('/taxrates', taxRateRoutes);
app.use('/taxrecords', taxRecordRoutes);
app.use('/notes', noteRoutes); app.use('/notes', noteRoutes);
if (process.env.SCHEDULE_HOUR) { if (process.env.SCHEDULE_HOUR) {

View File

@ -25,8 +25,6 @@ import documentPrintersRoutes from './management/documentprinters.js';
import documentJobsRoutes from './management/documentjobs.js'; import documentJobsRoutes from './management/documentjobs.js';
import courierRoutes from './management/courier.js'; import courierRoutes from './management/courier.js';
import courierServiceRoutes from './management/courierservice.js'; import courierServiceRoutes from './management/courierservice.js';
import taxRateRoutes from './management/taxrates.js';
import taxRecordRoutes from './management/taxrecords.js';
import noteRoutes from './misc/notes.js'; import noteRoutes from './misc/notes.js';
export { export {
@ -58,6 +56,4 @@ export {
documentJobsRoutes, documentJobsRoutes,
courierRoutes, courierRoutes,
courierServiceRoutes, courierServiceRoutes,
taxRateRoutes,
taxRecordRoutes,
}; };

View File

@ -1,46 +0,0 @@
import express from 'express';
import { isAuthenticated } from '../../keycloak.js';
import { getFilter, convertPropertiesString } from '../../utils.js';
const router = express.Router();
import {
listTaxRatesRouteHandler,
getTaxRateRouteHandler,
editTaxRateRouteHandler,
newTaxRateRouteHandler,
deleteTaxRateRouteHandler,
listTaxRatesByPropertiesRouteHandler,
} from '../../services/management/taxrates.js';
// list of tax rates
router.get('/', isAuthenticated, (req, res) => {
const { page, limit, property, search, sort, order } = req.query;
const allowedFilters = ['name', 'rate', 'rateType', 'active', 'country'];
const filter = getFilter(req.query, allowedFilters);
listTaxRatesRouteHandler(req, res, page, limit, property, filter, search, sort, order);
});
router.get('/properties', isAuthenticated, (req, res) => {
let properties = convertPropertiesString(req.query.properties);
const allowedFilters = ['rateType', 'country', 'active'];
const filter = getFilter(req.query, allowedFilters, false);
listTaxRatesByPropertiesRouteHandler(req, res, properties, filter);
});
router.post('/', isAuthenticated, (req, res) => {
newTaxRateRouteHandler(req, res);
});
router.get('/:id', isAuthenticated, (req, res) => {
getTaxRateRouteHandler(req, res);
});
router.put('/:id', isAuthenticated, async (req, res) => {
editTaxRateRouteHandler(req, res);
});
router.delete('/:id', isAuthenticated, async (req, res) => {
deleteTaxRateRouteHandler(req, res);
});
export default router;

View File

@ -1,46 +0,0 @@
import express from 'express';
import { isAuthenticated } from '../../keycloak.js';
import { getFilter, convertPropertiesString } from '../../utils.js';
const router = express.Router();
import {
listTaxRecordsRouteHandler,
getTaxRecordRouteHandler,
editTaxRecordRouteHandler,
newTaxRecordRouteHandler,
deleteTaxRecordRouteHandler,
listTaxRecordsByPropertiesRouteHandler,
} from '../../services/management/taxrecords.js';
// list of tax records
router.get('/', isAuthenticated, (req, res) => {
const { page, limit, property, search, sort, order } = req.query;
const allowedFilters = ['taxRate', 'transactionType', 'transaction', 'transactionDate'];
const filter = getFilter(req.query, allowedFilters);
listTaxRecordsRouteHandler(req, res, page, limit, property, filter, search, sort, order);
});
router.get('/properties', isAuthenticated, (req, res) => {
let properties = convertPropertiesString(req.query.properties);
const allowedFilters = ['taxRate', 'transactionType', 'transaction'];
const filter = getFilter(req.query, allowedFilters, false);
listTaxRecordsByPropertiesRouteHandler(req, res, properties, filter);
});
router.post('/', isAuthenticated, (req, res) => {
newTaxRecordRouteHandler(req, res);
});
router.get('/:id', isAuthenticated, (req, res) => {
getTaxRecordRouteHandler(req, res);
});
router.put('/:id', isAuthenticated, async (req, res) => {
editTaxRecordRouteHandler(req, res);
});
router.delete('/:id', isAuthenticated, async (req, res) => {
deleteTaxRecordRouteHandler(req, res);
});
export default router;

View File

@ -6,10 +6,7 @@ const itemSchema = new Schema({
itemType: { type: String, required: true }, itemType: { type: String, required: true },
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true }, item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true },
quantity: { type: Number, required: true }, quantity: { type: Number, required: true },
itemCost: { type: Number, required: true }, price: { 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(

View File

@ -14,10 +14,6 @@ const partSchema = new Schema(
margin: { type: Number, required: false }, margin: { type: Number, required: false },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true }, 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

@ -19,8 +19,6 @@ const productSchema = new Schema(
amount: { 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], 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

@ -1,25 +0,0 @@
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);

View File

@ -1,28 +0,0 @@
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);

View File

@ -1,94 +0,0 @@
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' },
};

View File

@ -78,7 +78,7 @@ export const getPurchaseOrderRouteHandler = async (req, res) => {
const result = await getObject({ const result = await getObject({
model: purchaseOrderModel, model: purchaseOrderModel,
id, id,
populate: ['vendor', 'items.item', 'items.taxRate'], populate: ['vendor', 'items.item'],
}); });
if (result?.error) { if (result?.error) {
logger.warn(`Purchase Order not found with supplied id.`); logger.warn(`Purchase Order not found with supplied id.`);

View File

@ -53,7 +53,7 @@ export const listPartsByPropertiesRouteHandler = async (req, res, properties = '
model: partModel, model: partModel,
properties, properties,
filter, filter,
populate: ['vendor', 'priceTaxRate', 'costTaxRate'], populate: ['vendor'],
}); });
if (result?.error) { if (result?.error) {
@ -71,7 +71,7 @@ export const getPartRouteHandler = async (req, res) => {
const result = await getObject({ const result = await getObject({
model: partModel, model: partModel,
id, id,
populate: ['vendor', 'priceTaxRate', 'costTaxRate'], populate: ['vendor'],
}); });
if (result?.error) { if (result?.error) {
logger.warn(`Part not found with supplied id.`); logger.warn(`Part not found with supplied id.`);
@ -96,10 +96,6 @@ export const editPartRouteHandler = async (req, res) => {
price: req.body?.price, price: req.body?.price,
cost: req.body?.cost, cost: req.body?.cost,
priceMode: req.body?.priceMode, priceMode: req.body?.priceMode,
priceTaxRate: req.body?.priceTaxRate,
costTaxRate: req.body?.costTaxRate,
priceWithTax: req.body?.priceWithTax,
costWithTax: req.body?.costWithTax,
}; };
// Create audit log before updating // Create audit log before updating
const result = await editObject({ const result = await editObject({
@ -130,10 +126,6 @@ export const newPartRouteHandler = async (req, res) => {
price: req.body?.price, price: req.body?.price,
cost: req.body?.cost, cost: req.body?.cost,
priceMode: req.body?.priceMode, priceMode: req.body?.priceMode,
priceTaxRate: req.body?.priceTaxRate,
costTaxRate: req.body?.costTaxRate,
priceWithTax: req.body?.priceWithTax,
costWithTax: req.body?.costWithTax,
}; };
const result = await newObject({ const result = await newObject({

View File

@ -1,168 +0,0 @@
import dotenv from 'dotenv';
import { taxRateModel } from '../../schemas/management/taxrates.schema.js';
import log4js from 'log4js';
import mongoose from 'mongoose';
import {
deleteObject,
listObjects,
getObject,
editObject,
newObject,
listObjectsByProperties,
} from '../../database/database.js';
dotenv.config();
const logger = log4js.getLogger('TaxRates');
logger.level = process.env.LOG_LEVEL;
export const listTaxRatesRouteHandler = async (
req,
res,
page = 1,
limit = 25,
property = '',
filter = {},
search = '',
sort = '',
order = 'ascend'
) => {
const result = await listObjects({
model: taxRateModel,
page,
limit,
property,
filter,
search,
sort,
order,
});
if (result?.error) {
logger.error('Error listing tax rates.');
res.status(result.code).send(result);
return;
}
logger.debug(`List of tax rates (Page ${page}, Limit ${limit}). Count: ${result.length}.`);
res.send(result);
};
export const listTaxRatesByPropertiesRouteHandler = async (
req,
res,
properties = '',
filter = {}
) => {
const result = await listObjectsByProperties({
model: taxRateModel,
properties,
filter,
});
if (result?.error) {
logger.error('Error listing tax rates.');
res.status(result.code).send(result);
return;
}
logger.debug(`List of tax rates. Count: ${result.length}`);
res.send(result);
};
export const getTaxRateRouteHandler = async (req, res) => {
const id = req.params.id;
const result = await getObject({
model: taxRateModel,
id,
});
if (result?.error) {
logger.warn(`Tax rate not found with supplied id.`);
return res.status(result.code).send(result);
}
logger.debug(`Retreived tax rate with ID: ${id}`);
res.send(result);
};
export const editTaxRateRouteHandler = async (req, res) => {
// Get ID from params
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Tax rate with ID: ${id}`);
const updateData = {
updatedAt: new Date(),
name: req.body.name,
rate: req.body.rate,
rateType: req.body.rateType,
active: req.body.active,
description: req.body.description,
country: req.body.country,
effectiveFrom: req.body.effectiveFrom,
effectiveTo: req.body.effectiveTo,
};
// Create audit log before updating
const result = await editObject({
model: taxRateModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error editing tax rate:', result.error);
res.status(result).send(result);
return;
}
logger.debug(`Edited tax rate with ID: ${id}`);
res.send(result);
};
export const newTaxRateRouteHandler = async (req, res) => {
const newData = {
updatedAt: new Date(),
name: req.body.name,
rate: req.body.rate,
rateType: req.body.rateType,
active: req.body.active,
description: req.body.description,
country: req.body.country,
effectiveFrom: req.body.effectiveFrom,
effectiveTo: req.body.effectiveTo,
};
const result = await newObject({
model: taxRateModel,
newData,
user: req.user,
});
if (result.error) {
logger.error('No tax rate created:', result.error);
return res.status(result.code).send(result);
}
logger.debug(`New tax rate with ID: ${result._id}`);
res.send(result);
};
export const deleteTaxRateRouteHandler = async (req, res) => {
// Get ID from params
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Tax rate with ID: ${id}`);
const result = await deleteObject({
model: taxRateModel,
id,
user: req.user,
});
if (result.error) {
logger.error('No tax rate deleted:', result.error);
return res.status(result.code).send(result);
}
logger.debug(`Deleted tax rate with ID: ${result._id}`);
res.send(result);
};

View File

@ -1,164 +0,0 @@
import dotenv from 'dotenv';
import { taxRecordModel } from '../../schemas/management/taxrecord.schema.js';
import log4js from 'log4js';
import mongoose from 'mongoose';
import {
deleteObject,
listObjects,
getObject,
editObject,
newObject,
listObjectsByProperties,
} from '../../database/database.js';
dotenv.config();
const logger = log4js.getLogger('TaxRecords');
logger.level = process.env.LOG_LEVEL;
export const listTaxRecordsRouteHandler = async (
req,
res,
page = 1,
limit = 25,
property = '',
filter = {},
search = '',
sort = '',
order = 'ascend'
) => {
const result = await listObjects({
model: taxRecordModel,
page,
limit,
property,
filter,
search,
sort,
order,
});
if (result?.error) {
logger.error('Error listing tax records.');
res.status(result.code).send(result);
return;
}
logger.debug(`List of tax records (Page ${page}, Limit ${limit}). Count: ${result.length}.`);
res.send(result);
};
export const listTaxRecordsByPropertiesRouteHandler = async (
req,
res,
properties = '',
filter = {}
) => {
const result = await listObjectsByProperties({
model: taxRecordModel,
properties,
filter,
});
if (result?.error) {
logger.error('Error listing tax records.');
res.status(result.code).send(result);
return;
}
logger.debug(`List of tax records. Count: ${result.length}`);
res.send(result);
};
export const getTaxRecordRouteHandler = async (req, res) => {
const id = req.params.id;
const result = await getObject({
model: taxRecordModel,
id,
});
if (result?.error) {
logger.warn(`Tax record not found with supplied id.`);
return res.status(result.code).send(result);
}
logger.debug(`Retreived tax record with ID: ${id}`);
res.send(result);
};
export const editTaxRecordRouteHandler = async (req, res) => {
// Get ID from params
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Tax record with ID: ${id}`);
const updateData = {
updatedAt: new Date(),
taxRate: req.body.taxRate,
transactionType: req.body.transactionType,
transaction: req.body.transaction,
amount: req.body.amount,
taxAmount: req.body.taxAmount,
transactionDate: req.body.transactionDate,
};
// Create audit log before updating
const result = await editObject({
model: taxRecordModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error editing tax record:', result.error);
res.status(result).send(result);
return;
}
logger.debug(`Edited tax record with ID: ${id}`);
res.send(result);
};
export const newTaxRecordRouteHandler = async (req, res) => {
const newData = {
updatedAt: new Date(),
taxRate: req.body.taxRate,
transactionType: req.body.transactionType,
transaction: req.body.transaction,
amount: req.body.amount,
taxAmount: req.body.taxAmount,
transactionDate: req.body.transactionDate,
};
const result = await newObject({
model: taxRecordModel,
newData,
user: req.user,
});
if (result.error) {
logger.error('No tax record created:', result.error);
return res.status(result.code).send(result);
}
logger.debug(`New tax record with ID: ${result._id}`);
res.send(result);
};
export const deleteTaxRecordRouteHandler = async (req, res) => {
// Get ID from params
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Tax record with ID: ${id}`);
const result = await deleteObject({
model: taxRecordModel,
id,
user: req.user,
});
if (result.error) {
logger.error('No tax record deleted:', result.error);
return res.status(result.code).send(result);
}
logger.debug(`Deleted tax record with ID: ${result._id}`);
res.send(result);
};

View File

@ -1,11 +1,65 @@
import { models } from '../../schemas/models.js'; import { jobModel } from '../../schemas/production/job.schema.js';
import { subJobModel } from '../../schemas/production/subjob.schema.js';
import { printerModel } from '../../schemas/production/printer.schema.js';
import { filamentModel } from '../../schemas/management/filament.schema.js';
import { gcodeFileModel } from '../../schemas/production/gcodefile.schema.js';
import { partModel } from '../../schemas/management/part.schema.js';
import { productModel } from '../../schemas/management/product.schema.js';
import { vendorModel } from '../../schemas/management/vendor.schema.js';
import { filamentStockModel } from '../../schemas/inventory/filamentstock.schema.js';
import { purchaseOrderModel } from '../../schemas/inventory/purchaseorder.schema.js';
import { stockEventModel } from '../../schemas/inventory/stockevent.schema.js';
import { stockAuditModel } from '../../schemas/inventory/stockaudit.schema.js';
import { partStockModel } from '../../schemas/inventory/partstock.schema.js';
import { auditLogModel } from '../../schemas/management/auditlog.schema.js';
import { userModel } from '../../schemas/management/user.schema.js';
import { noteTypeModel } from '../../schemas/management/notetype.schema.js';
import { noteModel } from '../../schemas/misc/note.schema.js';
import { documentSizeModel } from '../../schemas/management/documentsize.schema.js';
import { documentTemplateModel } from '../../schemas/management/documenttemplate.schema.js';
import { hostModel } from '../../schemas/management/host.schema.js';
import { documentPrinterModel } from '../../schemas/management/documentprinter.schema.js';
import { documentJobModel } from '../../schemas/management/documentjob.schema.js';
import { fileModel } from '../../schemas/management/file.schema.js';
import { courierServiceModel } from '../../schemas/management/courierservice.schema.js';
import { courierModel } from '../../schemas/management/courier.schema.js';
// Map prefixes to models and id fields
const PREFIX_MODEL_MAP = {
PRN: { model: printerModel, idField: '_id', type: 'printer' },
FIL: { model: filamentModel, idField: '_id', type: 'filament' },
GCF: { model: gcodeFileModel, idField: '_id', type: 'gcodeFile' },
JOB: { model: jobModel, idField: '_id', type: 'job' },
PRT: { model: partModel, idField: '_id', type: 'part' },
PRD: { model: productModel, idField: '_id', type: 'product' },
VEN: { model: vendorModel, idField: '_id', type: 'vendor' },
SJB: { model: subJobModel, idField: '_id', type: 'subJob' },
FLS: { model: filamentStockModel, idField: '_id', type: 'filamentStock' },
SEV: { model: stockEventModel, idField: '_id', type: 'stockEvent' },
SAU: { model: stockAuditModel, idField: '_id', type: 'stockAudit' },
PTS: { model: partStockModel, idField: '_id', type: 'partStock' },
PDS: { model: null, idField: '_id', type: 'productStock' }, // No productStockModel found
ADL: { model: auditLogModel, idField: '_id', type: 'auditLog' },
USR: { model: userModel, idField: '_id', type: 'user' },
NTY: { model: noteTypeModel, idField: '_id', type: 'noteType' },
NTE: { model: noteModel, idField: '_id', type: 'note' },
DSZ: { model: documentSizeModel, idField: '_id', type: 'documentSize' },
DTP: { model: documentTemplateModel, idField: '_id', type: 'documentTemplate' },
DPR: { model: documentPrinterModel, idField: '_id', type: 'documentPrinter' },
DJB: { model: documentJobModel, idField: '_id', type: 'documentJob' },
HST: { model: hostModel, idField: '_id', type: 'host' },
FLE: { model: fileModel, idField: '_id', type: 'file' },
POR: { model: purchaseOrderModel, idField: '_id', type: 'purchaseOrder' },
COS: { model: courierServiceModel, idField: '_id', type: 'courierService' },
COR: { model: courierModel, idField: '_id', type: 'courier' },
};
/** /**
* Get all models from the PREFIX_MODEL_MAP * Get all models from the PREFIX_MODEL_MAP
* @returns {Array} Array of model entries with model, idField, and type properties * @returns {Array} Array of model entries with model, idField, and type properties
*/ */
export const getAllModels = () => { export const getAllModels = () => {
return Object.values(models); return Object.values(PREFIX_MODEL_MAP);
}; };
/** /**
@ -14,7 +68,7 @@ export const getAllModels = () => {
* @returns {Object|null} The model entry or null if not found * @returns {Object|null} The model entry or null if not found
*/ */
export const getModelByName = (name) => { export const getModelByName = (name) => {
const entry = Object.values(models).find((entry) => entry.type === name); const entry = Object.values(PREFIX_MODEL_MAP).find((entry) => entry.type === name);
return entry || null; return entry || null;
}; };
@ -24,8 +78,8 @@ export const getModelByName = (name) => {
* @returns {Object|null} The model entry or null if not found * @returns {Object|null} The model entry or null if not found
*/ */
export const getModelByPrefix = (prefix) => { export const getModelByPrefix = (prefix) => {
return models[prefix] || null; return PREFIX_MODEL_MAP[prefix] || null;
}; };
// Export the PREFIX_MODEL_MAP for backward compatibility // Export the PREFIX_MODEL_MAP for backward compatibility
export { models }; export { PREFIX_MODEL_MAP };

View File

@ -60,7 +60,7 @@ export const getSpotlightRouteHandler = async (req, res) => {
res.status(200).send([]); res.status(200).send([]);
return; return;
} }
const prefix = query.substring(0, 3).toUpperCase(); const prefix = query.substring(0, 3);
const delimiter = query.substring(3, 4); const delimiter = query.substring(3, 4);
const suffix = query.substring(4); const suffix = query.substring(4);
@ -72,32 +72,18 @@ export const getSpotlightRouteHandler = async (req, res) => {
res.status(400).send({ error: 'Invalid or unsupported prefix' }); res.status(400).send({ error: 'Invalid or unsupported prefix' });
return; return;
} }
const { model, idField, type, referenceField } = prefixEntry; const { model, idField, type } = prefixEntry;
const suffixLength = suffix.length;
// Validate ObjectId if the idField is '_id' // Validate ObjectId if the idField is '_id'
if ( if (idField === '_id' && !mongoose.Types.ObjectId.isValid(suffix)) {
idField === '_id' &&
referenceField === '_reference' &&
!mongoose.Types.ObjectId.isValid(suffix) &&
suffixLength != 12
) {
res.status(200).send([]); res.status(200).send([]);
return; return;
} }
// Find the object by the correct field // Find the object by the correct field
const queryObj = {}; const queryObj = {};
queryObj[idField] = suffix.toLowerCase();
if (suffixLength == 12) {
queryObj[referenceField] = suffix.toUpperCase();
} else {
queryObj[idField] = suffix.toLowerCase();
}
let doc = await model.findOne(queryObj).lean(); let doc = await model.findOne(queryObj).lean();
if (!doc) { if (!doc) {
res.status(200).send([]); res.status(200).send([]);
return; return;

View File

@ -329,28 +329,9 @@ function getChangedValues(oldObj, newObj, old = false) {
changes[key] = nestedChanges; changes[key] = nestedChanges;
} }
} }
} else { } else if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
// Check if both values are numbers (or can be converted to numbers) // If the old value is different from the new value, include it
const oldIsNumber = changes[key] = old ? oldVal : newVal;
typeof oldVal === 'number' ||
(oldVal !== null && oldVal !== undefined && !isNaN(Number(oldVal)) && oldVal !== '');
const newIsNumber =
typeof newVal === 'number' ||
(newVal !== null && newVal !== undefined && !isNaN(Number(newVal)) && newVal !== '');
let valuesDiffer;
if (oldIsNumber && newIsNumber) {
// Compare numbers directly (this normalizes 7.50 to 7.5)
valuesDiffer = Number(oldVal) !== Number(newVal);
} else {
// Use JSON.stringify for non-number comparisons
valuesDiffer = JSON.stringify(oldVal) !== JSON.stringify(newVal);
}
if (valuesDiffer) {
// If the old value is different from the new value, include it
changes[key] = old ? oldVal : newVal;
}
} }
} }