Compare commits

...

17 Commits

Author SHA1 Message Date
a12ae1f340 Bump packages. 2025-12-27 14:03:54 +00:00
db85735f9b Update tax rate import path in taxrates.js to reflect schema renaming. 2025-12-27 14:03:44 +00:00
5a16890b7a Add route handler for updating multiple stock events in stockevents.js 2025-12-27 14:03:38 +00:00
361689cef4 Update allowedFilters in order items route to include shipment and shipment._id for enhanced filtering capabilities. 2025-12-27 14:03:25 +00:00
a7bda46acf Add shipment management functionality with new route handlers for shipping, receiving, and canceling shipments. Updated service methods to handle state validation and order item updates accordingly. 2025-12-27 14:03:03 +00:00
7541612d67 Refactor ObjectId handling in utils.js to use mongoose.Types.ObjectId for consistency across the codebase. 2025-12-27 14:02:50 +00:00
ecb888f692 Renamed tax rates. 2025-12-27 14:02:39 +00:00
fadaafdad8 Add purchase order management functionality with new route handlers for posting, acknowledging, and canceling purchase orders. Enhanced service methods to validate states and update order items and shipments accordingly. 2025-12-27 14:02:16 +00:00
eb2e920028 Add batch update functionality for filament stocks, order items, part stocks, purchase orders, shipments, and filaments. Implemented new route handlers for editing multiple records and enhanced existing services to support bulk updates. 2025-12-27 14:01:46 +00:00
2ac550b0c4 Refactor purchase order schema to include additional fields for shipping and state management. Implement rollup statistics and history methods for enhanced data aggregation and reporting capabilities. 2025-12-27 13:59:48 +00:00
9c4b73da67 Enhance order item schema with new fields for state management, shipment tracking, and tax calculations. Introduce rollup statistics and history methods for improved data aggregation and reporting. 2025-12-27 13:59:37 +00:00
75e5079479 Update models.js to correct tax rate import and add shipment and invoice models 2025-12-27 13:59:22 +00:00
4421c0b946 Add invoice management functionality with schema, routes, and service handlers 2025-12-27 13:59:08 +00:00
9ab08f39a1 Enhanced database functions with pagination support in listObjects, added checkStates function for state validation, and introduced editObjects function for batch updates. Updated editObject to include recalculate parameter. 2025-12-27 13:57:43 +00:00
85f9ca8b6d Updated configuration for development environment, changing Keycloak client ID and updating app URLs for client and API. 2025-12-27 13:56:29 +00:00
c750b1a573 Refactored shipment schema to include new fields and methods for handling order types and tax calculations. 2025-12-27 13:56:05 +00:00
5545452b0c Added dotenv support. 2025-12-14 01:22:42 +00:00
30 changed files with 1863 additions and 352 deletions

View File

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

View File

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

View File

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

View File

@ -0,0 +1,98 @@
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,6 +1,12 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { purchaseOrderModel } from './purchaseorder.schema.js'; import { purchaseOrderModel } from './purchaseorder.schema.js';
import { aggregateRollups, editObject } from '../../database.js'; import { taxRateModel } from '../management/taxrate.schema.js';
import {
aggregateRollups,
aggregateRollupsHistory,
editObject,
getObject,
} from '../../database.js';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
const { Schema } = mongoose; const { Schema } = mongoose;
@ -8,20 +14,64 @@ const orderItemSchema = new Schema(
{ {
_reference: { type: String, default: () => generateId()() }, _reference: { type: String, default: () => generateId()() },
orderType: { type: String, required: true }, orderType: { type: String, required: true },
state: {
type: { type: String, required: true, default: 'draft' },
},
order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true }, order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
itemType: { type: String, required: true }, itemType: { type: String, required: true },
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true }, item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true },
syncAmount: { type: String, required: true, default: null }, syncAmount: { type: String, required: false, default: null },
itemAmount: { type: Number, required: true }, itemAmount: { type: Number, required: true },
quantity: { type: Number, required: true }, quantity: { type: Number, required: true },
totalAmount: { type: Number, required: true }, totalAmount: { type: Number, required: true },
taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false }, taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
totalAmountWithTax: { type: Number, required: true }, totalAmountWithTax: { type: Number, required: true },
timestamp: { type: Date, default: Date.now }, 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 } { 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) { orderItemSchema.statics.recalculate = async function (orderItem, user) {
// Only purchase orders are supported for now // Only purchase orders are supported for now
if (orderItem.orderType !== 'purchaseOrder') { if (orderItem.orderType !== 'purchaseOrder') {
@ -33,6 +83,29 @@ orderItemSchema.statics.recalculate = async function (orderItem, user) {
return; 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({ const rollupResults = await aggregateRollups({
model: this, model: this,
baseFilter: { baseFilter: {
@ -51,21 +124,60 @@ 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 totals = rollupResults.orderTotals || {};
const totalAmount = totals.totalAmount.sum?.toFixed(2) || 0; const totalAmount = totals.totalAmount.sum?.toFixed(2) || 0;
const totalAmountWithTax = totals.totalAmountWithTax.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({ await editObject({
model: purchaseOrderModel, model: purchaseOrderModel,
id: orderId, id: orderId,
updateData: { updateData: updateData,
totalAmount: parseFloat(totalAmount),
totalAmountWithTax: parseFloat(totalAmountWithTax),
totalTaxAmount: parseFloat(totalAmountWithTax - totalAmount),
},
user, user,
}); });
}; };

View File

@ -1,22 +1,100 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
const { Schema } = mongoose; const { Schema } = mongoose;
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
const purchaseOrderSchema = new Schema( const purchaseOrderSchema = new Schema(
{ {
_reference: { type: String, default: () => generateId()() }, _reference: { type: String, default: () => generateId()() },
totalAmount: { type: Number, required: true }, totalAmount: { type: Number, required: true, default: 0 },
totalAmountWithTax: { type: Number, required: true }, totalAmountWithTax: { type: Number, required: true, default: 0 },
totalTaxAmount: { type: Number, required: true }, 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 }, timestamp: { type: Date, default: Date.now },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true }, vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
state: { state: {
type: { type: String, required: true, default: 'draft' }, 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 } { 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 // Add virtual id getter
purchaseOrderSchema.virtual('id').get(function () { purchaseOrderSchema.virtual('id').get(function () {
return this._id; return this._id;

View File

@ -1,43 +1,108 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
const { Schema } = mongoose; const { Schema } = mongoose;
import { purchaseOrderModel } from './purchaseorder.schema.js';
const shipmentItemSchema = new Schema({ import { taxRateModel } from '../management/taxrate.schema.js';
itemType: { type: String, required: true }, import { aggregateRollups, editObject, getObject } from '../../database.js';
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( const shipmentSchema = new Schema(
{ {
_reference: { type: String, default: () => generateId()() }, _reference: { type: String, default: () => generateId()() },
purchaseOrder: { type: Schema.Types.ObjectId, ref: 'purchaseOrder', required: true }, orderType: { type: String, required: true },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true }, order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
courierService: { type: Schema.Types.ObjectId, ref: 'courierService', required: false }, courierService: { type: Schema.Types.ObjectId, ref: 'courierService', required: false },
trackingNumber: { type: String, required: false }, trackingNumber: { type: String, required: false },
items: [shipmentItemSchema], amount: { type: Number, required: true },
cost: { net: { type: Number, required: true }, gross: { type: Number, required: true } }, amountWithTax: { type: Number, required: true },
shippedDate: { type: Date, required: false }, taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
expectedDeliveryDate: { type: Date, required: false }, shippedAt: { type: Date, required: false },
actualDeliveryDate: { type: Date, required: false }, expectedAt: { type: Date, required: false },
deliveredAt: { type: Date, required: false },
cancelledAt: { type: Date, required: false },
state: { state: {
type: { type: {
type: String, type: String,
required: true, required: true,
default: 'pending',
enum: ['pending', 'shipped', 'in_transit', 'delivered', 'cancelled'],
}, },
}, },
notes: { type: String },
timestamp: { type: Date, default: Date.now },
}, },
{ timestamps: true } { 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 // Add virtual id getter
shipmentSchema.virtual('id').get(function () { shipmentSchema.virtual('id').get(function () {
return this._id; return this._id;

View File

@ -24,8 +24,10 @@ import { documentJobModel } from './management/documentjob.schema.js';
import { fileModel } from './management/file.schema.js'; import { fileModel } from './management/file.schema.js';
import { courierServiceModel } from './management/courierservice.schema.js'; import { courierServiceModel } from './management/courierservice.schema.js';
import { courierModel } from './management/courier.schema.js'; import { courierModel } from './management/courier.schema.js';
import { taxRateModel } from './management/taxrates.schema.js'; import { taxRateModel } from './management/taxrate.schema.js';
import { taxRecordModel } from './management/taxrecord.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 // Map prefixes to models and id fields
export const models = { export const models = {
@ -98,4 +100,6 @@ export const models = {
COR: { model: courierModel, idField: '_id', type: 'courier', referenceField: '_reference' }, COR: { model: courierModel, idField: '_id', type: 'courier', referenceField: '_reference' },
TXR: { model: taxRateModel, idField: '_id', type: 'taxRate', referenceField: '_reference' }, TXR: { model: taxRateModel, idField: '_id', type: 'taxRate', referenceField: '_reference' },
TXD: { model: taxRecordModel, idField: '_id', type: 'taxRecord', 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,6 +37,7 @@ import {
courierServiceRoutes, courierServiceRoutes,
taxRateRoutes, taxRateRoutes,
taxRecordRoutes, taxRecordRoutes,
invoiceRoutes,
} from './routes/index.js'; } from './routes/index.js';
import path from 'path'; import path from 'path';
import * as fs from 'fs'; import * as fs from 'fs';
@ -139,6 +140,7 @@ app.use('/couriers', courierRoutes);
app.use('/courierservices', courierServiceRoutes); app.use('/courierservices', courierServiceRoutes);
app.use('/taxrates', taxRateRoutes); app.use('/taxrates', taxRateRoutes);
app.use('/taxrecords', taxRecordRoutes); app.use('/taxrecords', taxRecordRoutes);
app.use('/invoices', invoiceRoutes);
app.use('/notes', noteRoutes); app.use('/notes', noteRoutes);
// Start the application // Start the application

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,382 @@
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,6 +7,7 @@ import {
listObjects, listObjects,
getObject, getObject,
editObject, editObject,
editObjects,
newObject, newObject,
listObjectsByProperties, listObjectsByProperties,
getModelStats, getModelStats,
@ -114,6 +115,32 @@ export const editFilamentStockRouteHandler = async (req, res) => {
res.send(result); 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) => { export const newFilamentStockRouteHandler = async (req, res) => {
const newData = { const newData = {
updatedAt: new Date(), updatedAt: new Date(),

View File

@ -7,6 +7,7 @@ import {
listObjects, listObjects,
getObject, getObject,
editObject, editObject,
editObjects,
newObject, newObject,
listObjectsByProperties, listObjectsByProperties,
getModelStats, getModelStats,
@ -43,6 +44,10 @@ export const listOrderItemsRouteHandler = async (
path: 'taxRate', path: 'taxRate',
strictPopulate: false, strictPopulate: false,
}, },
{
path: 'shipment',
strictPopulate: false,
},
{ {
path: 'item', path: 'item',
populate: { path: 'costTaxRate', strictPopulate: false }, populate: { path: 'costTaxRate', strictPopulate: false },
@ -138,6 +143,7 @@ export const editOrderItemRouteHandler = async (req, res) => {
itemAmount: req.body.itemAmount, itemAmount: req.body.itemAmount,
quantity: req.body.quantity, quantity: req.body.quantity,
totalAmount: req.body.totalAmount, totalAmount: req.body.totalAmount,
shipment: req.body.shipment,
taxRate: req.body.taxRate, taxRate: req.body.taxRate,
totalAmountWithTax: req.body.totalAmountWithTax, totalAmountWithTax: req.body.totalAmountWithTax,
}; };
@ -160,6 +166,43 @@ export const editOrderItemRouteHandler = async (req, res) => {
res.send(result); 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) => { export const newOrderItemRouteHandler = async (req, res) => {
const newData = { const newData = {
updatedAt: new Date(), updatedAt: new Date(),
@ -175,6 +218,7 @@ export const newOrderItemRouteHandler = async (req, res) => {
totalAmount: req.body.totalAmount, totalAmount: req.body.totalAmount,
taxRate: req.body.taxRate, taxRate: req.body.taxRate,
totalAmountWithTax: req.body.totalAmountWithTax, totalAmountWithTax: req.body.totalAmountWithTax,
shipment: req.body.shipment,
}; };
const result = await newObject({ const result = await newObject({
model: orderItemModel, model: orderItemModel,

View File

@ -7,6 +7,7 @@ import {
listObjects, listObjects,
getObject, getObject,
editObject, editObject,
editObjects,
newObject, newObject,
listObjectsByProperties, listObjectsByProperties,
getModelStats, getModelStats,
@ -114,6 +115,32 @@ export const editPartStockRouteHandler = async (req, res) => {
res.send(result); 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) => { export const newPartStockRouteHandler = async (req, res) => {
const newData = { const newData = {
updatedAt: new Date(), updatedAt: new Date(),

View File

@ -7,11 +7,15 @@ import {
listObjects, listObjects,
getObject, getObject,
editObject, editObject,
editObjects,
newObject, newObject,
listObjectsByProperties, listObjectsByProperties,
getModelStats, getModelStats,
getModelHistory, getModelHistory,
checkStates,
} from '../../database/database.js'; } 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'); const logger = log4js.getLogger('Purchase Orders');
logger.level = config.server.logLevel; logger.level = config.server.logLevel;
@ -95,6 +99,20 @@ export const editPurchaseOrderRouteHandler = async (req, res) => {
logger.trace(`Purchase Order with ID: ${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 updateData = { const updateData = {
updatedAt: new Date(), updatedAt: new Date(),
vendor: req.body.vendor, vendor: req.body.vendor,
@ -118,10 +136,40 @@ export const editPurchaseOrderRouteHandler = async (req, res) => {
res.send(result); 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) => { export const newPurchaseOrderRouteHandler = async (req, res) => {
const newData = { const newData = {
updatedAt: new Date(), updatedAt: new Date(),
vendor: req.body.vendor, vendor: req.body.vendor,
totalAmount: 0,
totalAmountWithTax: 0,
totalTaxAmount: 0,
}; };
const result = await newObject({ const result = await newObject({
model: purchaseOrderModel, model: purchaseOrderModel,
@ -180,3 +228,232 @@ export const getPurchaseOrderHistoryRouteHandler = async (req, res) => {
logger.trace('Purchase order history:', result); logger.trace('Purchase order history:', result);
res.send(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,13 +7,16 @@ import {
listObjects, listObjects,
getObject, getObject,
editObject, editObject,
editObjects,
newObject, newObject,
listObjectsByProperties, listObjectsByProperties,
getModelStats, getModelStats,
getModelHistory, getModelHistory,
checkStates,
} from '../../database/database.js'; } from '../../database/database.js';
const logger = log4js.getLogger('Shipments'); const logger = log4js.getLogger('Shipments');
logger.level = config.server.logLevel; logger.level = config.server.logLevel;
import { orderItemModel } from '../../database/schemas/inventory/orderitem.schema.js';
export const listShipmentsRouteHandler = async ( export const listShipmentsRouteHandler = async (
req, req,
@ -35,7 +38,7 @@ export const listShipmentsRouteHandler = async (
search, search,
sort, sort,
order, order,
populate: ['purchaseOrder', 'vendor', 'courierService'], populate: ['order', 'courierService', 'taxRate'],
}); });
if (result?.error) { if (result?.error) {
@ -59,7 +62,7 @@ export const listShipmentsByPropertiesRouteHandler = async (
model: shipmentModel, model: shipmentModel,
properties, properties,
filter, filter,
populate: ['purchaseOrder', 'vendor', 'courierService'], populate: ['courierService'],
masterFilter, masterFilter,
}); });
@ -78,7 +81,7 @@ export const getShipmentRouteHandler = async (req, res) => {
const result = await getObject({ const result = await getObject({
model: shipmentModel, model: shipmentModel,
id, id,
populate: ['purchaseOrder', 'vendor', 'courierService', 'items.item', 'items.taxRate'], populate: ['order', 'courierService', 'taxRate'],
}); });
if (result?.error) { if (result?.error) {
logger.warn(`Shipment not found with supplied id.`); logger.warn(`Shipment not found with supplied id.`);
@ -96,15 +99,13 @@ export const editShipmentRouteHandler = async (req, res) => {
const updateData = { const updateData = {
updatedAt: new Date(), updatedAt: new Date(),
purchaseOrder: req.body.purchaseOrder, orderType: req.body.orderType,
vendor: req.body.vendor, order: req.body.order,
courierService: req.body.courierService, courierService: req.body.courierService,
trackingNumber: req.body.trackingNumber, trackingNumber: req.body.trackingNumber,
shippedDate: req.body.shippedDate, amount: req.body.amount,
expectedDeliveryDate: req.body.expectedDeliveryDate, amountWithTax: req.body.amountWithTax,
actualDeliveryDate: req.body.actualDeliveryDate, taxRate: req.body.taxRate,
state: req.body.state,
notes: req.body.notes,
}; };
// Create audit log before updating // Create audit log before updating
const result = await editObject({ const result = await editObject({
@ -125,20 +126,53 @@ export const editShipmentRouteHandler = async (req, res) => {
res.send(result); 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) => { export const newShipmentRouteHandler = async (req, res) => {
const newData = { const newData = {
updatedAt: new Date(), updatedAt: new Date(),
purchaseOrder: req.body.purchaseOrder, orderType: req.body.orderType,
vendor: req.body.vendor, order: req.body.order,
courierService: req.body.courierService, courierService: req.body.courierService,
trackingNumber: req.body.trackingNumber, trackingNumber: req.body.trackingNumber,
items: req.body.items, amount: req.body.amount,
cost: req.body.cost, amountWithTax: req.body.amountWithTax,
shippedDate: req.body.shippedDate, taxRate: req.body.taxRate,
expectedDeliveryDate: req.body.expectedDeliveryDate, shippedAt: req.body.shippedAt,
actualDeliveryDate: req.body.actualDeliveryDate, expectedAt: req.body.expectedAt,
state: req.body.state, deliveredAt: req.body.deliveredAt,
notes: req.body.notes, state: { type: 'draft' },
}; };
const result = await newObject({ const result = await newObject({
model: shipmentModel, model: shipmentModel,
@ -197,3 +231,212 @@ export const getShipmentHistoryRouteHandler = async (req, res) => {
logger.trace('Shipment history:', result); logger.trace('Shipment history:', result);
res.send(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,6 +7,7 @@ import {
listObjects, listObjects,
getObject, getObject,
editObject, editObject,
editObjects,
newObject, newObject,
listObjectsByProperties, listObjectsByProperties,
getModelStats, getModelStats,
@ -145,6 +146,32 @@ export const editStockEventRouteHandler = async (req, res) => {
res.send(result); 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) => { export const deleteStockEventRouteHandler = async (req, res) => {
// Get ID from params // Get ID from params
const id = new mongoose.Types.ObjectId(req.params.id); const id = new mongoose.Types.ObjectId(req.params.id);

View File

@ -7,6 +7,7 @@ import {
listObjects, listObjects,
listObjectsByProperties, listObjectsByProperties,
editObject, editObject,
editObjects,
newObject, newObject,
getModelStats, getModelStats,
getModelHistory, getModelHistory,
@ -58,7 +59,16 @@ export const listFilamentsByPropertiesRouteHandler = async (
model: filamentModel, model: filamentModel,
properties, properties,
filter, filter,
populate: 'vendor', populate: [
{
path: 'vendor',
from: 'vendors',
},
{
path: 'costTaxRate',
from: 'taxrates',
},
],
}); });
if (result?.error) { if (result?.error) {
@ -126,6 +136,45 @@ export const editFilamentRouteHandler = async (req, res) => {
res.send(result); 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) => { export const newFilamentRouteHandler = async (req, res) => {
const newData = { const newData = {
createdAt: new Date(), createdAt: new Date(),

View File

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

View File

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

379
yarn.lock
View File

@ -45,7 +45,7 @@
"@smithy/util-utf8" "^2.0.0" "@smithy/util-utf8" "^2.0.0"
tslib "^2.6.2" 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" version "5.2.0"
resolved "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz" resolved "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz"
integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA== integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==
@ -61,7 +61,7 @@
dependencies: dependencies:
tslib "^2.6.2" 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" version "5.2.0"
resolved "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz" resolved "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz"
integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ== integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==
@ -514,7 +514,7 @@
"@smithy/types" "^4.9.0" "@smithy/types" "^4.9.0"
tslib "^2.6.2" tslib "^2.6.2"
"@aws-sdk/types@^3.222.0", "@aws-sdk/types@3.930.0": "@aws-sdk/types@3.930.0", "@aws-sdk/types@^3.222.0":
version "3.930.0" version "3.930.0"
resolved "https://registry.npmjs.org/@aws-sdk/types/-/types-3.930.0.tgz" resolved "https://registry.npmjs.org/@aws-sdk/types/-/types-3.930.0.tgz"
integrity sha512-we/vaAgwlEFW7IeftmCLlLMw+6hFs3DzZPJw7lVHbj/5HJ0bz9gndxEsS2lQoeJ1zhiiLqAqvXxmM43s0MBg0A== integrity sha512-we/vaAgwlEFW7IeftmCLlLMw+6hFs3DzZPJw7lVHbj/5HJ0bz9gndxEsS2lQoeJ1zhiiLqAqvXxmM43s0MBg0A==
@ -622,7 +622,7 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz"
integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA== integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==
"@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": "@babel/core@^7.28.5":
version "7.28.5" version "7.28.5"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz" resolved "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz"
integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw== integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==
@ -1527,34 +1527,6 @@
"@eslint/core" "^0.17.0" "@eslint/core" "^0.17.0"
levn "^0.4.1" 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": "@humanfs/core@^0.19.1":
version "0.19.1" version "0.19.1"
resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz" resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz"
@ -1638,11 +1610,6 @@
"@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14" "@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": "@mongodb-js/saslprep@^1.3.0":
version "1.3.2" version "1.3.2"
resolved "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.2.tgz" resolved "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.2.tgz"
@ -1720,65 +1687,12 @@
resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz" resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz"
integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA== 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": "@redis/bloom@5.10.0":
version "5.10.0" version "5.10.0"
resolved "https://registry.npmjs.org/@redis/bloom/-/bloom-5.10.0.tgz" resolved "https://registry.npmjs.org/@redis/bloom/-/bloom-5.10.0.tgz"
integrity sha512-doIF37ob+l47n0rkpRNgU8n4iacBlKM9xLiP1LtTZTvz8TloJB8qx/MgvhMhKdYG+CvCY2aPBnN2706izFn/4A== 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" version "5.10.0"
resolved "https://registry.npmjs.org/@redis/client/-/client-5.10.0.tgz" resolved "https://registry.npmjs.org/@redis/client/-/client-5.10.0.tgz"
integrity sha512-JXmM4XCoso6C75Mr3lhKA3eNxSzkYi3nCzxDIKY+YOszYsJjuKbFgVtguVPbLMOttN4iu2fXoc2BGhdnYhIOxA== integrity sha512-JXmM4XCoso6C75Mr3lhKA3eNxSzkYi3nCzxDIKY+YOszYsJjuKbFgVtguVPbLMOttN4iu2fXoc2BGhdnYhIOxA==
@ -2342,7 +2256,7 @@
resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz" resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz"
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
"@types/node@*", "@types/node@>=13.7.0": "@types/node@*":
version "24.10.1" version "24.10.1"
resolved "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz" resolved "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz"
integrity sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ== integrity sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==
@ -2396,7 +2310,7 @@ acorn-jsx@^5.3.2:
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.15.0, acorn@^8.9.0: acorn@^8.15.0, acorn@^8.9.0:
version "8.15.0" version "8.15.0"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz" resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz"
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
@ -2656,11 +2570,6 @@ bcrypt@^6.0.0:
node-addon-api "^8.3.0" node-addon-api "^8.3.0"
node-gyp-build "^4.8.4" 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: binary-extensions@^2.0.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz"
@ -2723,7 +2632,7 @@ brorand@^1.1.0:
resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz"
integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==
browserslist@^4.24.0, browserslist@^4.26.3, "browserslist@>= 4.21.0": browserslist@^4.24.0, browserslist@^4.26.3:
version "4.28.0" version "4.28.0"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz"
integrity sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ== integrity sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==
@ -2768,7 +2677,7 @@ busboy@^1.6.0:
dependencies: dependencies:
streamsearch "^1.1.0" streamsearch "^1.1.0"
bytes@^3.1.2, bytes@3.1.2: bytes@3.1.2, bytes@^3.1.2:
version "3.1.2" version "3.1.2"
resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
@ -2814,7 +2723,7 @@ canonical-json@^0.2.0:
resolved "https://registry.npmjs.org/canonical-json/-/canonical-json-0.2.0.tgz" resolved "https://registry.npmjs.org/canonical-json/-/canonical-json-0.2.0.tgz"
integrity sha512-xeH/NgtNA7kIuKSxopJVdXqCKWyDB79aqxQRQ9FV02fvmqW7DSnjoFyzAUrBpfbwjU6lwTYOLc+HM6KupbsfVQ== integrity sha512-xeH/NgtNA7kIuKSxopJVdXqCKWyDB79aqxQRQ9FV02fvmqW7DSnjoFyzAUrBpfbwjU6lwTYOLc+HM6KupbsfVQ==
chalk@^4.0.0, chalk@4.1.2: chalk@4.1.2, chalk@^4.0.0:
version "4.1.2" version "4.1.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@ -2887,11 +2796,6 @@ cluster-key-slot@1.1.2:
resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz" resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz"
integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== 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: color-convert@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
@ -2983,17 +2887,17 @@ convert-source-map@^2.0.0:
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
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-signature@1.0.7: cookie-signature@1.0.7:
version "1.0.7" version "1.0.7"
resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz" resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz"
integrity sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA== integrity sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==
cookie@^0.7.1, cookie@0.7.2: 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:
version "0.7.2" version "0.7.2"
resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz" resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz"
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
@ -3064,20 +2968,6 @@ date-format@^4.0.14:
resolved "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz" resolved "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz"
integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== 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: debug@2.6.9:
version "2.6.9" version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
@ -3085,6 +2975,13 @@ debug@2.6.9:
dependencies: dependencies:
ms "2.0.0" 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: debug@4.3.1:
version "4.3.1" version "4.3.1"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz" resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz"
@ -3092,6 +2989,13 @@ debug@4.3.1:
dependencies: dependencies:
ms "2.1.2" 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: deep-is@^0.1.3:
version "0.1.4" version "0.1.4"
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
@ -3129,7 +3033,7 @@ delayed-stream@~1.0.0:
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== 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" version "2.0.0"
resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
@ -3397,7 +3301,7 @@ escodegen@^2.1.0:
optionalDependencies: optionalDependencies:
source-map "~0.6.1" source-map "~0.6.1"
eslint-config-prettier@^10.1.8, "eslint-config-prettier@>= 7.0.0 <10.0.0 || >=10.1.0": eslint-config-prettier@^10.1.8:
version "10.1.8" version "10.1.8"
resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz" resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz"
integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w== integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==
@ -3436,7 +3340,7 @@ eslint-plugin-es@^4.1.0:
eslint-utils "^2.0.0" eslint-utils "^2.0.0"
regexpp "^3.0.0" regexpp "^3.0.0"
eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.27.5: eslint-plugin-import@^2.27.5:
version "2.32.0" version "2.32.0"
resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz" resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz"
integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA== integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==
@ -3461,7 +3365,7 @@ eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.27.5:
string.prototype.trimend "^1.0.9" string.prototype.trimend "^1.0.9"
tsconfig-paths "^3.15.0" tsconfig-paths "^3.15.0"
"eslint-plugin-n@^15.0.0 || ^16.0.0 ", eslint-plugin-n@^15.7.0: eslint-plugin-n@^15.7.0:
version "15.7.0" version "15.7.0"
resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz" resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz"
integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q== integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==
@ -3483,12 +3387,12 @@ eslint-plugin-prettier@^5.5.4:
prettier-linter-helpers "^1.0.0" prettier-linter-helpers "^1.0.0"
synckit "^0.11.7" synckit "^0.11.7"
eslint-plugin-promise@^6.0.0, eslint-plugin-promise@^6.1.1: eslint-plugin-promise@^6.1.1:
version "6.6.0" version "6.6.0"
resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz" resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz"
integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ== integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==
eslint-plugin-react@^7.28.0, eslint-plugin-react@^7.36.1: eslint-plugin-react@^7.36.1:
version "7.37.5" version "7.37.5"
resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz" resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz"
integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==
@ -3562,7 +3466,7 @@ eslint-visitor-keys@^4.2.1:
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz"
integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==
"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: eslint@^8.41.0:
version "8.57.1" version "8.57.1"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz" resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
@ -3606,7 +3510,7 @@ eslint-visitor-keys@^4.2.1:
strip-ansi "^6.0.1" strip-ansi "^6.0.1"
text-table "^0.2.0" text-table "^0.2.0"
"eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^9.39.1, eslint@>=7.0.0, eslint@>=8.0.0: eslint@^9.39.1:
version "9.39.1" version "9.39.1"
resolved "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz" resolved "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz"
integrity sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g== integrity sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==
@ -3698,16 +3602,6 @@ etag@^1.8.1:
resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz"
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== 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: exifr@^7.1.3:
version "7.1.3" version "7.1.3"
resolved "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz" resolved "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz"
@ -4202,7 +4096,7 @@ homedir-polyfill@^1.0.1:
dependencies: dependencies:
parse-passwd "^1.0.0" 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" version "2.0.0"
resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz"
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
@ -4234,13 +4128,6 @@ i@^0.3.7:
resolved "https://registry.npmjs.org/i/-/i-0.3.7.tgz" resolved "https://registry.npmjs.org/i/-/i-0.3.7.tgz"
integrity sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q== integrity sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==
iconv-lite@^0.6.3:
version "0.6.3"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
iconv-lite@0.7.0: iconv-lite@0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz"
@ -4248,6 +4135,13 @@ iconv-lite@0.7.0:
dependencies: dependencies:
safer-buffer ">= 2.1.2 < 3.0.0" 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"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
ignore-by-default@^1.0.1: ignore-by-default@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz" resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz"
@ -4284,7 +4178,7 @@ inflight@^1.0.4:
once "^1.3.0" once "^1.3.0"
wrappy "1" wrappy "1"
inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@2, inherits@2.0.4: inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
version "2.0.4" version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -4778,11 +4672,6 @@ locate-path@^6.0.0:
dependencies: dependencies:
p-locate "^5.0.0" 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: lodash.debounce@^4.0.8:
version "4.0.8" version "4.0.8"
resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz"
@ -4844,11 +4733,6 @@ log4js@^6.9.1:
rfdc "^1.3.0" rfdc "^1.3.0"
streamroller "^3.1.5" 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: loose-envify@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
@ -4886,16 +4770,16 @@ math-intrinsics@^1.1.0:
resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz"
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
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: media-typer@0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== 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==
memory-pager@^1.0.2: memory-pager@^1.0.2:
version "1.5.0" version "1.5.0"
resolved "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz" resolved "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz"
@ -4906,17 +4790,17 @@ merge-descriptors@^2.0.0:
resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz" resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz"
integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g== integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==
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-db@1.52.0: mime-db@1.52.0:
version "1.52.0" version "1.52.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12: 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:
version "2.1.35" version "2.1.35"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
@ -4930,13 +4814,6 @@ mime-types@^3.0.0, mime-types@^3.0.1:
dependencies: dependencies:
mime-db "^1.54.0" 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: minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz"
@ -4947,6 +4824,13 @@ minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz"
integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== 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: minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2" version "3.1.2"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
@ -4961,13 +4845,6 @@ minimatch@^9.0.4:
dependencies: dependencies:
brace-expansion "^2.0.1" 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: minimist@^1.2.0, minimist@^1.2.6:
version "1.2.8" version "1.2.8"
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
@ -5048,11 +4925,6 @@ mquery@5.0.0:
dependencies: dependencies:
debug "4.x" 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: ms@2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
@ -5063,6 +4935,11 @@ ms@2.1.2:
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 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: multer@^2.0.2:
version "2.0.2" version "2.0.2"
resolved "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz" resolved "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz"
@ -5447,7 +5324,7 @@ pg-types@2.2.0:
postgres-date "~1.0.4" postgres-date "~1.0.4"
postgres-interval "^1.1.0" postgres-interval "^1.1.0"
pg@^8.16.3, pg@>=8.0: pg@^8.16.3:
version "8.16.3" version "8.16.3"
resolved "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz" resolved "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz"
integrity sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw== integrity sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==
@ -5541,7 +5418,7 @@ prettier-linter-helpers@^1.0.0:
dependencies: dependencies:
fast-diff "^1.1.2" fast-diff "^1.1.2"
prettier@^3.6.2, prettier@>=3.0.0: prettier@^3.6.2:
version "3.6.2" version "3.6.2"
resolved "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz" resolved "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz"
integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==
@ -5560,24 +5437,6 @@ proto-list@~1.2.1:
resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz"
integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== 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: proxy-addr@^2.0.7:
version "2.0.7" version "2.0.7"
resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz"
@ -5845,7 +5704,7 @@ safe-array-concat@^1.1.2, safe-array-concat@^1.1.3:
has-symbols "^1.1.0" has-symbols "^1.1.0"
isarray "^2.0.5" isarray "^2.0.5"
safe-buffer@^5.0.1, safe-buffer@~5.2.0, safe-buffer@5.2.1: safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0:
version "5.2.1" version "5.2.1"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@ -5867,17 +5726,12 @@ safe-regex-test@^1.1.0:
es-errors "^1.3.0" es-errors "^1.3.0"
is-regex "^1.2.1" is-regex "^1.2.1"
safer-buffer@^2.1.0, "safer-buffer@>= 2.1.2 < 3.0.0": "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0:
version "2.1.2" version "2.1.2"
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
semver@^5.6.0: semver@^5.6.0, semver@^5.7.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" version "5.7.2"
resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
@ -5887,22 +5741,7 @@ semver@^6.3.1:
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.0.0: semver@^7.0.0, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4:
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" version "7.7.3"
resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz" resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz"
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
@ -6110,7 +5949,7 @@ socks-proxy-agent@^8.0.5:
debug "^4.3.4" debug "^4.3.4"
socks "^2.8.3" socks "^2.8.3"
socks@^2.7.1, socks@^2.8.3: socks@^2.8.3:
version "2.8.7" version "2.8.7"
resolved "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz" resolved "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz"
integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A== integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==
@ -6168,16 +6007,16 @@ standard@^17.1.2:
standard-engine "^15.1.0" standard-engine "^15.1.0"
version-guard "^1.1.1" version-guard "^1.1.1"
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: statuses@2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== 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==
stop-iteration-iterator@^1.1.0: stop-iteration-iterator@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz" resolved "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz"
@ -6200,13 +6039,6 @@ streamsearch@^1.1.0:
resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== 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": "string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3" version "4.2.3"
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
@ -6293,6 +6125,13 @@ string.prototype.trimstart@^1.0.8:
define-properties "^1.2.1" define-properties "^1.2.1"
es-object-atoms "^1.0.0" 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": "strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1" version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
@ -6329,6 +6168,13 @@ strnum@^2.1.0:
resolved "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz" resolved "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz"
integrity sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw== 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: supports-color@^5.5.0:
version "5.5.0" version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
@ -6343,13 +6189,6 @@ supports-color@^7.1.0:
dependencies: dependencies:
has-flag "^4.0.0" 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: supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
@ -6779,6 +6618,19 @@ yargs-parser@^21.1.1:
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== 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: yargs@^16.2.0:
version "16.2.0" version "16.2.0"
resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz"
@ -6792,19 +6644,6 @@ yargs@^16.2.0:
y18n "^5.0.5" y18n "^5.0.5"
yargs-parser "^20.2.2" 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: yauzl@^2.10.0:
version "2.10.0" version "2.10.0"
resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz"