Compare commits

..

No commits in common. "a12ae1f340eb478a5c60ab121a287c009f6fba3a" and "9c4e0ee97485b3c4144a2bbf0cd2f632dd3c1a5b" have entirely different histories.

30 changed files with 352 additions and 1863 deletions

View File

@ -9,14 +9,14 @@
"keycloak": {
"url": "https://auth.tombutcher.work",
"realm": "master",
"clientId": "farmcontrol-dev"
"clientId": "farmcontrol-client"
},
"requiredRoles": []
},
"app": {
"urlClient": "https://dev.tombutcher.work",
"urlElectronClient": "http://localhost:5780",
"urlApi": "https://dev.tombutcher.work/api",
"urlClient": "http://localhost:3000",
"urlElectronClient": "http://localhost:3000",
"urlApi": "http://localhost:8787",
"devAuthClient": "http://localhost:3500"
},
"database": {

View File

@ -2,10 +2,6 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
// Load environment variables from .env file
dotenv.config();
// Configure paths relative to this file
const __filename = fileURLToPath(import.meta.url);

View File

@ -349,14 +349,12 @@ export const listObjects = async ({
filter = {},
sort = '',
order = 'ascend',
pagination = true,
project, // optional: override default projection
}) => {
try {
logger.trace('Listing object:', {
model,
populate,
pagination,
page,
limit,
filter,
@ -365,7 +363,7 @@ export const listObjects = async ({
project,
});
// Calculate the skip value based on the page number and limit
const skip = pagination ? (page - 1) * limit : 0;
const skip = (page - 1) * limit;
// Fix: descend should be -1, ascend should be 1
const sortOrder = order === 'descend' ? -1 : 1;
@ -391,7 +389,7 @@ export const listObjects = async ({
.find(filter)
.sort({ [sort]: sortOrder })
.skip(skip)
.limit(pagination ? Number(limit) : undefined);
.limit(Number(limit));
// Handle populate (array or single value)
if (populate) {
@ -601,7 +599,7 @@ export const listObjectsByProperties = async ({
} else {
// If no properties specified, just return all objects without grouping
// Ensure pipeline is not empty by adding a $match stage if needed
if (pipeline.length === 0 && masterFilter == {}) {
if (pipeline.length === 0) {
pipeline.push({ $match: {} });
}
const results = await model.aggregate(pipeline);
@ -733,25 +731,8 @@ export const listObjectDependencies = async ({ model, id }) => {
}
};
export const checkStates = async ({ model, id, states }) => {
try {
const object = await getObject({ model, id, cached: true });
if (!object?.state?.type) {
logger.warn(`Object ${id} has no state type.`);
return false;
}
if (states.includes(object?.state?.type)) {
return true;
}
return false;
} catch (error) {
logger.error('checkStates error:', error);
return { error: error.message, code: 500 };
}
};
// Reusable function to edit an object by ID, with audit logging and distribution
export const editObject = async ({ model, id, updateData, user, populate, recalculate = true }) => {
export const editObject = async ({ model, id, updateData, user, populate }) => {
try {
// Determine parentType from model name
const parentType = model.modelName ? model.modelName : 'unknown';
@ -829,7 +810,7 @@ export const editObject = async ({ model, id, updateData, user, populate, recalc
populate,
});
if (model.recalculate && recalculate == true) {
if (model.recalculate) {
logger.debug(`Recalculating ${model.modelName}`);
await model.recalculate(updatedObject, user);
}
@ -847,33 +828,6 @@ export const editObject = async ({ model, id, updateData, user, populate, recalc
}
};
// Reusable function to edit multiple objects
export const editObjects = async ({ model, updates, user, populate, recalculate = true }) => {
try {
const results = [];
for (const update of updates) {
const id = update._id || update.id;
const updateData = { ...update };
delete updateData._id;
delete updateData.id;
const result = await editObject({
model,
id,
updateData,
user,
populate,
recalculate,
});
results.push(result);
}
return results;
} catch (error) {
logger.error('editObjects error:', error);
return { error: error.message, code: 500 };
}
};
// Reusable function to create a new object
export const newObject = async ({ model, newData, user = null }, distributeChanges = true) => {
try {

View File

@ -1,98 +0,0 @@
import mongoose from 'mongoose';
import { generateId } from '../../utils.js';
const { Schema } = mongoose;
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
const invoiceSchema = new Schema(
{
_reference: { type: String, default: () => generateId()() },
totalAmount: { type: Number, required: true, default: 0 },
totalAmountWithTax: { type: Number, required: true, default: 0 },
shippingAmount: { type: Number, required: true, default: 0 },
shippingAmountWithTax: { type: Number, required: true, default: 0 },
grandTotalAmount: { type: Number, required: true, default: 0 },
totalTaxAmount: { type: Number, required: true, default: 0 },
timestamp: { type: Date, default: Date.now },
invoiceDate: { type: Date, required: false },
dueDate: { type: Date, required: false },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: false },
customer: { type: Schema.Types.ObjectId, ref: 'customer', required: false },
invoiceType: { type: String, required: true, default: 'sales', enum: ['sales', 'purchase'] },
relatedOrderType: { type: String, required: false },
relatedOrder: { type: Schema.Types.ObjectId, refPath: 'relatedOrderType', required: false },
state: {
type: { type: String, required: true, default: 'draft' },
},
sentAt: { type: Date, required: false },
paidAt: { type: Date, required: false },
cancelledAt: { type: Date, required: false },
overdueAt: { type: Date, required: false },
},
{ timestamps: true }
);
const rollupConfigs = [
{
name: 'draft',
filter: { 'state.type': 'draft' },
rollups: [{ name: 'draft', property: 'state.type', operation: 'count' }],
},
{
name: 'sent',
filter: { 'state.type': 'sent' },
rollups: [{ name: 'sent', property: 'state.type', operation: 'count' }],
},
{
name: 'partiallyPaid',
filter: { 'state.type': 'partiallyPaid' },
rollups: [{ name: 'partiallyPaid', property: 'state.type', operation: 'count' }],
},
{
name: 'paid',
filter: { 'state.type': 'paid' },
rollups: [{ name: 'paid', property: 'state.type', operation: 'count' }],
},
{
name: 'overdue',
filter: { 'state.type': 'overdue' },
rollups: [{ name: 'overdue', property: 'state.type', operation: 'count' }],
},
{
name: 'cancelled',
filter: { 'state.type': 'cancelled' },
rollups: [{ name: 'cancelled', property: 'state.type', operation: 'count' }],
},
];
invoiceSchema.statics.stats = async function () {
const results = await aggregateRollups({
model: this,
rollupConfigs: rollupConfigs,
});
// Transform the results to match the expected format
return results;
};
invoiceSchema.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
invoiceSchema.virtual('id').get(function () {
return this._id;
});
// Configure JSON serialization to include virtuals
invoiceSchema.set('toJSON', { virtuals: true });
// Create and export the model
export const invoiceModel = mongoose.model('invoice', invoiceSchema);

View File

@ -1,12 +1,6 @@
import mongoose from 'mongoose';
import { purchaseOrderModel } from './purchaseorder.schema.js';
import { taxRateModel } from '../management/taxrate.schema.js';
import {
aggregateRollups,
aggregateRollupsHistory,
editObject,
getObject,
} from '../../database.js';
import { aggregateRollups, editObject } from '../../database.js';
import { generateId } from '../../utils.js';
const { Schema } = mongoose;
@ -14,64 +8,20 @@ const orderItemSchema = new Schema(
{
_reference: { type: String, default: () => generateId()() },
orderType: { type: String, required: true },
state: {
type: { type: String, required: true, default: 'draft' },
},
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: false, default: null },
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 },
shipment: { type: Schema.Types.ObjectId, ref: 'shipment', required: false },
orderedAt: { type: Date, required: false },
receivedAt: { type: Date, required: false },
},
{ timestamps: true }
);
const rollupConfigs = [
{
name: 'shipped',
filter: { 'state.type': 'shipped' },
rollups: [{ name: 'shipped', property: 'state.type', operation: 'count' }],
},
{
name: 'received',
filter: { 'state.type': 'received' },
rollups: [{ name: 'received', property: 'state.type', operation: 'count' }],
},
];
orderItemSchema.statics.stats = async function () {
const results = await aggregateRollups({
model: this,
baseFilter: {},
rollupConfigs: rollupConfigs,
});
console.log(results);
// Transform the results to match the expected format
return results;
};
orderItemSchema.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;
};
orderItemSchema.statics.recalculate = async function (orderItem, user) {
// Only purchase orders are supported for now
if (orderItem.orderType !== 'purchaseOrder') {
@ -83,29 +33,6 @@ orderItemSchema.statics.recalculate = async function (orderItem, user) {
return;
}
var taxRate = orderItem.taxRate;
if (orderItem.taxRate?._id && Object.keys(orderItem.taxRate).length == 1) {
taxRate = await getObject({
model: taxRateModel,
id: orderItem.taxRate._id,
cached: true,
});
}
const orderTotalAmount = orderItem.itemAmount * orderItem.quantity;
const orderTotalAmountWithTax = orderTotalAmount * (1 + (taxRate?.rate || 0) / 100);
await editObject({
model: orderItemModel,
id: orderItem._id,
updateData: {
totalAmount: orderTotalAmount,
totalAmountWithTax: orderTotalAmountWithTax,
},
user,
recalculate: false,
});
const rollupResults = await aggregateRollups({
model: this,
baseFilter: {
@ -124,60 +51,21 @@ orderItemSchema.statics.recalculate = async function (orderItem, user) {
},
],
},
{
name: 'overallCount',
rollups: [{ name: 'overallCount', property: '_id', operation: 'count' }],
},
...rollupConfigs,
],
});
console.log('rollupResults', rollupResults);
const totals = rollupResults.orderTotals || {};
const totalAmount = totals.totalAmount.sum?.toFixed(2) || 0;
const totalAmountWithTax = totals.totalAmountWithTax.sum?.toFixed(2) || 0;
const purchaseOrder = await getObject({
model: purchaseOrderModel,
id: orderId,
cached: true,
});
const grandTotalAmount =
parseFloat(totalAmountWithTax || 0) + parseFloat(purchaseOrder.shippingAmountWithTax || 0);
var updateData = {
totalAmount: parseFloat(totalAmount).toFixed(2),
totalAmountWithTax: parseFloat(totalAmountWithTax).toFixed(2),
totalTaxAmount: parseFloat((totalAmountWithTax - totalAmount).toFixed(2)),
grandTotalAmount: parseFloat(grandTotalAmount).toFixed(2),
};
const overallCount = rollupResults.overallCount.count || 0;
const shippedCount = rollupResults.shipped.count || 0;
const receivedCount = rollupResults.received.count || 0;
if (shippedCount > 0 && shippedCount < overallCount) {
updateData = { ...updateData, state: { type: 'partiallyShipped' } };
}
if (shippedCount > 0 && shippedCount == overallCount) {
updateData = { ...updateData, state: { type: 'shipped' } };
}
if (receivedCount > 0 && receivedCount < overallCount) {
updateData = { ...updateData, state: { type: 'partiallyReceived' } };
}
if (receivedCount > 0 && receivedCount == overallCount) {
updateData = { ...updateData, state: { type: 'received' } };
}
await editObject({
model: purchaseOrderModel,
id: orderId,
updateData: updateData,
updateData: {
totalAmount: parseFloat(totalAmount),
totalAmountWithTax: parseFloat(totalAmountWithTax),
totalTaxAmount: parseFloat(totalAmountWithTax - totalAmount),
},
user,
});
};

View File

@ -1,100 +1,22 @@
import mongoose from 'mongoose';
import { generateId } from '../../utils.js';
const { Schema } = mongoose;
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
const purchaseOrderSchema = new Schema(
{
_reference: { type: String, default: () => generateId()() },
totalAmount: { type: Number, required: true, default: 0 },
totalAmountWithTax: { type: Number, required: true, default: 0 },
shippingAmount: { type: Number, required: true, default: 0 },
shippingAmountWithTax: { type: Number, required: true, default: 0 },
grandTotalAmount: { type: Number, required: true, default: 0 },
totalTaxAmount: { type: Number, required: true, default: 0 },
totalAmount: { type: Number, required: true },
totalAmountWithTax: { type: Number, required: true },
totalTaxAmount: { type: Number, required: true },
timestamp: { type: Date, default: Date.now },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
state: {
type: { type: String, required: true, default: 'draft' },
},
postedAt: { type: Date, required: false },
acknowledgedAt: { type: Date, required: false },
cancelledAt: { type: Date, required: false },
completedAt: { type: Date, required: false },
},
{ timestamps: true }
);
const rollupConfigs = [
{
name: 'draft',
filter: { 'state.type': 'draft' },
rollups: [{ name: 'draft', property: 'state.type', operation: 'count' }],
},
{
name: 'sent',
filter: { 'state.type': 'sent' },
rollups: [{ name: 'sent', property: 'state.type', operation: 'count' }],
},
{
name: 'acknowledged',
filter: { 'state.type': 'acknowledged' },
rollups: [{ name: 'acknowledged', property: 'state.type', operation: 'count' }],
},
{
name: 'partiallyShipped',
filter: { 'state.type': 'partiallyShipped' },
rollups: [{ name: 'partiallyShipped', property: 'state.type', operation: 'count' }],
},
{
name: 'shipped',
filter: { 'state.type': 'shipped' },
rollups: [{ name: 'shipped', property: 'state.type', operation: 'count' }],
},
{
name: 'partiallyReceived',
filter: { 'state.type': 'partiallyReceived' },
rollups: [{ name: 'partiallyReceived', property: 'state.type', operation: 'count' }],
},
{
name: 'received',
filter: { 'state.type': 'received' },
rollups: [{ name: 'received', property: 'state.type', operation: 'count' }],
},
{
name: 'cancelled',
filter: { 'state.type': 'cancelled' },
rollups: [{ name: 'cancelled', property: 'state.type', operation: 'count' }],
},
{
name: 'completed',
filter: { 'state.type': 'completed' },
rollups: [{ name: 'completed', property: 'state.type', operation: 'count' }],
},
];
purchaseOrderSchema.statics.stats = async function () {
const results = await aggregateRollups({
model: this,
rollupConfigs: rollupConfigs,
});
// Transform the results to match the expected format
return results;
};
purchaseOrderSchema.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
purchaseOrderSchema.virtual('id').get(function () {
return this._id;

View File

@ -1,108 +1,43 @@
import mongoose from 'mongoose';
import { generateId } from '../../utils.js';
const { Schema } = mongoose;
import { purchaseOrderModel } from './purchaseorder.schema.js';
import { taxRateModel } from '../management/taxrate.schema.js';
import { aggregateRollups, editObject, getObject } from '../../database.js';
const shipmentItemSchema = new Schema({
itemType: { type: String, required: true },
item: { type: Schema.Types.ObjectId, refPath: '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 shipmentSchema = new Schema(
{
_reference: { type: String, default: () => generateId()() },
orderType: { type: String, required: true },
order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
purchaseOrder: { type: Schema.Types.ObjectId, ref: 'purchaseOrder', required: true },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
courierService: { type: Schema.Types.ObjectId, ref: 'courierService', required: false },
trackingNumber: { type: String, required: false },
amount: { type: Number, required: true },
amountWithTax: { type: Number, required: true },
taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
shippedAt: { type: Date, required: false },
expectedAt: { type: Date, required: false },
deliveredAt: { type: Date, required: false },
cancelledAt: { type: Date, required: false },
items: [shipmentItemSchema],
cost: { net: { type: Number, required: true }, gross: { type: Number, required: true } },
shippedDate: { type: Date, required: false },
expectedDeliveryDate: { type: Date, required: false },
actualDeliveryDate: { type: Date, required: false },
state: {
type: {
type: String,
required: true,
default: 'pending',
enum: ['pending', 'shipped', 'in_transit', 'delivered', 'cancelled'],
},
},
notes: { type: String },
timestamp: { type: Date, default: Date.now },
},
{ timestamps: true }
);
shipmentSchema.statics.recalculate = async function (shipment, user) {
// Only purchase orders are supported for now
if (shipment.orderType !== 'purchaseOrder') {
return;
}
const orderId = shipment.order?._id || shipment.order;
if (!orderId) {
return;
}
var taxRate = shipment.taxRate;
if (shipment.taxRate?._id && Object.keys(shipment.taxRate).length == 1) {
taxRate = await getObject({
model: taxRateModel,
id: shipment.taxRate._id,
cached: true,
});
}
const amountWithTax = shipment.amount * (1 + (taxRate?.rate || 0) / 100);
await editObject({
model: shipmentModel,
id: shipment._id,
updateData: {
amountWithTax: amountWithTax,
},
user,
recalculate: false,
});
const rollupResults = await aggregateRollups({
model: this,
baseFilter: {
order: new mongoose.Types.ObjectId(orderId),
orderType: shipment.orderType,
},
rollupConfigs: [
{
name: 'shipmentTotals',
rollups: [
{ name: 'amount', property: 'amount', operation: 'sum' },
{ name: 'amountWithTax', property: 'amountWithTax', operation: 'sum' },
],
},
],
});
const totals = rollupResults.shipmentTotals || {};
const totalShippingAmount = totals.amount.sum?.toFixed(2) || 0;
const totalShippingAmountWithTax = totals.amountWithTax.sum?.toFixed(2) || 0;
const purchaseOrder = await getObject({
model: purchaseOrderModel,
id: orderId,
cached: true,
});
const grandTotalAmount =
parseFloat(purchaseOrder.totalAmountWithTax || 0) + parseFloat(totalShippingAmountWithTax || 0);
await editObject({
model: purchaseOrderModel,
id: orderId,
updateData: {
shippingAmount: parseFloat(totalShippingAmount).toFixed(2),
shippingAmountWithTax: parseFloat(totalShippingAmountWithTax).toFixed(2),
grandTotalAmount: parseFloat(grandTotalAmount).toFixed(2),
},
user,
recalculate: false,
});
};
// Add virtual id getter
shipmentSchema.virtual('id').get(function () {
return this._id;

View File

@ -24,10 +24,8 @@ 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/taxrate.schema.js';
import { taxRateModel } from './management/taxrates.schema.js';
import { taxRecordModel } from './management/taxrecord.schema.js';
import { shipmentModel } from './inventory/shipment.schema.js';
import { invoiceModel } from './finance/invoice.schema.js';
// Map prefixes to models and id fields
export const models = {
@ -100,6 +98,4 @@ export const models = {
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' },
SHP: { model: shipmentModel, idField: '_id', type: 'shipment', referenceField: '_reference' },
INV: { model: invoiceModel, idField: '_id', type: 'invoice', referenceField: '_reference' },
};

View File

@ -37,7 +37,6 @@ import {
courierServiceRoutes,
taxRateRoutes,
taxRecordRoutes,
invoiceRoutes,
} from './routes/index.js';
import path from 'path';
import * as fs from 'fs';
@ -140,7 +139,6 @@ app.use('/couriers', courierRoutes);
app.use('/courierservices', courierServiceRoutes);
app.use('/taxrates', taxRateRoutes);
app.use('/taxrecords', taxRecordRoutes);
app.use('/invoices', invoiceRoutes);
app.use('/notes', noteRoutes);
// Start the application

View File

@ -1,99 +0,0 @@
import express from 'express';
import { isAuthenticated } from '../../keycloak.js';
import { getFilter, convertPropertiesString } from '../../utils.js';
const router = express.Router();
import {
listInvoicesRouteHandler,
getInvoiceRouteHandler,
editInvoiceRouteHandler,
editMultipleInvoicesRouteHandler,
newInvoiceRouteHandler,
deleteInvoiceRouteHandler,
listInvoicesByPropertiesRouteHandler,
getInvoiceStatsRouteHandler,
getInvoiceHistoryRouteHandler,
sendInvoiceRouteHandler,
markInvoicePaidRouteHandler,
cancelInvoiceRouteHandler,
} from '../../services/finance/invoices.js';
// list of invoices
router.get('/', isAuthenticated, (req, res) => {
const { page, limit, property, search, sort, order } = req.query;
const allowedFilters = [
'vendor',
'customer',
'invoiceType',
'state',
'value',
'vendor._id',
'customer._id',
];
const filter = getFilter(req.query, allowedFilters);
listInvoicesRouteHandler(req, res, page, limit, property, filter, search, sort, order);
});
router.get('/properties', isAuthenticated, (req, res) => {
let properties = convertPropertiesString(req.query.properties);
const allowedFilters = [
'vendor',
'customer',
'invoiceType',
'state.type',
'value',
'vendor._id',
'customer._id',
];
const filter = getFilter(req.query, allowedFilters, false);
var masterFilter = {};
if (req.query.masterFilter) {
masterFilter = JSON.parse(req.query.masterFilter);
}
listInvoicesByPropertiesRouteHandler(req, res, properties, filter, masterFilter);
});
router.post('/', isAuthenticated, (req, res) => {
newInvoiceRouteHandler(req, res);
});
// get invoice stats
router.get('/stats', isAuthenticated, (req, res) => {
getInvoiceStatsRouteHandler(req, res);
});
// get invoice history
router.get('/history', isAuthenticated, (req, res) => {
getInvoiceHistoryRouteHandler(req, res);
});
router.get('/:id', isAuthenticated, (req, res) => {
getInvoiceRouteHandler(req, res);
});
// update multiple invoices
router.put('/', isAuthenticated, async (req, res) => {
editMultipleInvoicesRouteHandler(req, res);
});
router.put('/:id', isAuthenticated, async (req, res) => {
editInvoiceRouteHandler(req, res);
});
router.delete('/:id', isAuthenticated, async (req, res) => {
deleteInvoiceRouteHandler(req, res);
});
router.post('/:id/send', isAuthenticated, async (req, res) => {
sendInvoiceRouteHandler(req, res);
});
router.post('/:id/markpaid', isAuthenticated, async (req, res) => {
markInvoicePaidRouteHandler(req, res);
});
router.post('/:id/cancel', isAuthenticated, async (req, res) => {
cancelInvoiceRouteHandler(req, res);
});
export default router;

View File

@ -29,7 +29,6 @@ import courierRoutes from './management/courier.js';
import courierServiceRoutes from './management/courierservice.js';
import taxRateRoutes from './management/taxrates.js';
import taxRecordRoutes from './management/taxrecords.js';
import invoiceRoutes from './finance/invoices.js';
import noteRoutes from './misc/notes.js';
export {
@ -65,5 +64,4 @@ export {
courierServiceRoutes,
taxRateRoutes,
taxRecordRoutes,
invoiceRoutes,
};

View File

@ -7,7 +7,6 @@ import {
listFilamentStocksRouteHandler,
getFilamentStockRouteHandler,
editFilamentStockRouteHandler,
editMultipleFilamentStocksRouteHandler,
newFilamentStockRouteHandler,
deleteFilamentStockRouteHandler,
listFilamentStocksByPropertiesRouteHandler,
@ -52,11 +51,6 @@ router.get('/:id', isAuthenticated, (req, res) => {
getFilamentStockRouteHandler(req, res);
});
// update multiple filament stocks
router.put('/', isAuthenticated, async (req, res) => {
editMultipleFilamentStocksRouteHandler(req, res);
});
router.put('/:id', isAuthenticated, async (req, res) => {
editFilamentStockRouteHandler(req, res);
});

View File

@ -7,7 +7,6 @@ import {
listOrderItemsRouteHandler,
getOrderItemRouteHandler,
editOrderItemRouteHandler,
editMultipleOrderItemsRouteHandler,
newOrderItemRouteHandler,
deleteOrderItemRouteHandler,
listOrderItemsByPropertiesRouteHandler,
@ -18,32 +17,14 @@ import {
// list of order items
router.get('/', isAuthenticated, (req, res) => {
const { page, limit, property, search, sort, order } = req.query;
const allowedFilters = [
'itemType',
'item',
'item._id',
'order',
'order._id',
'orderType',
'shipment',
'shipment._id',
];
const allowedFilters = ['itemType', 'item', 'item._id', 'order', 'order._id', 'orderType'];
const filter = getFilter(req.query, allowedFilters);
listOrderItemsRouteHandler(req, res, page, limit, property, filter, search, sort, order);
});
router.get('/properties', isAuthenticated, (req, res) => {
let properties = convertPropertiesString(req.query.properties);
const allowedFilters = [
'itemType',
'item',
'item._id',
'order',
'order._id',
'orderType',
'shipment',
'shipment._id',
];
const allowedFilters = ['itemType', 'item', 'item._id', 'order', 'order._id', 'orderType'];
const filter = getFilter(req.query, allowedFilters, false);
var masterFilter = {};
if (req.query.masterFilter) {
@ -70,11 +51,6 @@ router.get('/:id', isAuthenticated, (req, res) => {
getOrderItemRouteHandler(req, res);
});
// update multiple order items
router.put('/', isAuthenticated, async (req, res) => {
editMultipleOrderItemsRouteHandler(req, res);
});
router.put('/:id', isAuthenticated, async (req, res) => {
editOrderItemRouteHandler(req, res);
});

View File

@ -7,7 +7,6 @@ import {
listPartStocksRouteHandler,
getPartStockRouteHandler,
editPartStockRouteHandler,
editMultiplePartStocksRouteHandler,
newPartStockRouteHandler,
deletePartStockRouteHandler,
listPartStocksByPropertiesRouteHandler,
@ -52,11 +51,6 @@ router.get('/:id', isAuthenticated, (req, res) => {
getPartStockRouteHandler(req, res);
});
// update multiple part stocks
router.put('/', isAuthenticated, async (req, res) => {
editMultiplePartStocksRouteHandler(req, res);
});
router.put('/:id', isAuthenticated, async (req, res) => {
editPartStockRouteHandler(req, res);
});

View File

@ -7,15 +7,11 @@ import {
listPurchaseOrdersRouteHandler,
getPurchaseOrderRouteHandler,
editPurchaseOrderRouteHandler,
editMultiplePurchaseOrdersRouteHandler,
newPurchaseOrderRouteHandler,
deletePurchaseOrderRouteHandler,
listPurchaseOrdersByPropertiesRouteHandler,
getPurchaseOrderStatsRouteHandler,
getPurchaseOrderHistoryRouteHandler,
postPurchaseOrderRouteHandler,
acknowledgePurchaseOrderRouteHandler,
cancelPurchaseOrderRouteHandler,
} from '../../services/inventory/purchaseorders.js';
// list of purchase orders
@ -32,7 +28,7 @@ router.get('/properties', isAuthenticated, (req, res) => {
const filter = getFilter(req.query, allowedFilters, false);
var masterFilter = {};
if (req.query.masterFilter) {
masterFilter = getFilter(JSON.parse(req.query.masterFilter), allowedFilters, true);
masterFilter = JSON.parse(req.query.masterFilter);
}
listPurchaseOrdersByPropertiesRouteHandler(req, res, properties, filter, masterFilter);
});
@ -55,11 +51,6 @@ router.get('/:id', isAuthenticated, (req, res) => {
getPurchaseOrderRouteHandler(req, res);
});
// update multiple purchase orders
router.put('/', isAuthenticated, async (req, res) => {
editMultiplePurchaseOrdersRouteHandler(req, res);
});
router.put('/:id', isAuthenticated, async (req, res) => {
editPurchaseOrderRouteHandler(req, res);
});
@ -68,16 +59,4 @@ router.delete('/:id', isAuthenticated, async (req, res) => {
deletePurchaseOrderRouteHandler(req, res);
});
router.post('/:id/post', isAuthenticated, async (req, res) => {
postPurchaseOrderRouteHandler(req, res);
});
router.post('/:id/acknowledge', isAuthenticated, async (req, res) => {
acknowledgePurchaseOrderRouteHandler(req, res);
});
router.post('/:id/cancel', isAuthenticated, async (req, res) => {
cancelPurchaseOrderRouteHandler(req, res);
});
export default router;

View File

@ -7,21 +7,24 @@ import {
listShipmentsRouteHandler,
getShipmentRouteHandler,
editShipmentRouteHandler,
editMultipleShipmentsRouteHandler,
newShipmentRouteHandler,
deleteShipmentRouteHandler,
listShipmentsByPropertiesRouteHandler,
getShipmentStatsRouteHandler,
getShipmentHistoryRouteHandler,
shipShipmentRouteHandler,
receiveShipmentRouteHandler,
cancelShipmentRouteHandler,
} from '../../services/inventory/shipments.js';
// list of shipments
router.get('/', isAuthenticated, (req, res) => {
const { page, limit, property, search, sort, order } = req.query;
const allowedFilters = ['orderType', 'order', 'state', 'courierService', 'order._id', 'taxRate'];
const allowedFilters = [
'vendor',
'purchaseOrder',
'state',
'courierService',
'vendor._id',
'purchaseOrder._id',
];
const filter = getFilter(req.query, allowedFilters);
listShipmentsRouteHandler(req, res, page, limit, property, filter, search, sort, order);
});
@ -29,17 +32,17 @@ router.get('/', isAuthenticated, (req, res) => {
router.get('/properties', isAuthenticated, (req, res) => {
let properties = convertPropertiesString(req.query.properties);
const allowedFilters = [
'orderType',
'order',
'vendor',
'purchaseOrder',
'state.type',
'courierService',
'order._id',
'taxRate',
'vendor._id',
'purchaseOrder._id',
];
const filter = getFilter(req.query, allowedFilters, false);
var masterFilter = {};
if (req.query.masterFilter) {
masterFilter = getFilter(JSON.parse(req.query.masterFilter), allowedFilters, true);
masterFilter = JSON.parse(req.query.masterFilter);
}
listShipmentsByPropertiesRouteHandler(req, res, properties, filter, masterFilter);
});
@ -62,11 +65,6 @@ router.get('/:id', isAuthenticated, (req, res) => {
getShipmentRouteHandler(req, res);
});
// update multiple shipments
router.put('/', isAuthenticated, async (req, res) => {
editMultipleShipmentsRouteHandler(req, res);
});
router.put('/:id', isAuthenticated, async (req, res) => {
editShipmentRouteHandler(req, res);
});
@ -75,16 +73,4 @@ router.delete('/:id', isAuthenticated, async (req, res) => {
deleteShipmentRouteHandler(req, res);
});
router.post('/:id/ship', isAuthenticated, async (req, res) => {
shipShipmentRouteHandler(req, res);
});
router.post('/:id/receive', isAuthenticated, async (req, res) => {
receiveShipmentRouteHandler(req, res);
});
router.post('/:id/cancel', isAuthenticated, async (req, res) => {
cancelShipmentRouteHandler(req, res);
});
export default router;

View File

@ -8,7 +8,6 @@ import {
getStockEventRouteHandler,
newStockEventRouteHandler,
editStockEventRouteHandler,
editMultipleStockEventsRouteHandler,
deleteStockEventRouteHandler,
listStockEventsByPropertiesRouteHandler,
getStockEventStatsRouteHandler,
@ -52,11 +51,6 @@ router.get('/:id', isAuthenticated, (req, res) => {
getStockEventRouteHandler(req, res);
});
// update multiple stock events
router.put('/', isAuthenticated, async (req, res) => {
editMultipleStockEventsRouteHandler(req, res);
});
router.put('/:id', isAuthenticated, async (req, res) => {
editStockEventRouteHandler(req, res);
});

View File

@ -8,7 +8,6 @@ import {
listFilamentsByPropertiesRouteHandler,
getFilamentRouteHandler,
editFilamentRouteHandler,
editMultipleFilamentsRouteHandler,
newFilamentRouteHandler,
getFilamentStatsRouteHandler,
getFilamentHistoryRouteHandler,
@ -67,11 +66,6 @@ router.get('/:id', isAuthenticated, (req, res) => {
getFilamentRouteHandler(req, res);
});
// update filaments info
router.put('/', isAuthenticated, async (req, res) => {
editMultipleFilamentsRouteHandler(req, res);
});
// update printer info
router.put('/:id', isAuthenticated, async (req, res) => {
editFilamentRouteHandler(req, res);

View File

@ -1,382 +0,0 @@
import config from '../../config.js';
import { invoiceModel } from '../../database/schemas/finance/invoice.schema.js';
import log4js from 'log4js';
import mongoose from 'mongoose';
import {
deleteObject,
listObjects,
getObject,
editObject,
editObjects,
newObject,
listObjectsByProperties,
getModelStats,
getModelHistory,
checkStates,
} from '../../database/database.js';
const logger = log4js.getLogger('Invoices');
logger.level = config.server.logLevel;
export const listInvoicesRouteHandler = async (
req,
res,
page = 1,
limit = 25,
property = '',
filter = {},
search = '',
sort = '',
order = 'ascend'
) => {
const populateFields = ['vendor', 'customer', 'relatedOrder'];
const result = await listObjects({
model: invoiceModel,
page,
limit,
property,
filter,
search,
sort,
order,
populate: populateFields,
});
if (result?.error) {
logger.error('Error listing invoices.');
res.status(result.code).send(result);
return;
}
logger.debug(`List of invoices (Page ${page}, Limit ${limit}). Count: ${result.length}`);
res.send(result);
};
export const listInvoicesByPropertiesRouteHandler = async (
req,
res,
properties = '',
filter = {},
masterFilter = {}
) => {
const populateFields = ['vendor', 'customer', 'relatedOrder'];
const result = await listObjectsByProperties({
model: invoiceModel,
properties,
filter,
populate: populateFields,
masterFilter,
});
if (result?.error) {
logger.error('Error listing invoices.');
res.status(result.code).send(result);
return;
}
logger.debug(`List of invoices. Count: ${result.length}`);
res.send(result);
};
export const getInvoiceRouteHandler = async (req, res) => {
const id = req.params.id;
const populateFields = ['vendor', 'customer', 'relatedOrder'];
const result = await getObject({
model: invoiceModel,
id,
populate: populateFields,
});
if (result?.error) {
logger.warn(`Invoice not found with supplied id.`);
return res.status(result.code).send(result);
}
logger.debug(`Retrieved invoice with ID: ${id}`);
res.send(result);
};
export const editInvoiceRouteHandler = async (req, res) => {
// Get ID from params
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Invoice with ID: ${id}`);
const checkStatesResult = await checkStates({ model: invoiceModel, id, states: ['draft'] });
if (checkStatesResult.error) {
logger.error('Error checking invoice states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Invoice is not in draft state.');
res.status(400).send({ error: 'Invoice is not in draft state.', code: 400 });
return;
}
const updateData = {
updatedAt: new Date(),
vendor: req.body.vendor,
customer: req.body.customer,
invoiceType: req.body.invoiceType,
invoiceDate: req.body.invoiceDate,
dueDate: req.body.dueDate,
relatedOrderType: req.body.relatedOrderType,
relatedOrder: req.body.relatedOrder,
};
// Create audit log before updating
const result = await editObject({
model: invoiceModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error editing invoice:', result.error);
res.status(result).send(result);
return;
}
logger.debug(`Edited invoice with ID: ${id}`);
res.send(result);
};
export const editMultipleInvoicesRouteHandler = async (req, res) => {
const updates = req.body.map((update) => ({
_id: update._id,
vendor: update.vendor,
customer: update.customer,
invoiceType: update.invoiceType,
}));
if (!Array.isArray(updates)) {
return res.status(400).send({ error: 'Body must be an array of updates.', code: 400 });
}
const result = await editObjects({
model: invoiceModel,
updates,
user: req.user,
});
if (result.error) {
logger.error('Error editing invoices:', result.error);
res.status(result.code || 500).send(result);
return;
}
logger.debug(`Edited ${updates.length} invoices`);
res.send(result);
};
export const newInvoiceRouteHandler = async (req, res) => {
const newData = {
updatedAt: new Date(),
vendor: req.body.vendor,
customer: req.body.customer,
invoiceType: req.body.invoiceType || 'sales',
invoiceDate: req.body.invoiceDate || new Date(),
dueDate: req.body.dueDate,
relatedOrderType: req.body.relatedOrderType,
relatedOrder: req.body.relatedOrder,
totalAmount: 0,
totalAmountWithTax: 0,
totalTaxAmount: 0,
grandTotalAmount: 0,
shippingAmount: 0,
shippingAmountWithTax: 0,
};
const result = await newObject({
model: invoiceModel,
newData,
user: req.user,
});
if (result.error) {
logger.error('No invoice created:', result.error);
return res.status(result.code).send(result);
}
logger.debug(`New invoice with ID: ${result._id}`);
res.send(result);
};
export const deleteInvoiceRouteHandler = async (req, res) => {
// Get ID from params
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Invoice with ID: ${id}`);
const result = await deleteObject({
model: invoiceModel,
id,
user: req.user,
});
if (result.error) {
logger.error('No invoice deleted:', result.error);
return res.status(result.code).send(result);
}
logger.debug(`Deleted invoice with ID: ${result._id}`);
res.send(result);
};
export const getInvoiceStatsRouteHandler = async (req, res) => {
const result = await getModelStats({ model: invoiceModel });
if (result?.error) {
logger.error('Error fetching invoice stats:', result.error);
return res.status(result.code).send(result);
}
logger.trace('Invoice stats:', result);
res.send(result);
};
export const getInvoiceHistoryRouteHandler = async (req, res) => {
const from = req.query.from;
const to = req.query.to;
const result = await getModelHistory({ model: invoiceModel, from, to });
if (result?.error) {
logger.error('Error fetching invoice history:', result.error);
return res.status(result.code).send(result);
}
logger.trace('Invoice history:', result);
res.send(result);
};
export const sendInvoiceRouteHandler = async (req, res) => {
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Invoice with ID: ${id}`);
const checkStatesResult = await checkStates({ model: invoiceModel, id, states: ['draft'] });
if (checkStatesResult.error) {
logger.error('Error checking invoice states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Invoice is not in draft state.');
res.status(400).send({ error: 'Invoice is not in draft state.', code: 400 });
return;
}
const updateData = {
updatedAt: new Date(),
state: { type: 'sent' },
sentAt: new Date(),
};
const result = await editObject({
model: invoiceModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error sending invoice:', result.error);
res.status(result.code).send(result);
return;
}
logger.debug(`Sent invoice with ID: ${id}`);
res.send(result);
};
export const markInvoicePaidRouteHandler = async (req, res) => {
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Invoice with ID: ${id}`);
const checkStatesResult = await checkStates({
model: invoiceModel,
id,
states: ['sent', 'partiallyPaid'],
});
if (checkStatesResult.error) {
logger.error('Error checking invoice states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Invoice is not in sent or partially paid state.');
res.status(400).send({ error: 'Invoice is not in sent or partially paid state.', code: 400 });
return;
}
const updateData = {
updatedAt: new Date(),
state: { type: 'paid' },
paidAt: new Date(),
};
const result = await editObject({
model: invoiceModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error marking invoice as paid:', result.error);
res.status(result.code).send(result);
return;
}
logger.debug(`Marked invoice as paid with ID: ${id}`);
res.send(result);
};
export const cancelInvoiceRouteHandler = async (req, res) => {
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Invoice with ID: ${id}`);
const checkStatesResult = await checkStates({
model: invoiceModel,
id,
states: ['draft', 'sent'],
});
if (checkStatesResult.error) {
logger.error('Error checking invoice states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Invoice is not in a cancellable state.');
res.status(400).send({
error: 'Invoice is not in a cancellable state (must be draft or sent).',
code: 400,
});
return;
}
const updateData = {
updatedAt: new Date(),
state: { type: 'cancelled' },
cancelledAt: new Date(),
};
const result = await editObject({
model: invoiceModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error cancelling invoice:', result.error);
res.status(result.code).send(result);
return;
}
logger.debug(`Cancelled invoice with ID: ${id}`);
res.send(result);
};

View File

@ -7,7 +7,6 @@ import {
listObjects,
getObject,
editObject,
editObjects,
newObject,
listObjectsByProperties,
getModelStats,
@ -115,32 +114,6 @@ export const editFilamentStockRouteHandler = async (req, res) => {
res.send(result);
};
export const editMultipleFilamentStocksRouteHandler = async (req, res) => {
const updates = req.body.map((update) => ({
_id: update._id,
}));
if (!Array.isArray(updates)) {
return res.status(400).send({ error: 'Body must be an array of updates.', code: 400 });
}
const result = await editObjects({
model: filamentStockModel,
updates,
user: req.user,
});
if (result.error) {
logger.error('Error editing filament stocks:', result.error);
res.status(result.code || 500).send(result);
return;
}
logger.debug(`Edited ${updates.length} filament stocks`);
res.send(result);
};
export const newFilamentStockRouteHandler = async (req, res) => {
const newData = {
updatedAt: new Date(),

View File

@ -7,7 +7,6 @@ import {
listObjects,
getObject,
editObject,
editObjects,
newObject,
listObjectsByProperties,
getModelStats,
@ -44,10 +43,6 @@ export const listOrderItemsRouteHandler = async (
path: 'taxRate',
strictPopulate: false,
},
{
path: 'shipment',
strictPopulate: false,
},
{
path: 'item',
populate: { path: 'costTaxRate', strictPopulate: false },
@ -143,7 +138,6 @@ export const editOrderItemRouteHandler = async (req, res) => {
itemAmount: req.body.itemAmount,
quantity: req.body.quantity,
totalAmount: req.body.totalAmount,
shipment: req.body.shipment,
taxRate: req.body.taxRate,
totalAmountWithTax: req.body.totalAmountWithTax,
};
@ -166,43 +160,6 @@ export const editOrderItemRouteHandler = async (req, res) => {
res.send(result);
};
export const editMultipleOrderItemsRouteHandler = async (req, res) => {
const updates = req.body.map((update) => ({
_id: update._id,
itemType: update.itemType,
item: update.item,
orderType: update.orderType,
order: update.order,
syncAmount: update.syncAmount,
itemAmount: update.itemAmount,
quantity: update.quantity,
totalAmount: update.totalAmount,
shipment: update.shipment,
taxRate: update.taxRate,
totalAmountWithTax: update.totalAmountWithTax,
}));
if (!Array.isArray(updates)) {
return res.status(400).send({ error: 'Body must be an array of updates.', code: 400 });
}
const result = await editObjects({
model: orderItemModel,
updates,
user: req.user,
});
if (result.error) {
logger.error('Error editing order items:', result.error);
res.status(result.code || 500).send(result);
return;
}
logger.debug(`Edited ${updates.length} order items`);
res.send(result);
};
export const newOrderItemRouteHandler = async (req, res) => {
const newData = {
updatedAt: new Date(),
@ -218,7 +175,6 @@ export const newOrderItemRouteHandler = async (req, res) => {
totalAmount: req.body.totalAmount,
taxRate: req.body.taxRate,
totalAmountWithTax: req.body.totalAmountWithTax,
shipment: req.body.shipment,
};
const result = await newObject({
model: orderItemModel,

View File

@ -7,7 +7,6 @@ import {
listObjects,
getObject,
editObject,
editObjects,
newObject,
listObjectsByProperties,
getModelStats,
@ -115,32 +114,6 @@ export const editPartStockRouteHandler = async (req, res) => {
res.send(result);
};
export const editMultiplePartStocksRouteHandler = async (req, res) => {
const updates = req.body.map((update) => ({
_id: update._id,
}));
if (!Array.isArray(updates)) {
return res.status(400).send({ error: 'Body must be an array of updates.', code: 400 });
}
const result = await editObjects({
model: partStockModel,
updates,
user: req.user,
});
if (result.error) {
logger.error('Error editing part stocks:', result.error);
res.status(result.code || 500).send(result);
return;
}
logger.debug(`Edited ${updates.length} part stocks`);
res.send(result);
};
export const newPartStockRouteHandler = async (req, res) => {
const newData = {
updatedAt: new Date(),

View File

@ -7,15 +7,11 @@ import {
listObjects,
getObject,
editObject,
editObjects,
newObject,
listObjectsByProperties,
getModelStats,
getModelHistory,
checkStates,
} from '../../database/database.js';
import { orderItemModel } from '../../database/schemas/inventory/orderitem.schema.js';
import { shipmentModel } from '../../database/schemas/inventory/shipment.schema.js';
const logger = log4js.getLogger('Purchase Orders');
logger.level = config.server.logLevel;
@ -99,20 +95,6 @@ export const editPurchaseOrderRouteHandler = async (req, res) => {
logger.trace(`Purchase Order with ID: ${id}`);
const checkStatesResult = await checkStates({ model: purchaseOrderModel, id, states: ['draft'] });
if (checkStatesResult.error) {
logger.error('Error checking purchase order states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Purchase order is not in draft state.');
res.status(400).send({ error: 'Purchase order is not in draft state.', code: 400 });
return;
}
const updateData = {
updatedAt: new Date(),
vendor: req.body.vendor,
@ -136,40 +118,10 @@ export const editPurchaseOrderRouteHandler = async (req, res) => {
res.send(result);
};
export const editMultiplePurchaseOrdersRouteHandler = async (req, res) => {
const updates = req.body.map((update) => ({
_id: update._id,
vendor: update.vendor,
}));
if (!Array.isArray(updates)) {
return res.status(400).send({ error: 'Body must be an array of updates.', code: 400 });
}
const result = await editObjects({
model: purchaseOrderModel,
updates,
user: req.user,
});
if (result.error) {
logger.error('Error editing purchase orders:', result.error);
res.status(result.code || 500).send(result);
return;
}
logger.debug(`Edited ${updates.length} purchase orders`);
res.send(result);
};
export const newPurchaseOrderRouteHandler = async (req, res) => {
const newData = {
updatedAt: new Date(),
vendor: req.body.vendor,
totalAmount: 0,
totalAmountWithTax: 0,
totalTaxAmount: 0,
};
const result = await newObject({
model: purchaseOrderModel,
@ -228,232 +180,3 @@ export const getPurchaseOrderHistoryRouteHandler = async (req, res) => {
logger.trace('Purchase order history:', result);
res.send(result);
};
export const postPurchaseOrderRouteHandler = async (req, res) => {
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Purchase Order with ID: ${id}`);
const checkStatesResult = await checkStates({ model: purchaseOrderModel, id, states: ['draft'] });
if (checkStatesResult.error) {
logger.error('Error checking purchase order states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Purchase order is not in draft state.');
res.status(400).send({ error: 'Purchase order is not in draft state.', code: 400 });
return;
}
const orderItemsResult = await listObjects({
model: orderItemModel,
filter: { order: id, orderType: 'purchaseOrder' },
pagination: false,
});
const shipmentsResult = await listObjects({
model: shipmentModel,
filter: { order: id, orderType: 'purchaseOrder' },
pagination: false,
});
for (const orderItem of orderItemsResult) {
if (orderItem.state.type != 'draft') {
logger.warn(`Order item ${orderItem._id} is not in draft state.`);
return res
.status(400)
.send({ error: `Order item ${orderItem._reference} not in draft state.`, code: 400 });
}
if (!orderItem?.shipment || orderItem?.shipment == null) {
logger.warn(`Order item ${orderItem._id} does not have a shipment.`);
return res
.status(400)
.send({ error: `Order item ${orderItem._reference} does not have a shipment.`, code: 400 });
}
}
for (const shipment of shipmentsResult) {
if (shipment.state.type != 'draft') {
logger.warn(`Shipment ${shipment._id} is not in draft state.`);
return res
.status(400)
.send({ error: `Shipment ${shipment._reference} not in draft state.`, code: 400 });
}
}
for (const orderItem of orderItemsResult) {
await editObject({
model: orderItemModel,
id: orderItem._id,
updateData: {
state: { type: 'ordered' },
orderedAt: new Date(),
},
user: req.user,
});
}
for (const shipment of shipmentsResult) {
await editObject({
model: shipmentModel,
id: shipment._id,
updateData: {
state: { type: 'planned' },
},
user: req.user,
});
}
const updateData = {
updatedAt: new Date(),
state: { type: 'sent' },
postedAt: new Date(),
};
const result = await editObject({
model: purchaseOrderModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error posting purchase order:', result.error);
res.status(result.code).send(result);
return;
}
logger.debug(`Posted purchase order with ID: ${id}`);
res.send(result);
};
export const acknowledgePurchaseOrderRouteHandler = async (req, res) => {
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Purchase Order with ID: ${id}`);
const checkStatesResult = await checkStates({ model: purchaseOrderModel, id, states: ['sent'] });
if (checkStatesResult.error) {
logger.error('Error checking purchase order states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Purchase order is not in sent state.');
res.status(400).send({ error: 'Purchase order is not in sent state.', code: 400 });
return;
}
const updateData = {
updatedAt: new Date(),
state: { type: 'acknowledged' },
acknowledgedAt: new Date(),
};
const result = await editObject({
model: purchaseOrderModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error acknowledging purchase order:', result.error);
res.status(result.code).send(result);
return;
}
logger.debug(`Acknowledged purchase order with ID: ${id}`);
res.send(result);
};
export const cancelPurchaseOrderRouteHandler = async (req, res) => {
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Purchase Order with ID: ${id}`);
const checkStatesResult = await checkStates({
model: purchaseOrderModel,
id,
states: ['sent', 'acknowledged', 'partiallyShipped', 'shipped', 'partiallyReceived'],
});
if (checkStatesResult.error) {
logger.error('Error checking purchase order states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Purchase order is not in a cancellable state.');
res.status(400).send({
error: 'Purchase order is not in a cancellable state (must be draft, sent, or acknowledged).',
code: 400,
});
return;
}
const orderItemsResult = await listObjects({
model: orderItemModel,
filter: { order: id, orderType: 'purchaseOrder' },
pagination: false,
});
const shipmentsResult = await listObjects({
model: shipmentModel,
filter: { order: id, orderType: 'purchaseOrder' },
pagination: false,
});
const allowedOrderItemStates = ['ordered', 'shipped'];
const allowedShipmentStates = ['shipped', 'planned'];
for (const orderItem of orderItemsResult) {
if (allowedOrderItemStates.includes(orderItem.state.type)) {
await editObject({
model: orderItemModel,
id: orderItem._id,
updateData: {
state: { type: 'cancelled' },
},
user: req.user,
});
}
}
for (const shipment of shipmentsResult) {
if (allowedShipmentStates.includes(shipment.state.type)) {
await editObject({
model: shipmentModel,
id: shipment._id,
updateData: {
state: { type: 'cancelled' },
},
user: req.user,
});
}
}
const updateData = {
updatedAt: new Date(),
state: { type: 'cancelled' },
cancelledAt: new Date(),
};
const result = await editObject({
model: purchaseOrderModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error cancelling purchase order:', result.error);
res.status(result.code).send(result);
return;
}
logger.debug(`Cancelled purchase order with ID: ${id}`);
res.send(result);
};

View File

@ -7,16 +7,13 @@ import {
listObjects,
getObject,
editObject,
editObjects,
newObject,
listObjectsByProperties,
getModelStats,
getModelHistory,
checkStates,
} from '../../database/database.js';
const logger = log4js.getLogger('Shipments');
logger.level = config.server.logLevel;
import { orderItemModel } from '../../database/schemas/inventory/orderitem.schema.js';
export const listShipmentsRouteHandler = async (
req,
@ -38,7 +35,7 @@ export const listShipmentsRouteHandler = async (
search,
sort,
order,
populate: ['order', 'courierService', 'taxRate'],
populate: ['purchaseOrder', 'vendor', 'courierService'],
});
if (result?.error) {
@ -62,7 +59,7 @@ export const listShipmentsByPropertiesRouteHandler = async (
model: shipmentModel,
properties,
filter,
populate: ['courierService'],
populate: ['purchaseOrder', 'vendor', 'courierService'],
masterFilter,
});
@ -81,7 +78,7 @@ export const getShipmentRouteHandler = async (req, res) => {
const result = await getObject({
model: shipmentModel,
id,
populate: ['order', 'courierService', 'taxRate'],
populate: ['purchaseOrder', 'vendor', 'courierService', 'items.item', 'items.taxRate'],
});
if (result?.error) {
logger.warn(`Shipment not found with supplied id.`);
@ -99,13 +96,15 @@ export const editShipmentRouteHandler = async (req, res) => {
const updateData = {
updatedAt: new Date(),
orderType: req.body.orderType,
order: req.body.order,
purchaseOrder: req.body.purchaseOrder,
vendor: req.body.vendor,
courierService: req.body.courierService,
trackingNumber: req.body.trackingNumber,
amount: req.body.amount,
amountWithTax: req.body.amountWithTax,
taxRate: req.body.taxRate,
shippedDate: req.body.shippedDate,
expectedDeliveryDate: req.body.expectedDeliveryDate,
actualDeliveryDate: req.body.actualDeliveryDate,
state: req.body.state,
notes: req.body.notes,
};
// Create audit log before updating
const result = await editObject({
@ -126,53 +125,20 @@ export const editShipmentRouteHandler = async (req, res) => {
res.send(result);
};
export const editMultipleShipmentsRouteHandler = async (req, res) => {
const updates = req.body.map((update) => ({
_id: update._id,
orderType: update.orderType,
order: update.order,
courierService: update.courierService,
trackingNumber: update.trackingNumber,
amount: update.amount,
amountWithTax: update.amountWithTax,
taxRate: update.taxRate,
}));
if (!Array.isArray(updates)) {
return res.status(400).send({ error: 'Body must be an array of updates.', code: 400 });
}
const result = await editObjects({
model: shipmentModel,
updates,
user: req.user,
});
if (result.error) {
logger.error('Error editing shipments:', result.error);
res.status(result.code || 500).send(result);
return;
}
logger.debug(`Edited ${updates.length} shipments`);
res.send(result);
};
export const newShipmentRouteHandler = async (req, res) => {
const newData = {
updatedAt: new Date(),
orderType: req.body.orderType,
order: req.body.order,
purchaseOrder: req.body.purchaseOrder,
vendor: req.body.vendor,
courierService: req.body.courierService,
trackingNumber: req.body.trackingNumber,
amount: req.body.amount,
amountWithTax: req.body.amountWithTax,
taxRate: req.body.taxRate,
shippedAt: req.body.shippedAt,
expectedAt: req.body.expectedAt,
deliveredAt: req.body.deliveredAt,
state: { type: 'draft' },
items: req.body.items,
cost: req.body.cost,
shippedDate: req.body.shippedDate,
expectedDeliveryDate: req.body.expectedDeliveryDate,
actualDeliveryDate: req.body.actualDeliveryDate,
state: req.body.state,
notes: req.body.notes,
};
const result = await newObject({
model: shipmentModel,
@ -231,212 +197,3 @@ export const getShipmentHistoryRouteHandler = async (req, res) => {
logger.trace('Shipment history:', result);
res.send(result);
};
export const shipShipmentRouteHandler = async (req, res) => {
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Shipment with ID: ${id}`);
const checkStatesResult = await checkStates({ model: shipmentModel, id, states: ['planned'] });
if (checkStatesResult.error) {
logger.error('Error checking shipment states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Shipment is not in planned state.');
res.status(400).send({ error: 'Shipment is not in planned state.', code: 400 });
return;
}
const orderItemsResult = await listObjects({
model: orderItemModel,
filter: { shipment: id },
pagination: false,
});
if (orderItemsResult.error) {
logger.error('Error listing order items:', orderItemsResult.error);
res.status(orderItemsResult.code).send(orderItemsResult);
return;
}
for (const orderItem of orderItemsResult) {
if (orderItem.state.type != 'ordered') {
logger.error('Order item is not in ordered state.');
res.status(400).send({ error: 'Order item is not in ordered state.', code: 400 });
return;
}
}
for (const orderItem of orderItemsResult) {
await editObject({
model: orderItemModel,
id: orderItem._id,
user: req.user,
updateData: {
state: { type: 'shipped' },
receivedAt: new Date(),
},
});
}
const updateData = {
state: { type: 'shipped' },
shippedAt: new Date(),
};
const result = await editObject({ model: shipmentModel, id, updateData, user: req.user });
if (result.error) {
logger.error('Error shipping shipment:', result.error);
res.status(result.code).send(result);
return;
}
logger.debug(`Shipped shipment with ID: ${id}`);
res.send(result);
return;
};
export const receiveShipmentRouteHandler = async (req, res) => {
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Shipment with ID: ${id}`);
const checkStatesResult = await checkStates({ model: shipmentModel, id, states: ['shipped'] });
if (checkStatesResult.error) {
logger.error('Error checking shipment states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Shipment is not in shipped state.');
res.status(400).send({ error: 'Shipment is not in shipped state.', code: 400 });
return;
}
const orderItemsResult = await listObjects({
model: orderItemModel,
filter: { shipment: id },
pagination: false,
});
if (orderItemsResult.error) {
logger.error('Error listing order items:', orderItemsResult.error);
res.status(orderItemsResult.code).send(orderItemsResult);
return;
}
for (const orderItem of orderItemsResult) {
if (orderItem.state.type != 'shipped') {
logger.error('Order item is not in shipped state.');
res.status(400).send({ error: 'Order item is not in shipped state.', code: 400 });
return;
}
}
for (const orderItem of orderItemsResult) {
await editObject({
model: orderItemModel,
id: orderItem._id,
updateData: {
state: { type: 'received' },
receivedAt: new Date(),
},
user: req.user,
});
}
const result = await editObject({
model: shipmentModel,
id,
updateData: {
state: { type: 'delivered' },
deliveredAt: new Date(),
},
user: req.user,
});
if (result.error) {
logger.error('Error receiving shipment:', result.error);
res.status(result.code).send(result);
return;
}
logger.debug(`Received shipment with ID: ${id}`);
res.send(result);
};
export const cancelShipmentRouteHandler = async (req, res) => {
const id = new mongoose.Types.ObjectId(req.params.id);
logger.trace(`Shipment with ID: ${id}`);
const checkStatesResult = await checkStates({
model: shipmentModel,
id,
states: ['planned', 'shipped'],
});
if (checkStatesResult.error) {
logger.error('Error checking shipment states:', checkStatesResult.error);
res.status(checkStatesResult.code).send(checkStatesResult);
return;
}
if (checkStatesResult === false) {
logger.error('Shipment is not in a cancellable state.');
res.status(400).send({
error: 'Shipment is not in a cancellable state (must be planned or shipped).',
code: 400,
});
return;
}
const orderItemsResult = await listObjects({
model: orderItemModel,
filter: { shipment: id },
pagination: false,
});
if (orderItemsResult.error) {
logger.error('Error listing order items:', orderItemsResult.error);
res.status(orderItemsResult.code).send(orderItemsResult);
return;
}
// Cancel related order items if they are in cancellable states
for (const orderItem of orderItemsResult) {
if (orderItem.state.type === 'draft' || orderItem.state.type === 'ordered') {
await editObject({
model: orderItemModel,
id: orderItem._id,
updateData: {
state: { type: 'cancelled' },
},
user: req.user,
});
}
}
const updateData = {
updatedAt: new Date(),
state: { type: 'cancelled' },
cancelledAt: new Date(),
};
const result = await editObject({
model: shipmentModel,
id,
updateData,
user: req.user,
});
if (result.error) {
logger.error('Error cancelling shipment:', result.error);
res.status(result.code).send(result);
return;
}
logger.debug(`Cancelled shipment with ID: ${id}`);
res.send(result);
};

View File

@ -7,7 +7,6 @@ import {
listObjects,
getObject,
editObject,
editObjects,
newObject,
listObjectsByProperties,
getModelStats,
@ -146,32 +145,6 @@ export const editStockEventRouteHandler = async (req, res) => {
res.send(result);
};
export const editMultipleStockEventsRouteHandler = async (req, res) => {
const updates = req.body.map((update) => ({
_id: update._id,
}));
if (!Array.isArray(updates)) {
return res.status(400).send({ error: 'Body must be an array of updates.', code: 400 });
}
const result = await editObjects({
model: stockEventModel,
updates,
user: req.user,
});
if (result.error) {
logger.error('Error editing stock events:', result.error);
res.status(result.code || 500).send(result);
return;
}
logger.debug(`Edited ${updates.length} stock events`);
res.send(result);
};
export const deleteStockEventRouteHandler = async (req, res) => {
// Get ID from params
const id = new mongoose.Types.ObjectId(req.params.id);

View File

@ -7,7 +7,6 @@ import {
listObjects,
listObjectsByProperties,
editObject,
editObjects,
newObject,
getModelStats,
getModelHistory,
@ -59,16 +58,7 @@ export const listFilamentsByPropertiesRouteHandler = async (
model: filamentModel,
properties,
filter,
populate: [
{
path: 'vendor',
from: 'vendors',
},
{
path: 'costTaxRate',
from: 'taxrates',
},
],
populate: 'vendor',
});
if (result?.error) {
@ -136,45 +126,6 @@ export const editFilamentRouteHandler = async (req, res) => {
res.send(result);
};
export const editMultipleFilamentsRouteHandler = async (req, res) => {
const updates = req.body.map((update) => ({
_id: update._id,
name: update.name,
barcode: update.barcode,
url: update.url,
image: update.image,
color: update.color,
vendor: update.vendor,
type: update.type,
cost: update.cost,
costTaxRate: update.costTaxRate,
costWithTax: update.costWithTax,
diameter: update.diameter,
density: update.density,
emptySpoolWeight: update.emptySpoolWeight,
}));
if (!Array.isArray(updates)) {
return res.status(400).send({ error: 'Body must be an array of updates.', code: 400 });
}
const result = await editObjects({
model: filamentModel,
updates,
user: req.user,
});
if (result.error) {
logger.error('Error editing filaments:', result.error);
res.status(result.code || 500).send(result);
return;
}
logger.debug(`Edited ${updates.length} filaments`);
res.send(result);
};
export const newFilamentRouteHandler = async (req, res) => {
const newData = {
createdAt: new Date(),

View File

@ -1,5 +1,5 @@
import config from '../../config.js';
import { taxRateModel } from '../../database/schemas/management/taxrate.schema.js';
import { taxRateModel } from '../../database/schemas/management/taxrates.schema.js';
import log4js from 'log4js';
import mongoose from 'mongoose';
import {

View File

@ -1,4 +1,4 @@
import { mongoose } from 'mongoose';
import { ObjectId } from 'mongodb';
import { auditLogModel } from './database/schemas/management/auditlog.schema.js';
import exifr from 'exifr';
import { natsServer } from './database/nats.js';
@ -20,9 +20,6 @@ function buildWildcardRegexPattern(input) {
}
function parseFilter(property, value) {
if (value?._id !== undefined && value?._id !== null) {
return { [property]: { _id: new mongoose.Types.ObjectId(value._id) } };
}
if (typeof value === 'string') {
var trimmed = value.trim();
if (trimmed.charAt(3) == ':') {
@ -36,7 +33,7 @@ function parseFilter(property, value) {
// Handle ObjectId (24-char hex)
if (/^[a-f\d]{24}$/i.test(trimmed) && trimmed.length >= 24) {
return { [property]: new mongoose.Types.ObjectId(trimmed) };
return { [property]: new ObjectId(trimmed) };
}
// Handle numbers
@ -517,7 +514,7 @@ function expandObjectIds(input) {
// Helper to check if a value is an ObjectId or a 24-char hex string
function isObjectId(val) {
// Check for MongoDB ObjectId instance
if (val instanceof mongoose.Types.ObjectId) return true;
if (val instanceof ObjectId) return true;
// Check for exactly 24 hex characters (no special characters)
if (typeof val === 'string' && /^[a-fA-F\d]{24}$/.test(val)) return true;
return false;
@ -527,7 +524,7 @@ function expandObjectIds(input) {
function expand(value) {
if (Array.isArray(value)) {
return value.map(expand);
} else if (value && typeof value === 'object' && !(value instanceof mongoose.Types.ObjectId)) {
} else if (value && typeof value === 'object' && !(value instanceof ObjectId)) {
var result = {};
for (const [key, val] of Object.entries(value)) {
if (key === '_id') {

379
yarn.lock
View File

@ -45,7 +45,7 @@
"@smithy/util-utf8" "^2.0.0"
tslib "^2.6.2"
"@aws-crypto/sha256-js@5.2.0", "@aws-crypto/sha256-js@^5.2.0":
"@aws-crypto/sha256-js@^5.2.0", "@aws-crypto/sha256-js@5.2.0":
version "5.2.0"
resolved "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz"
integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==
@ -61,7 +61,7 @@
dependencies:
tslib "^2.6.2"
"@aws-crypto/util@5.2.0", "@aws-crypto/util@^5.2.0":
"@aws-crypto/util@^5.2.0", "@aws-crypto/util@5.2.0":
version "5.2.0"
resolved "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz"
integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==
@ -514,7 +514,7 @@
"@smithy/types" "^4.9.0"
tslib "^2.6.2"
"@aws-sdk/types@3.930.0", "@aws-sdk/types@^3.222.0":
"@aws-sdk/types@^3.222.0", "@aws-sdk/types@3.930.0":
version "3.930.0"
resolved "https://registry.npmjs.org/@aws-sdk/types/-/types-3.930.0.tgz"
integrity sha512-we/vaAgwlEFW7IeftmCLlLMw+6hFs3DzZPJw7lVHbj/5HJ0bz9gndxEsS2lQoeJ1zhiiLqAqvXxmM43s0MBg0A==
@ -622,7 +622,7 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz"
integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==
"@babel/core@^7.28.5":
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.28.5", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0":
version "7.28.5"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz"
integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==
@ -1527,6 +1527,34 @@
"@eslint/core" "^0.17.0"
levn "^0.4.1"
"@grpc/grpc-js@^1.8.20":
version "1.14.1"
resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.1.tgz"
integrity sha512-sPxgEWtPUR3EnRJCEtbGZG2iX8LQDUls2wUS3o27jg07KqJFMq6YDeWvMo1wfpmy3rqRdS0rivpLwhqQtEyCuQ==
dependencies:
"@grpc/proto-loader" "^0.8.0"
"@js-sdsl/ordered-map" "^4.4.2"
"@grpc/proto-loader@^0.7.8":
version "0.7.15"
resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz"
integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==
dependencies:
lodash.camelcase "^4.3.0"
long "^5.0.0"
protobufjs "^7.2.5"
yargs "^17.7.2"
"@grpc/proto-loader@^0.8.0":
version "0.8.0"
resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz"
integrity sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==
dependencies:
lodash.camelcase "^4.3.0"
long "^5.0.0"
protobufjs "^7.5.3"
yargs "^17.7.2"
"@humanfs/core@^0.19.1":
version "0.19.1"
resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz"
@ -1610,6 +1638,11 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@js-sdsl/ordered-map@^4.4.2":
version "4.4.2"
resolved "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz"
integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==
"@mongodb-js/saslprep@^1.3.0":
version "1.3.2"
resolved "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.2.tgz"
@ -1687,12 +1720,65 @@
resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz"
integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz"
integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
"@protobufjs/base64@^1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz"
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
"@protobufjs/codegen@^2.0.4":
version "2.0.4"
resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz"
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
"@protobufjs/eventemitter@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz"
integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
"@protobufjs/fetch@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz"
integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
dependencies:
"@protobufjs/aspromise" "^1.1.1"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/float@^1.0.2":
version "1.0.2"
resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz"
integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
"@protobufjs/inquire@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz"
integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
"@protobufjs/path@^1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz"
integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
"@protobufjs/pool@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz"
integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
"@protobufjs/utf8@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz"
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
"@redis/bloom@5.10.0":
version "5.10.0"
resolved "https://registry.npmjs.org/@redis/bloom/-/bloom-5.10.0.tgz"
integrity sha512-doIF37ob+l47n0rkpRNgU8n4iacBlKM9xLiP1LtTZTvz8TloJB8qx/MgvhMhKdYG+CvCY2aPBnN2706izFn/4A==
"@redis/client@5.10.0":
"@redis/client@^5.10.0", "@redis/client@5.10.0":
version "5.10.0"
resolved "https://registry.npmjs.org/@redis/client/-/client-5.10.0.tgz"
integrity sha512-JXmM4XCoso6C75Mr3lhKA3eNxSzkYi3nCzxDIKY+YOszYsJjuKbFgVtguVPbLMOttN4iu2fXoc2BGhdnYhIOxA==
@ -2256,7 +2342,7 @@
resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz"
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
"@types/node@*":
"@types/node@*", "@types/node@>=13.7.0":
version "24.10.1"
resolved "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz"
integrity sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==
@ -2310,7 +2396,7 @@ acorn-jsx@^5.3.2:
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn@^8.15.0, acorn@^8.9.0:
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.15.0, acorn@^8.9.0:
version "8.15.0"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz"
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
@ -2570,6 +2656,11 @@ bcrypt@^6.0.0:
node-addon-api "^8.3.0"
node-gyp-build "^4.8.4"
bignumber.js@^9.1.1:
version "9.3.1"
resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz"
integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==
binary-extensions@^2.0.0:
version "2.3.0"
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz"
@ -2632,7 +2723,7 @@ brorand@^1.1.0:
resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz"
integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==
browserslist@^4.24.0, browserslist@^4.26.3:
browserslist@^4.24.0, browserslist@^4.26.3, "browserslist@>= 4.21.0":
version "4.28.0"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz"
integrity sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==
@ -2677,7 +2768,7 @@ busboy@^1.6.0:
dependencies:
streamsearch "^1.1.0"
bytes@3.1.2, bytes@^3.1.2:
bytes@^3.1.2, bytes@3.1.2:
version "3.1.2"
resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
@ -2723,7 +2814,7 @@ canonical-json@^0.2.0:
resolved "https://registry.npmjs.org/canonical-json/-/canonical-json-0.2.0.tgz"
integrity sha512-xeH/NgtNA7kIuKSxopJVdXqCKWyDB79aqxQRQ9FV02fvmqW7DSnjoFyzAUrBpfbwjU6lwTYOLc+HM6KupbsfVQ==
chalk@4.1.2, chalk@^4.0.0:
chalk@^4.0.0, chalk@4.1.2:
version "4.1.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@ -2796,6 +2887,11 @@ cluster-key-slot@1.1.2:
resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz"
integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==
cockatiel@^3.1.1:
version "3.2.1"
resolved "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz"
integrity sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
@ -2887,17 +2983,17 @@ convert-source-map@^2.0.0:
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
cookie-signature@1.0.7:
version "1.0.7"
resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz"
integrity sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==
cookie-signature@^1.2.1:
version "1.2.2"
resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz"
integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==
cookie@0.7.2, cookie@^0.7.1:
cookie-signature@1.0.7:
version "1.0.7"
resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz"
integrity sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==
cookie@^0.7.1, cookie@0.7.2:
version "0.7.2"
resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz"
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
@ -2968,6 +3064,20 @@ date-format@^4.0.14:
resolved "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz"
integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==
debug@^3.2.7:
version "3.2.7"
resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
ms "^2.1.1"
debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0, debug@^4.4.1, debug@4, debug@4.x:
version "4.4.3"
resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
dependencies:
ms "^2.1.3"
debug@2.6.9:
version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
@ -2975,13 +3085,6 @@ debug@2.6.9:
dependencies:
ms "2.0.0"
debug@4, debug@4.x, debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0, debug@^4.4.1:
version "4.4.3"
resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
dependencies:
ms "^2.1.3"
debug@4.3.1:
version "4.3.1"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz"
@ -2989,13 +3092,6 @@ debug@4.3.1:
dependencies:
ms "2.1.2"
debug@^3.2.7:
version "3.2.7"
resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
ms "^2.1.1"
deep-is@^0.1.3:
version "0.1.4"
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
@ -3033,7 +3129,7 @@ delayed-stream@~1.0.0:
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
depd@2.0.0, depd@^2.0.0, depd@~2.0.0:
depd@^2.0.0, depd@~2.0.0, depd@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
@ -3301,7 +3397,7 @@ escodegen@^2.1.0:
optionalDependencies:
source-map "~0.6.1"
eslint-config-prettier@^10.1.8:
eslint-config-prettier@^10.1.8, "eslint-config-prettier@>= 7.0.0 <10.0.0 || >=10.1.0":
version "10.1.8"
resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz"
integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==
@ -3340,7 +3436,7 @@ eslint-plugin-es@^4.1.0:
eslint-utils "^2.0.0"
regexpp "^3.0.0"
eslint-plugin-import@^2.27.5:
eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.27.5:
version "2.32.0"
resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz"
integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==
@ -3365,7 +3461,7 @@ eslint-plugin-import@^2.27.5:
string.prototype.trimend "^1.0.9"
tsconfig-paths "^3.15.0"
eslint-plugin-n@^15.7.0:
"eslint-plugin-n@^15.0.0 || ^16.0.0 ", eslint-plugin-n@^15.7.0:
version "15.7.0"
resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz"
integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==
@ -3387,12 +3483,12 @@ eslint-plugin-prettier@^5.5.4:
prettier-linter-helpers "^1.0.0"
synckit "^0.11.7"
eslint-plugin-promise@^6.1.1:
eslint-plugin-promise@^6.0.0, eslint-plugin-promise@^6.1.1:
version "6.6.0"
resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz"
integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==
eslint-plugin-react@^7.36.1:
eslint-plugin-react@^7.28.0, eslint-plugin-react@^7.36.1:
version "7.37.5"
resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz"
integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==
@ -3466,7 +3562,7 @@ eslint-visitor-keys@^4.2.1:
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz"
integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==
eslint@^8.41.0:
"eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^7.0.0 || ^8.0.0 || ^9.0.0", eslint@^8.0.1, eslint@^8.41.0, eslint@^8.8.0, eslint@>=4.19.1, eslint@>=5:
version "8.57.1"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
@ -3510,7 +3606,7 @@ eslint@^8.41.0:
strip-ansi "^6.0.1"
text-table "^0.2.0"
eslint@^9.39.1:
"eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^9.39.1, eslint@>=7.0.0, eslint@>=8.0.0:
version "9.39.1"
resolved "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz"
integrity sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==
@ -3602,6 +3698,16 @@ etag@^1.8.1:
resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz"
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
etcd3@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/etcd3/-/etcd3-1.1.2.tgz"
integrity sha512-YIampCz1/OmrVo/tR3QltAVUtYCQQOSFoqmHKKeoHbalm+WdXe3l4rhLIylklu8EzR/I3PBiOF4dC847dDskKg==
dependencies:
"@grpc/grpc-js" "^1.8.20"
"@grpc/proto-loader" "^0.7.8"
bignumber.js "^9.1.1"
cockatiel "^3.1.1"
exifr@^7.1.3:
version "7.1.3"
resolved "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz"
@ -4096,7 +4202,7 @@ homedir-polyfill@^1.0.1:
dependencies:
parse-passwd "^1.0.0"
http-errors@2.0.0, http-errors@^2.0.0:
http-errors@^2.0.0, http-errors@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz"
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
@ -4128,13 +4234,6 @@ i@^0.3.7:
resolved "https://registry.npmjs.org/i/-/i-0.3.7.tgz"
integrity sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==
iconv-lite@0.7.0:
version "0.7.0"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz"
integrity sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
iconv-lite@^0.6.3:
version "0.6.3"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
@ -4142,6 +4241,13 @@ iconv-lite@^0.6.3:
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
iconv-lite@0.7.0:
version "0.7.0"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz"
integrity sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
ignore-by-default@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz"
@ -4178,7 +4284,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@2, inherits@2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -4672,6 +4778,11 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz"
integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz"
@ -4733,6 +4844,11 @@ log4js@^6.9.1:
rfdc "^1.3.0"
streamroller "^3.1.5"
long@^5.0.0:
version "5.3.2"
resolved "https://registry.npmjs.org/long/-/long-5.3.2.tgz"
integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==
loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
@ -4770,16 +4886,16 @@ math-intrinsics@^1.1.0:
resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz"
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
media-typer@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz"
integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
memory-pager@^1.0.2:
version "1.5.0"
resolved "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz"
@ -4790,17 +4906,17 @@ merge-descriptors@^2.0.0:
resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz"
integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-db@^1.54.0:
version "1.54.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
mime-types@^2.1.12, mime-types@~2.1.24:
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12:
version "2.1.35"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
@ -4814,6 +4930,13 @@ mime-types@^3.0.0, mime-types@^3.0.1:
dependencies:
mime-db "^1.54.0"
mime-types@~2.1.24:
version "2.1.35"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz"
@ -4824,13 +4947,6 @@ minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz"
integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==
minimatch@9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz"
integrity sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
@ -4845,6 +4961,13 @@ minimatch@^9.0.4:
dependencies:
brace-expansion "^2.0.1"
minimatch@9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz"
integrity sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==
dependencies:
brace-expansion "^2.0.1"
minimist@^1.2.0, minimist@^1.2.6:
version "1.2.8"
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
@ -4925,6 +5048,11 @@ mquery@5.0.0:
dependencies:
debug "4.x"
ms@^2.1.1, ms@^2.1.3, ms@2.1.3:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
@ -4935,11 +5063,6 @@ ms@2.1.2:
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@2.1.3, ms@^2.1.1, ms@^2.1.3:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
multer@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz"
@ -5324,7 +5447,7 @@ pg-types@2.2.0:
postgres-date "~1.0.4"
postgres-interval "^1.1.0"
pg@^8.16.3:
pg@^8.16.3, pg@>=8.0:
version "8.16.3"
resolved "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz"
integrity sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==
@ -5418,7 +5541,7 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"
prettier@^3.6.2:
prettier@^3.6.2, prettier@>=3.0.0:
version "3.6.2"
resolved "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz"
integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==
@ -5437,6 +5560,24 @@ proto-list@~1.2.1:
resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz"
integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==
protobufjs@^7.2.5, protobufjs@^7.5.3:
version "7.5.4"
resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz"
integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
"@protobufjs/codegen" "^2.0.4"
"@protobufjs/eventemitter" "^1.1.0"
"@protobufjs/fetch" "^1.1.0"
"@protobufjs/float" "^1.0.2"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/path" "^1.1.2"
"@protobufjs/pool" "^1.1.0"
"@protobufjs/utf8" "^1.1.0"
"@types/node" ">=13.7.0"
long "^5.0.0"
proxy-addr@^2.0.7:
version "2.0.7"
resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz"
@ -5704,7 +5845,7 @@ safe-array-concat@^1.1.2, safe-array-concat@^1.1.3:
has-symbols "^1.1.0"
isarray "^2.0.5"
safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0:
safe-buffer@^5.0.1, safe-buffer@~5.2.0, safe-buffer@5.2.1:
version "5.2.1"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@ -5726,12 +5867,17 @@ safe-regex-test@^1.1.0:
es-errors "^1.3.0"
is-regex "^1.2.1"
"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0:
safer-buffer@^2.1.0, "safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
semver@^5.6.0, semver@^5.7.0:
semver@^5.6.0:
version "5.7.2"
resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@^5.7.0:
version "5.7.2"
resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
@ -5741,7 +5887,22 @@ semver@^6.3.1:
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.0.0, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4:
semver@^7.0.0:
version "7.7.3"
resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz"
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
semver@^7.3.8:
version "7.7.3"
resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz"
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
semver@^7.5.3:
version "7.7.3"
resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz"
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
semver@^7.5.4:
version "7.7.3"
resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz"
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
@ -5949,7 +6110,7 @@ socks-proxy-agent@^8.0.5:
debug "^4.3.4"
socks "^2.8.3"
socks@^2.8.3:
socks@^2.7.1, socks@^2.8.3:
version "2.8.7"
resolved "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz"
integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==
@ -6007,16 +6168,16 @@ standard@^17.1.2:
standard-engine "^15.1.0"
version-guard "^1.1.1"
statuses@2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
statuses@^2.0.1:
version "2.0.2"
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz"
integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==
statuses@2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
stop-iteration-iterator@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz"
@ -6039,6 +6200,13 @@ streamsearch@^1.1.0:
resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
@ -6125,13 +6293,6 @@ string.prototype.trimstart@^1.0.8:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
@ -6168,13 +6329,6 @@ strnum@^2.1.0:
resolved "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz"
integrity sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==
supports-color@8.1.1:
version "8.1.1"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
@ -6189,6 +6343,13 @@ supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
supports-color@8.1.1:
version "8.1.1"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
@ -6618,19 +6779,6 @@ yargs-parser@^21.1.1:
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
yargs@17.7.2:
version "17.7.2"
resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
dependencies:
cliui "^8.0.1"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.1.1"
yargs@^16.2.0:
version "16.2.0"
resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz"
@ -6644,6 +6792,19 @@ yargs@^16.2.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"
yargs@^17.7.2, yargs@17.7.2:
version "17.7.2"
resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
dependencies:
cliui "^8.0.1"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.1.1"
yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz"