Compare commits
No commits in common. "0fb0493d99252773cb7452c64de4851c07117333" and "944ad34f891bda92f5e625a28854f5d50d897a1c" have entirely different histories.
0fb0493d99
...
944ad34f89
@ -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) {
|
||||||
|
|||||||
@ -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,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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(
|
||||||
|
|||||||
@ -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 }
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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 }
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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);
|
|
||||||
@ -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);
|
|
||||||
@ -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' },
|
|
||||||
};
|
|
||||||
@ -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.`);
|
||||||
|
|||||||
@ -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({
|
||||||
|
|||||||
@ -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);
|
|
||||||
};
|
|
||||||
@ -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);
|
|
||||||
};
|
|
||||||
@ -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 };
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
25
src/utils.js
25
src/utils.js
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user