Compare commits
10 Commits
97bdf613c6
...
88a531756f
| Author | SHA1 | Date | |
|---|---|---|---|
| 88a531756f | |||
| e3f28fef12 | |||
| 12eb0474fb | |||
| e0776e9595 | |||
| 5209467b0a | |||
| 50307a1861 | |||
| 8fc9ff085e | |||
| dc87278ca6 | |||
| 8e92d4cc1e | |||
| 08a7ecff38 |
2
fcdev.js
2
fcdev.js
@ -6,7 +6,7 @@ const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
async function syncModelsWithWS() {
|
||||
const sourceDir = path.resolve(__dirname, 'src/schemas');
|
||||
const sourceDir = path.resolve(__dirname, 'src/database/schemas');
|
||||
const targetDir = path.resolve(__dirname, '../farmcontrol-ws/src/database/schemas');
|
||||
|
||||
console.log(`Syncing schemas from ${sourceDir} to ${targetDir}...`);
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
"canonical-json": "^0.2.0",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^17.2.3",
|
||||
"etcd3": "^1.1.2",
|
||||
"exifr": "^7.1.3",
|
||||
"express": "^5.1.0",
|
||||
"express-session": "^1.18.2",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { fileModel } from '../schemas/management/file.schema.js';
|
||||
import { fileModel } from './schemas/management/file.schema.js';
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
deleteAuditLog,
|
||||
@ -7,7 +7,7 @@ import {
|
||||
expandObjectIds,
|
||||
modelHasRef,
|
||||
getFieldsByRef,
|
||||
jsonToCacheKey,
|
||||
getQueryToCacheKey,
|
||||
} from '../utils.js';
|
||||
import log4js from 'log4js';
|
||||
import {
|
||||
@ -18,9 +18,11 @@ import {
|
||||
distributeChildUpdate,
|
||||
distributeChildDelete,
|
||||
distributeChildNew,
|
||||
distributeStats,
|
||||
} from '../utils.js';
|
||||
import { getAllModels } from '../services/misc/model.js';
|
||||
import { redisServer } from './redis.js';
|
||||
import { auditLogModel } from './schemas/management/auditlog.schema.js';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
@ -35,19 +37,14 @@ const CACHE_TTL_SECONDS = parseInt(process.env.REDIS_CACHE_TTL || '30', 10);
|
||||
export const retrieveObjectCache = async ({ model, id, populate = [] }) => {
|
||||
if (!model || !id) return undefined;
|
||||
|
||||
const cacheKeyObject = {
|
||||
model: model.modelName,
|
||||
id: id.toString(),
|
||||
};
|
||||
const cacheKey = getQueryToCacheKey({ model: model.modelName, id, populate });
|
||||
|
||||
const cacheKey = jsonToCacheKey(cacheKeyObject);
|
||||
|
||||
cacheLogger.trace('Retrieving object from cache:', cacheKeyObject);
|
||||
cacheLogger.trace('Retrieving object from cache:', { model: model.modelName, id, populate });
|
||||
|
||||
try {
|
||||
const cachedObject = await redisServer.getKey(cacheKey);
|
||||
if (cachedObject == null) {
|
||||
cacheLogger.trace('Cache miss:', cacheKeyObject);
|
||||
cacheLogger.trace('Cache miss:', { model: model.modelName, id });
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -66,48 +63,285 @@ export const retrieveObjectCache = async ({ model, id, populate = [] }) => {
|
||||
export const updateObjectCache = async ({ model, id, object, populate = [] }) => {
|
||||
if (!model || !id || !object) return object;
|
||||
|
||||
const cacheKeyObject = {
|
||||
model: model.modelName,
|
||||
id: id.toString(),
|
||||
};
|
||||
const cacheKeyFilter = `${model.modelName}:${id?.toString()}*`;
|
||||
const cacheKey = getQueryToCacheKey({ model: model.modelName, id, populate });
|
||||
|
||||
const cacheKey = jsonToCacheKey(cacheKeyObject);
|
||||
|
||||
cacheLogger.trace('Updating object cache:', cacheKeyObject);
|
||||
cacheLogger.trace('Updating object cache:', cacheKeyFilter);
|
||||
|
||||
try {
|
||||
const cachedObject = (await redisServer.getKey(cacheKey)) || {};
|
||||
const mergedObject = _.merge(cachedObject, object);
|
||||
// Get all keys matching the filter pattern
|
||||
const matchingKeys = await redisServer.getKeysByPattern(cacheKeyFilter);
|
||||
// Merge the object with each cached object and update
|
||||
const mergedObjects = [];
|
||||
for (const key of matchingKeys) {
|
||||
logger.trace('Updating object cache:', key);
|
||||
const cachedObject = (await redisServer.getKey(key)) || {};
|
||||
const mergedObject = _.merge(cachedObject, object);
|
||||
await redisServer.setKey(key, mergedObject, CACHE_TTL_SECONDS);
|
||||
mergedObjects.push(mergedObject);
|
||||
}
|
||||
|
||||
const cacheObject = (await redisServer.getKey(cacheKey)) || {};
|
||||
const mergedObject = _.merge(cacheObject, object);
|
||||
await redisServer.setKey(cacheKey, mergedObject, CACHE_TTL_SECONDS);
|
||||
cacheLogger.trace('Updated object cache:', cacheKeyObject);
|
||||
|
||||
cacheLogger.trace('Updated object cache:', {
|
||||
filter: cacheKeyFilter,
|
||||
keysUpdated: matchingKeys.length,
|
||||
});
|
||||
|
||||
// Return the merged object
|
||||
return mergedObject;
|
||||
} catch (err) {
|
||||
cacheLogger.error('Error updating object in Redis cache:', err);
|
||||
// Fallback to returning the provided object if cache fails
|
||||
return object;
|
||||
}
|
||||
|
||||
return object;
|
||||
};
|
||||
|
||||
export const deleteObjectCache = async ({ model, id }) => {
|
||||
if (!model || !id) return;
|
||||
|
||||
const cacheKeyObject = {
|
||||
model: model.modelName,
|
||||
id: id.toString(),
|
||||
populate: [],
|
||||
};
|
||||
const cacheKeyFilter = `${model.modelName}:${id?.toString()}*`;
|
||||
|
||||
const cacheKey = jsonToCacheKey(cacheKeyObject);
|
||||
|
||||
cacheLogger.trace('Deleting object cache:', cacheKeyObject);
|
||||
cacheLogger.trace('Deleting object cache:', cacheKeyFilter);
|
||||
|
||||
try {
|
||||
await redisServer.deleteKey(cacheKey);
|
||||
cacheLogger.trace('Deleted object cache:', cacheKeyObject);
|
||||
// Get all keys matching the filter pattern and delete them
|
||||
const matchingKeys = await redisServer.getKeysByPattern(cacheKeyFilter);
|
||||
|
||||
for (const cacheKey of matchingKeys) {
|
||||
await redisServer.deleteKey(cacheKey);
|
||||
}
|
||||
|
||||
cacheLogger.trace('Deleted object cache:', {
|
||||
filter: cacheKeyFilter,
|
||||
keysDeleted: matchingKeys.length,
|
||||
});
|
||||
} catch (err) {
|
||||
cacheLogger.error('Error deleting object from Redis cache:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// Utility to run one or many rollup aggregations in a single query via $facet.
|
||||
export const aggregateRollups = async ({ model, baseFilter = {}, rollupConfigs = [] }) => {
|
||||
if (!rollupConfigs.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const facetStage = rollupConfigs.reduce((facets, definition, index) => {
|
||||
const key = definition.name || `rollup${index}`;
|
||||
const matchStage = { $match: { ...baseFilter, ...(definition.filter || {}) } };
|
||||
const groupStage = { $group: { _id: null } };
|
||||
|
||||
(definition.rollups || []).forEach((rollup) => {
|
||||
switch (rollup.operation) {
|
||||
case 'sum':
|
||||
groupStage.$group[rollup.name] = { $sum: `$${rollup.property}` };
|
||||
break;
|
||||
case 'count':
|
||||
groupStage.$group[rollup.name] = { $sum: 1 };
|
||||
break;
|
||||
case 'avg':
|
||||
groupStage.$group[rollup.name] = { $avg: `$${rollup.property}` };
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported rollup operation: ${rollup.operation}`);
|
||||
}
|
||||
});
|
||||
|
||||
facets[key] = [matchStage, groupStage];
|
||||
return facets;
|
||||
}, {});
|
||||
|
||||
const [results] = await model.aggregate([{ $facet: facetStage }]);
|
||||
|
||||
return rollupConfigs.reduce((acc, definition, index) => {
|
||||
const key = definition.name || `rollup${index}`;
|
||||
const rawResult = results?.[key]?.[0] || {};
|
||||
|
||||
// Transform the result to nest rollup values under operation type
|
||||
const transformedResult = {};
|
||||
(definition.rollups || []).forEach((rollup) => {
|
||||
const value = rawResult[rollup.name] || 0;
|
||||
// If there's only one rollup and its name matches the key, flatten the structure
|
||||
if (definition.rollups.length === 1 && rollup.name === key) {
|
||||
transformedResult[rollup.operation] = value;
|
||||
} else {
|
||||
transformedResult[rollup.name] = { [rollup.operation]: value };
|
||||
}
|
||||
});
|
||||
|
||||
acc[key] = transformedResult;
|
||||
return acc;
|
||||
}, {});
|
||||
};
|
||||
|
||||
// Reusable function to aggregate rollups over history using state reconstruction
|
||||
export const aggregateRollupsHistory = async ({
|
||||
model,
|
||||
baseFilter = {},
|
||||
rollupConfigs = [],
|
||||
startDate,
|
||||
endDate,
|
||||
}) => {
|
||||
if (!rollupConfigs.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Set default dates if not provided
|
||||
const end = endDate ? new Date(endDate) : new Date();
|
||||
const start = startDate ? new Date(startDate) : new Date(end.getTime() - 24 * 60 * 60 * 1000);
|
||||
|
||||
// Get model name for filtering audit logs
|
||||
const parentType = model.modelName ? model.modelName : 'unknown';
|
||||
|
||||
// 1. Fetch all audit logs for this model type from start date to now
|
||||
// Filter by parentType instead of fetching object IDs first
|
||||
const auditLogs = await auditLogModel
|
||||
.find({
|
||||
parentType,
|
||||
createdAt: { $gte: start },
|
||||
})
|
||||
.sort({ createdAt: -1 }) // Newest first
|
||||
.lean();
|
||||
|
||||
// 2. Extract unique parent IDs from audit logs
|
||||
const parentIds = [...new Set(auditLogs.map((log) => log.parent.toString()))];
|
||||
|
||||
if (parentIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 3. Fetch current state of relevant objects that match baseFilter
|
||||
// Note: This only includes objects that CURRENTLY match the baseFilter.
|
||||
// Objects that matched in the past but don't match now are excluded.
|
||||
const currentObjects = await model
|
||||
.find({
|
||||
_id: { $in: parentIds },
|
||||
...baseFilter,
|
||||
})
|
||||
.lean();
|
||||
const objectMap = new Map();
|
||||
currentObjects.forEach((obj) => {
|
||||
// Ensure _id is a string for map keys
|
||||
objectMap.set(obj._id.toString(), expandObjectIds(obj));
|
||||
});
|
||||
|
||||
if (objectMap.size === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Helper to check if object matches filter
|
||||
const matchesFilter = (obj, filter) => {
|
||||
if (!filter || Object.keys(filter).length === 0) return true;
|
||||
|
||||
for (const [key, expectedValue] of Object.entries(filter)) {
|
||||
const actualValue = _.get(obj, key);
|
||||
|
||||
// Handle simple equality
|
||||
if (actualValue != expectedValue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// 3. Generate time buckets (1 minute intervals)
|
||||
const buckets = [];
|
||||
let currentTime = new Date(end);
|
||||
// Round down to nearest minute
|
||||
currentTime.setSeconds(0, 0);
|
||||
|
||||
while (currentTime >= start) {
|
||||
buckets.push(new Date(currentTime));
|
||||
currentTime = new Date(currentTime.getTime() - 60000); // -1 minute
|
||||
}
|
||||
|
||||
// 4. Rewind state and snapshot
|
||||
const results = [];
|
||||
let logIndex = 0;
|
||||
|
||||
// Create a working copy of objects to mutate during rewind
|
||||
// (deep clone to avoid issues if we need original later, though expandObjectIds creates new objs)
|
||||
const workingObjects = new Map();
|
||||
objectMap.forEach((val, key) => workingObjects.set(key, _.cloneDeep(val)));
|
||||
|
||||
// Iterate backwards through time
|
||||
for (const bucketDate of buckets) {
|
||||
// Apply all logs that happened AFTER this bucket time (between last bucket and this one)
|
||||
// Since we iterate backwards, these are logs with createdAt > bucketDate
|
||||
while (logIndex < auditLogs.length) {
|
||||
const log = auditLogs[logIndex];
|
||||
const logDate = new Date(log.createdAt);
|
||||
|
||||
if (logDate <= bucketDate) {
|
||||
// This log happened at or before the current bucket time,
|
||||
// so its effects are already present (or rather, will be handled in a future/earlier bucket).
|
||||
// Stop processing logs for this step.
|
||||
break;
|
||||
}
|
||||
|
||||
// Revert this change
|
||||
const objectId = log.parent.toString();
|
||||
const object = workingObjects.get(objectId);
|
||||
|
||||
if (object) {
|
||||
if (log.operation === 'new') {
|
||||
// Object didn't exist before this creation event
|
||||
workingObjects.delete(objectId);
|
||||
} else if (log.changes && log.changes.old) {
|
||||
// Apply old values to revert state
|
||||
_.merge(object, log.changes.old);
|
||||
}
|
||||
}
|
||||
|
||||
logIndex++;
|
||||
}
|
||||
|
||||
// Snapshot: Calculate rollups for current state of all objects
|
||||
const bucketResult = {
|
||||
date: bucketDate.toISOString(),
|
||||
};
|
||||
|
||||
const activeObjects = Array.from(workingObjects.values());
|
||||
|
||||
rollupConfigs.forEach((config) => {
|
||||
const configName = config.name;
|
||||
|
||||
// Filter objects for this config
|
||||
// Note: We also check baseFilter here in case the object state reverted to something
|
||||
// that no longer matches baseFilter (e.g. active: false)
|
||||
const matchingObjects = activeObjects.filter(
|
||||
(obj) => matchesFilter(obj, baseFilter) && matchesFilter(obj, config.filter)
|
||||
);
|
||||
|
||||
// Calculate rollups
|
||||
(config.rollups || []).forEach((rollup) => {
|
||||
const rollupName = rollup.name;
|
||||
|
||||
let value = 0;
|
||||
if (rollup.operation === 'count') {
|
||||
value = matchingObjects.length;
|
||||
} else if (rollup.operation === 'sum') {
|
||||
value = _.sumBy(matchingObjects, (obj) => _.get(obj, rollup.property) || 0);
|
||||
} else if (rollup.operation === 'avg') {
|
||||
const sum = _.sumBy(matchingObjects, (obj) => _.get(obj, rollup.property) || 0);
|
||||
value = matchingObjects.length ? sum / matchingObjects.length : 0;
|
||||
}
|
||||
|
||||
// Nest the value under the operation type
|
||||
bucketResult[rollupName] = { [rollup.operation]: value };
|
||||
});
|
||||
});
|
||||
|
||||
results.push(bucketResult);
|
||||
}
|
||||
|
||||
// Reverse results to be chronological
|
||||
return results.reverse();
|
||||
};
|
||||
|
||||
// Reusable function to list objects with aggregation, filtering, search, sorting, and pagination
|
||||
export const listObjects = async ({
|
||||
model,
|
||||
@ -324,14 +558,13 @@ export const listObjectsByProperties = async ({
|
||||
} else if (typeof pop === 'object' && pop.path) {
|
||||
pipeline.push({
|
||||
$lookup: {
|
||||
from:
|
||||
pop.options && pop.options.from ? pop.options.from : pop.path.toLowerCase() + 's',
|
||||
from: pop.from ? pop.from : pop.path.toLowerCase(),
|
||||
localField: pop.path,
|
||||
foreignField: '_id',
|
||||
as: pop.path,
|
||||
},
|
||||
});
|
||||
if (!pop.justOne === false) {
|
||||
if (pop?.multiple == false || pop?.multiple == undefined) {
|
||||
// default to unwind unless justOne is explicitly false
|
||||
pipeline.push({
|
||||
$unwind: {
|
||||
@ -363,6 +596,7 @@ export const listObjectsByProperties = async ({
|
||||
|
||||
// Run aggregation
|
||||
const results = await model.aggregate(pipeline);
|
||||
console.log('results', results);
|
||||
return nestGroups(results, properties, filter);
|
||||
} else {
|
||||
// If no properties specified, just return all objects without grouping
|
||||
@ -435,6 +669,22 @@ export const getObject = async ({ model, id, populate }) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const getModelStats = async ({ model }) => {
|
||||
if (!model.stats) {
|
||||
logger.warn(`Model ${model.modelName} does not have a stats method.`);
|
||||
return { error: 'Model does not have a stats method.', code: 500 };
|
||||
}
|
||||
return await model.stats();
|
||||
};
|
||||
|
||||
export const getModelHistory = async ({ model, from, to }) => {
|
||||
if (!model.history && !from && !to) {
|
||||
logger.warn(`Model ${model.modelName} does not have a history method.`);
|
||||
return { error: 'Model does not have a history method.', code: 500 };
|
||||
}
|
||||
return await model.history(from, to);
|
||||
};
|
||||
|
||||
export const listObjectDependencies = async ({ model, id }) => {
|
||||
try {
|
||||
const dependencies = [];
|
||||
@ -562,6 +812,17 @@ export const editObject = async ({ model, id, updateData, user, populate }) => {
|
||||
populate,
|
||||
});
|
||||
|
||||
if (model.recalculate) {
|
||||
logger.debug(`Recalculating ${model.modelName}`);
|
||||
await model.recalculate(updatedObject, user);
|
||||
}
|
||||
|
||||
if (model.stats) {
|
||||
logger.debug(`Getting stats for ${model.modelName}`);
|
||||
const statsData = await model.stats();
|
||||
await distributeStats(statsData, parentType);
|
||||
}
|
||||
|
||||
return updatedObject;
|
||||
} catch (error) {
|
||||
logger.error('editObject error:', error);
|
||||
@ -594,6 +855,17 @@ export const newObject = async ({ model, newData, user = null }, distributeChang
|
||||
populate: [],
|
||||
});
|
||||
|
||||
if (model.recalculate) {
|
||||
logger.debug(`Recalculating ${model.modelName}`);
|
||||
await model.recalculate(created, user);
|
||||
}
|
||||
|
||||
if (model.stats) {
|
||||
logger.debug(`Getting stats for ${model.modelName}`);
|
||||
const statsData = await model.stats();
|
||||
await distributeStats(statsData, parentType);
|
||||
}
|
||||
|
||||
return created;
|
||||
} catch (error) {
|
||||
logger.error('newObject error:', error);
|
||||
@ -625,6 +897,17 @@ export const deleteObject = async ({ model, id, user = null }, distributeChanges
|
||||
// Invalidate cache for this object
|
||||
await deleteObjectCache({ model, id });
|
||||
|
||||
if (model.recalculate) {
|
||||
logger.debug(`Recalculating ${model.modelName}`);
|
||||
await model.recalculate(deleted, user);
|
||||
}
|
||||
|
||||
if (model.stats) {
|
||||
logger.debug(`Getting stats for ${model.modelName}`);
|
||||
const statsData = await model.stats();
|
||||
await distributeStats(statsData, parentType);
|
||||
}
|
||||
|
||||
return { deleted: true, object: deleted };
|
||||
} catch (error) {
|
||||
logger.error('deleteObject error:', error);
|
||||
|
||||
@ -1,110 +0,0 @@
|
||||
import { Etcd3 } from 'etcd3';
|
||||
import log4js from 'log4js';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const ETCD_HOST = process.env.ETCD_HOST || 'localhost';
|
||||
const ETCD_PORT = process.env.ETCD_PORT || 2379;
|
||||
const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
|
||||
|
||||
const logger = log4js.getLogger('Etcd');
|
||||
logger.level = LOG_LEVEL;
|
||||
|
||||
class EtcdServer {
|
||||
constructor() {
|
||||
this.client = null;
|
||||
this.watchers = new Map();
|
||||
this.hosts = [`${ETCD_HOST}:${ETCD_PORT}`];
|
||||
logger.trace(`EtcdServer constructor: hosts set to ${JSON.stringify(this.hosts)}`);
|
||||
}
|
||||
|
||||
async connect() {
|
||||
if (!this.client) {
|
||||
logger.info('Connecting to Etcd...');
|
||||
logger.trace(`Creating Etcd client with hosts ${JSON.stringify(this.hosts)}`);
|
||||
this.client = new Etcd3({
|
||||
hosts: this.hosts,
|
||||
});
|
||||
|
||||
// Test connection
|
||||
try {
|
||||
await this.client.get('test-connection').string();
|
||||
logger.trace('Etcd client connected successfully.');
|
||||
} catch (error) {
|
||||
if (error.code === 'NOT_FOUND') {
|
||||
logger.trace('Etcd client connected successfully (test key not found as expected).');
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.trace('Etcd client already exists, skipping connection.');
|
||||
}
|
||||
return this.client;
|
||||
}
|
||||
|
||||
async getClient() {
|
||||
logger.trace('Checking if Etcd client exists.');
|
||||
if (!this.client) {
|
||||
logger.trace('No client found, calling connect().');
|
||||
await this.connect();
|
||||
}
|
||||
logger.trace('Returning Etcd client.');
|
||||
return this.client;
|
||||
}
|
||||
|
||||
// Hash-like functionality using etcd
|
||||
async setKey(key, value) {
|
||||
const client = await this.getClient();
|
||||
const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
|
||||
|
||||
await client.put(key).value(stringValue);
|
||||
logger.trace(`Set key: ${key}, value: ${stringValue}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
async getKey(key) {
|
||||
const client = await this.getClient();
|
||||
|
||||
try {
|
||||
const value = await client.get(key).string();
|
||||
logger.trace(`Retrieved key: ${key}, value: ${value}`);
|
||||
|
||||
// Try to parse as JSON, fallback to string
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch {
|
||||
return value;
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code === 'NOT_FOUND') {
|
||||
logger.trace(`Key not found: ${key}`);
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
logger.info('Disconnecting from Etcd...');
|
||||
|
||||
// Stop all watchers
|
||||
for (const [key, watcher] of this.watchers) {
|
||||
logger.trace(`Stopping watcher: ${key}`);
|
||||
watcher.removeAllListeners();
|
||||
await watcher.close();
|
||||
}
|
||||
this.watchers.clear();
|
||||
|
||||
if (this.client) {
|
||||
await this.client.close();
|
||||
this.client = null;
|
||||
logger.info('Disconnected from Etcd');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const etcdServer = new EtcdServer();
|
||||
|
||||
export { EtcdServer, etcdServer };
|
||||
@ -31,6 +31,7 @@ class RedisServer {
|
||||
|
||||
async connect() {
|
||||
if (this.connected) return;
|
||||
logger.info('Connecting to Redis...');
|
||||
await this.client.connect();
|
||||
this.connected = true;
|
||||
logger.info('Connected to Redis');
|
||||
@ -61,6 +62,21 @@ class RedisServer {
|
||||
await this.connect();
|
||||
await this.client.del(key);
|
||||
}
|
||||
|
||||
async getKeysByPattern(pattern) {
|
||||
await this.connect();
|
||||
const keys = [];
|
||||
let cursor = '0';
|
||||
do {
|
||||
const result = await this.client.scan(cursor, {
|
||||
MATCH: pattern,
|
||||
COUNT: 100,
|
||||
});
|
||||
cursor = result.cursor;
|
||||
keys.push(...result.keys);
|
||||
} while (cursor !== '0');
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
const redisServer = new RedisServer();
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
||||
|
||||
// Define the main filamentStock schema
|
||||
const filamentStockSchema = new Schema(
|
||||
@ -23,6 +24,35 @@ const filamentStockSchema = new Schema(
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const rollupConfigs = [
|
||||
{
|
||||
name: 'totalCurrentWeight',
|
||||
filter: {},
|
||||
rollups: [{ name: 'totalCurrentWeight', property: 'currentWeight.net', operation: 'sum' }],
|
||||
},
|
||||
];
|
||||
|
||||
filamentStockSchema.statics.stats = async function () {
|
||||
const results = await aggregateRollups({
|
||||
model: this,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
filamentStockSchema.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
|
||||
filamentStockSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
82
src/database/schemas/inventory/orderitem.schema.js
Normal file
82
src/database/schemas/inventory/orderitem.schema.js
Normal file
@ -0,0 +1,82 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { purchaseOrderModel } from './purchaseorder.schema.js';
|
||||
import { aggregateRollups, editObject } from '../../database.js';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
const orderItemSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
orderType: { type: String, required: true },
|
||||
order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
|
||||
itemType: { type: String, required: true },
|
||||
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true },
|
||||
syncAmount: { type: String, required: true, default: null },
|
||||
itemAmount: { type: Number, required: true },
|
||||
quantity: { type: Number, required: true },
|
||||
totalAmount: { type: Number, required: true },
|
||||
taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
totalAmountWithTax: { type: Number, required: true },
|
||||
timestamp: { type: Date, default: Date.now },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
orderItemSchema.statics.recalculate = async function (orderItem, user) {
|
||||
// Only purchase orders are supported for now
|
||||
if (orderItem.orderType !== 'purchaseOrder') {
|
||||
return;
|
||||
}
|
||||
|
||||
const orderId = orderItem.order?._id || orderItem.order;
|
||||
if (!orderId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rollupResults = await aggregateRollups({
|
||||
model: this,
|
||||
baseFilter: {
|
||||
order: new mongoose.Types.ObjectId(orderId),
|
||||
orderType: orderItem.orderType,
|
||||
},
|
||||
rollupConfigs: [
|
||||
{
|
||||
name: 'orderTotals',
|
||||
rollups: [
|
||||
{ name: 'totalAmount', property: 'totalAmount', operation: 'sum' },
|
||||
{
|
||||
name: 'totalAmountWithTax',
|
||||
property: 'totalAmountWithTax',
|
||||
operation: 'sum',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const totals = rollupResults.orderTotals || {};
|
||||
const totalAmount = totals.totalAmount.sum?.toFixed(2) || 0;
|
||||
const totalAmountWithTax = totals.totalAmountWithTax.sum?.toFixed(2) || 0;
|
||||
|
||||
await editObject({
|
||||
model: purchaseOrderModel,
|
||||
id: orderId,
|
||||
updateData: {
|
||||
totalAmount: parseFloat(totalAmount),
|
||||
totalAmountWithTax: parseFloat(totalAmountWithTax),
|
||||
totalTaxAmount: parseFloat(totalAmountWithTax - totalAmount),
|
||||
},
|
||||
user,
|
||||
});
|
||||
};
|
||||
|
||||
// Add virtual id getter
|
||||
orderItemSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
});
|
||||
|
||||
// Configure JSON serialization to include virtuals
|
||||
orderItemSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
// Create and export the model
|
||||
export const orderItemModel = mongoose.model('orderItem', orderItemSchema);
|
||||
@ -1,6 +1,7 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
||||
|
||||
// Define the main partStock schema
|
||||
const partStockSchema = new Schema(
|
||||
@ -18,6 +19,35 @@ const partStockSchema = new Schema(
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const rollupConfigs = [
|
||||
{
|
||||
name: 'totalCurrentQuantity',
|
||||
filter: {},
|
||||
rollups: [{ name: 'totalCurrentQuantity', property: 'currentQuantity', operation: 'sum' }],
|
||||
},
|
||||
];
|
||||
|
||||
partStockSchema.statics.stats = async function () {
|
||||
const results = await aggregateRollups({
|
||||
model: this,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
partStockSchema.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
|
||||
partStockSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
@ -2,21 +2,12 @@ import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
const itemSchema = new Schema({
|
||||
itemType: { type: String, required: true },
|
||||
item: { type: Schema.Types.ObjectId, refPath: 'items.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 purchaseOrderSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
cost: { net: { type: Number, required: true }, gross: { type: Number, required: true } },
|
||||
items: [itemSchema],
|
||||
totalAmount: { type: Number, required: true },
|
||||
totalAmountWithTax: { type: Number, required: true },
|
||||
totalTaxAmount: { type: Number, required: true },
|
||||
timestamp: { type: Date, default: Date.now },
|
||||
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
|
||||
state: {
|
||||
@ -18,7 +18,8 @@ const documentJobSchema = new Schema(
|
||||
},
|
||||
state: {
|
||||
type: { type: String, required: true, default: 'queued' },
|
||||
percent: { type: Number, required: false },
|
||||
progress: { type: Number, required: false },
|
||||
message: { type: String, required: false },
|
||||
},
|
||||
documentTemplate: {
|
||||
type: Schema.Types.ObjectId,
|
||||
@ -12,6 +12,8 @@ const filamentSchema = new mongoose.Schema({
|
||||
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
|
||||
type: { required: true, type: String },
|
||||
cost: { required: true, type: Number },
|
||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: true },
|
||||
costWithTax: { required: true, type: Number },
|
||||
diameter: { required: true, type: Number },
|
||||
density: { required: true, type: Number },
|
||||
createdAt: { required: true, type: Date },
|
||||
@ -8,6 +8,7 @@ import { productModel } from './management/product.schema.js';
|
||||
import { vendorModel } from './management/vendor.schema.js';
|
||||
import { filamentStockModel } from './inventory/filamentstock.schema.js';
|
||||
import { purchaseOrderModel } from './inventory/purchaseorder.schema.js';
|
||||
import { orderItemModel } from './inventory/orderitem.schema.js';
|
||||
import { stockEventModel } from './inventory/stockevent.schema.js';
|
||||
import { stockAuditModel } from './inventory/stockaudit.schema.js';
|
||||
import { partStockModel } from './inventory/partstock.schema.js';
|
||||
@ -82,6 +83,12 @@ export const models = {
|
||||
type: 'purchaseOrder',
|
||||
referenceField: '_reference',
|
||||
},
|
||||
ODI: {
|
||||
model: orderItemModel,
|
||||
idField: '_id',
|
||||
type: 'orderItem',
|
||||
referenceField: '_reference',
|
||||
},
|
||||
COS: {
|
||||
model: courierServiceModel,
|
||||
idField: '_id',
|
||||
91
src/database/schemas/production/job.schema.js
Normal file
91
src/database/schemas/production/job.schema.js
Normal file
@ -0,0 +1,91 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
||||
|
||||
const jobSchema = new mongoose.Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
state: {
|
||||
type: { required: true, type: String },
|
||||
progress: { type: Number, required: false },
|
||||
},
|
||||
printers: [{ type: Schema.Types.ObjectId, ref: 'printer', required: false }],
|
||||
createdAt: { required: true, type: Date },
|
||||
updatedAt: { required: true, type: Date },
|
||||
startedAt: { required: false, type: Date, default: null },
|
||||
finishedAt: { required: false, type: Date, default: null },
|
||||
gcodeFile: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'gcodeFile',
|
||||
required: false,
|
||||
},
|
||||
quantity: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 1,
|
||||
min: 1,
|
||||
},
|
||||
subJobs: [{ type: Schema.Types.ObjectId, ref: 'subJob', required: false }],
|
||||
notes: [{ type: Schema.Types.ObjectId, ref: 'note', required: false }],
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const rollupConfigs = [
|
||||
{
|
||||
name: 'queued',
|
||||
filter: { 'state.type': 'queued' },
|
||||
rollups: [{ name: 'queued', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'printing',
|
||||
filter: { 'state.type': 'printing' },
|
||||
rollups: [{ name: 'printing', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'draft',
|
||||
filter: { 'state.type': 'draft' },
|
||||
rollups: [{ name: 'draft', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'complete',
|
||||
filter: { 'state.type': 'complete' },
|
||||
rollups: [{ name: 'complete', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'failed',
|
||||
filter: { 'state.type': 'failed' },
|
||||
rollups: [{ name: 'failed', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
];
|
||||
|
||||
jobSchema.statics.stats = async function () {
|
||||
const results = await aggregateRollups({
|
||||
model: this,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
// Transform the results to match the expected format
|
||||
return results;
|
||||
};
|
||||
|
||||
jobSchema.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;
|
||||
};
|
||||
|
||||
jobSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
});
|
||||
|
||||
jobSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
export const jobModel = mongoose.model('job', jobSchema);
|
||||
@ -1,6 +1,7 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
||||
|
||||
// Define the moonraker connection schema
|
||||
const moonrakerSchema = new Schema(
|
||||
@ -56,6 +57,59 @@ const printerSchema = new Schema(
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const rollupConfigs = [
|
||||
{
|
||||
name: 'standby',
|
||||
filter: { 'state.type': 'standby' },
|
||||
rollups: [{ name: 'standby', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'complete',
|
||||
filter: { 'state.type': 'complete' },
|
||||
rollups: [{ name: 'complete', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'printing',
|
||||
filter: { 'state.type': 'printing' },
|
||||
rollups: [{ name: 'printing', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'error',
|
||||
filter: { 'state.type': 'error' },
|
||||
rollups: [{ name: 'error', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'offline',
|
||||
filter: { 'state.type': 'offline' },
|
||||
rollups: [{ name: 'offline', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
];
|
||||
|
||||
printerSchema.statics.stats = async function () {
|
||||
const results = await aggregateRollups({
|
||||
model: this,
|
||||
baseFilter: { active: true },
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
console.log(results);
|
||||
|
||||
// Transform the results to match the expected format
|
||||
return results;
|
||||
};
|
||||
|
||||
printerSchema.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
|
||||
printerSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
7
src/database/utils.js
Normal file
7
src/database/utils.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { customAlphabet } from 'nanoid';
|
||||
|
||||
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
export const generateId = () => {
|
||||
// 10 characters
|
||||
return customAlphabet(ALPHABET, 12);
|
||||
};
|
||||
@ -21,6 +21,8 @@ import {
|
||||
partStockRoutes,
|
||||
filamentStockRoutes,
|
||||
purchaseOrderRoutes,
|
||||
orderItemRoutes,
|
||||
shipmentRoutes,
|
||||
stockAuditRoutes,
|
||||
stockEventRoutes,
|
||||
auditLogRoutes,
|
||||
@ -41,7 +43,6 @@ import * as fs from 'fs';
|
||||
import cron from 'node-cron';
|
||||
import ReseedAction from './database/ReseedAction.js';
|
||||
import log4js from 'log4js';
|
||||
import { etcdServer } from './database/etcd.js';
|
||||
import { populateUserMiddleware } from './services/misc/auth.js';
|
||||
import { natsServer } from './database/nats.js';
|
||||
import { initializeBuckets } from './services/storage/ceph.js';
|
||||
@ -74,10 +75,6 @@ async function initializeApp() {
|
||||
// Connect to database
|
||||
dbConnect();
|
||||
|
||||
// Connect to Etcd
|
||||
//etcdServer.connect();
|
||||
//logger.info('Connected to Etcd');
|
||||
|
||||
// Connect to NATS
|
||||
natsServer.connect();
|
||||
logger.info('Connected to NATS');
|
||||
@ -129,6 +126,8 @@ app.use('/materials', materialRoutes);
|
||||
app.use('/partstocks', partStockRoutes);
|
||||
app.use('/filamentstocks', filamentStockRoutes);
|
||||
app.use('/purchaseorders', purchaseOrderRoutes);
|
||||
app.use('/orderitems', orderItemRoutes);
|
||||
app.use('/shipments', shipmentRoutes);
|
||||
app.use('/stockevents', stockEventRoutes);
|
||||
app.use('/stockaudits', stockAuditRoutes);
|
||||
app.use('/auditlogs', auditLogRoutes);
|
||||
|
||||
@ -5,9 +5,9 @@ import axios from 'axios';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import log4js from 'log4js';
|
||||
import NodeCache from 'node-cache';
|
||||
import { userModel } from './schemas/management/user.schema.js';
|
||||
import { userModel } from './database/schemas/management/user.schema.js';
|
||||
import { getObject } from './database/database.js';
|
||||
import { hostModel } from './schemas/management/host.schema.js';
|
||||
import { hostModel } from './database/schemas/management/host.schema.js';
|
||||
|
||||
dotenv.config();
|
||||
const logger = log4js.getLogger('Keycloak');
|
||||
|
||||
@ -15,6 +15,8 @@ import materialRoutes from './management/materials.js';
|
||||
import partStockRoutes from './inventory/partstocks.js';
|
||||
import filamentStockRoutes from './inventory/filamentstocks.js';
|
||||
import purchaseOrderRoutes from './inventory/purchaseorders.js';
|
||||
import orderItemRoutes from './inventory/orderitems.js';
|
||||
import shipmentRoutes from './inventory/shipments.js';
|
||||
import stockEventRoutes from './inventory/stockevents.js';
|
||||
import stockAuditRoutes from './inventory/stockaudits.js';
|
||||
import auditLogRoutes from './management/auditlogs.js';
|
||||
@ -47,6 +49,8 @@ export {
|
||||
partStockRoutes,
|
||||
filamentStockRoutes,
|
||||
purchaseOrderRoutes,
|
||||
orderItemRoutes,
|
||||
shipmentRoutes,
|
||||
stockEventRoutes,
|
||||
stockAuditRoutes,
|
||||
auditLogRoutes,
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newFilamentStockRouteHandler,
|
||||
deleteFilamentStockRouteHandler,
|
||||
listFilamentStocksByPropertiesRouteHandler,
|
||||
getFilamentStockStatsRouteHandler,
|
||||
getFilamentStockHistoryRouteHandler,
|
||||
} from '../../services/inventory/filamentstocks.js';
|
||||
|
||||
// list of filament stocks
|
||||
@ -35,6 +37,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newFilamentStockRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get filament stock stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getFilamentStockStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get filament stock history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getFilamentStockHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getFilamentStockRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newOrderItemRouteHandler,
|
||||
deleteOrderItemRouteHandler,
|
||||
listOrderItemsByPropertiesRouteHandler,
|
||||
getOrderItemStatsRouteHandler,
|
||||
getOrderItemHistoryRouteHandler,
|
||||
} from '../../services/inventory/orderitems.js';
|
||||
|
||||
// list of order items
|
||||
@ -35,6 +37,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newOrderItemRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get order item stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getOrderItemStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get order item history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getOrderItemHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getOrderItemRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newPartStockRouteHandler,
|
||||
deletePartStockRouteHandler,
|
||||
listPartStocksByPropertiesRouteHandler,
|
||||
getPartStockStatsRouteHandler,
|
||||
getPartStockHistoryRouteHandler,
|
||||
} from '../../services/inventory/partstocks.js';
|
||||
|
||||
// list of part stocks
|
||||
@ -35,6 +37,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newPartStockRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get part stock stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getPartStockStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get part stock history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getPartStockHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getPartStockRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newPurchaseOrderRouteHandler,
|
||||
deletePurchaseOrderRouteHandler,
|
||||
listPurchaseOrdersByPropertiesRouteHandler,
|
||||
getPurchaseOrderStatsRouteHandler,
|
||||
getPurchaseOrderHistoryRouteHandler,
|
||||
} from '../../services/inventory/purchaseorders.js';
|
||||
|
||||
// list of purchase orders
|
||||
@ -35,6 +37,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newPurchaseOrderRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get purchase order stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getPurchaseOrderStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get purchase order history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getPurchaseOrderHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getPurchaseOrderRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newShipmentRouteHandler,
|
||||
deleteShipmentRouteHandler,
|
||||
listShipmentsByPropertiesRouteHandler,
|
||||
getShipmentStatsRouteHandler,
|
||||
getShipmentHistoryRouteHandler,
|
||||
} from '../../services/inventory/shipments.js';
|
||||
|
||||
// list of shipments
|
||||
@ -49,6 +51,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newShipmentRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get shipment stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getShipmentStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get shipment history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getShipmentHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getShipmentRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -9,6 +9,8 @@ import {
|
||||
newStockAuditRouteHandler,
|
||||
updateStockAuditRouteHandler,
|
||||
deleteStockAuditRouteHandler,
|
||||
getStockAuditStatsRouteHandler,
|
||||
getStockAuditHistoryRouteHandler,
|
||||
} from '../../services/inventory/stockaudits.js';
|
||||
|
||||
// List stock audits
|
||||
@ -36,6 +38,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newStockAuditRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get stock audit stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getStockAuditStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get stock audit history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getStockAuditHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// Get specific stock audit
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getStockAuditRouteHandler(req, res);
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
editStockEventRouteHandler,
|
||||
deleteStockEventRouteHandler,
|
||||
listStockEventsByPropertiesRouteHandler,
|
||||
getStockEventStatsRouteHandler,
|
||||
getStockEventHistoryRouteHandler,
|
||||
} from '../../services/inventory/stockevents.js';
|
||||
|
||||
// list of stock events
|
||||
@ -35,6 +37,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newStockEventRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get stock event stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getStockEventStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get stock event history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getStockEventHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getStockEventRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -3,6 +3,8 @@ import { isAuthenticated } from '../../keycloak.js';
|
||||
import {
|
||||
listAuditLogsRouteHandler,
|
||||
getAuditLogRouteHandler,
|
||||
getAuditLogStatsRouteHandler,
|
||||
getAuditLogHistoryRouteHandler,
|
||||
} from '../../services/management/auditlogs.js';
|
||||
import { parseFilter } from '../../utils.js';
|
||||
|
||||
@ -27,6 +29,16 @@ router.get('/', isAuthenticated, async (req, res) => {
|
||||
listAuditLogsRouteHandler(req, res, page, limit, filter, sort, order);
|
||||
});
|
||||
|
||||
// get audit log stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getAuditLogStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get audit log history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getAuditLogHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
/**
|
||||
* @route GET /api/auditlogs/:id
|
||||
* @desc Get a single audit log by ID
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newCourierRouteHandler,
|
||||
deleteCourierRouteHandler,
|
||||
listCouriersByPropertiesRouteHandler,
|
||||
getCourierStatsRouteHandler,
|
||||
getCourierHistoryRouteHandler,
|
||||
} from '../../services/management/courier.js';
|
||||
|
||||
// list of couriers
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newCourierRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get courier stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getCourierStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get courier history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getCourierHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getCourierRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newCourierServiceRouteHandler,
|
||||
deleteCourierServiceRouteHandler,
|
||||
listCourierServicesByPropertiesRouteHandler,
|
||||
getCourierServiceStatsRouteHandler,
|
||||
getCourierServiceHistoryRouteHandler,
|
||||
} from '../../services/management/courierservice.js';
|
||||
|
||||
// list of courier services
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newCourierServiceRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get courier service stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getCourierServiceStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get courierservice history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getCourierServiceHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getCourierServiceRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newDocumentJobRouteHandler,
|
||||
deleteDocumentJobRouteHandler,
|
||||
listDocumentJobsByPropertiesRouteHandler,
|
||||
getDocumentJobStatsRouteHandler,
|
||||
getDocumentJobHistoryRouteHandler,
|
||||
} from '../../services/management/documentjobs.js';
|
||||
|
||||
// list of document jobs
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newDocumentJobRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get document job stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getDocumentJobStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get documentjobs history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getDocumentJobHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getDocumentJobRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newDocumentPrinterRouteHandler,
|
||||
deleteDocumentPrinterRouteHandler,
|
||||
listDocumentPrintersByPropertiesRouteHandler,
|
||||
getDocumentPrinterStatsRouteHandler,
|
||||
getDocumentPrinterHistoryRouteHandler,
|
||||
} from '../../services/management/documentprinters.js';
|
||||
|
||||
// list of document printers
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newDocumentPrinterRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get document printer stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getDocumentPrinterStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get documentprinters history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getDocumentPrinterHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getDocumentPrinterRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newDocumentSizeRouteHandler,
|
||||
deleteDocumentSizeRouteHandler,
|
||||
listDocumentSizesByPropertiesRouteHandler,
|
||||
getDocumentSizeStatsRouteHandler,
|
||||
getDocumentSizeHistoryRouteHandler,
|
||||
} from '../../services/management/documentsizes.js';
|
||||
|
||||
// list of document sizes
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newDocumentSizeRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get document size stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getDocumentSizeStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get documentsizes history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getDocumentSizeHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getDocumentSizeRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newDocumentTemplateRouteHandler,
|
||||
deleteDocumentTemplateRouteHandler,
|
||||
listDocumentTemplatesByPropertiesRouteHandler,
|
||||
getDocumentTemplateStatsRouteHandler,
|
||||
getDocumentTemplateHistoryRouteHandler,
|
||||
} from '../../services/management/documenttemplates.js';
|
||||
|
||||
// list of document templates
|
||||
@ -35,6 +37,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newDocumentTemplateRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get document template stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getDocumentTemplateStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get document template history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getDocumentTemplateHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getDocumentTemplateRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -9,6 +9,8 @@ import {
|
||||
getFilamentRouteHandler,
|
||||
editFilamentRouteHandler,
|
||||
newFilamentRouteHandler,
|
||||
getFilamentStatsRouteHandler,
|
||||
getFilamentHistoryRouteHandler,
|
||||
} from '../../services/management/filaments.js';
|
||||
|
||||
// list of filaments
|
||||
@ -50,6 +52,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newFilamentRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get filament stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getFilamentStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get filaments history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getFilamentHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getFilamentRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -12,6 +12,8 @@ import {
|
||||
flushFileRouteHandler,
|
||||
deleteFileRouteHandler,
|
||||
listFilesByPropertiesRouteHandler,
|
||||
getFileStatsRouteHandler,
|
||||
getFileHistoryRouteHandler,
|
||||
} from '../../services/management/files.js';
|
||||
|
||||
// list of files
|
||||
@ -33,6 +35,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newFileRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get file stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getFileStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get file history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getFileHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.delete('/:id/flush', isAuthenticated, (req, res) => {
|
||||
flushFileRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newHostRouteHandler,
|
||||
deleteHostRouteHandler,
|
||||
listHostsByPropertiesRouteHandler,
|
||||
getHostStatsRouteHandler,
|
||||
getHostHistoryRouteHandler,
|
||||
} from '../../services/management/hosts.js';
|
||||
|
||||
// list of hosts
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newHostRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get host stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getHostStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get hosts history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getHostHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getHostRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -8,6 +8,8 @@ import {
|
||||
getMaterialRouteHandler,
|
||||
editMaterialRouteHandler,
|
||||
newMaterialRouteHandler,
|
||||
getMaterialStatsRouteHandler,
|
||||
getMaterialHistoryRouteHandler,
|
||||
} from '../../services/management/materials.js';
|
||||
|
||||
// list of materials
|
||||
@ -34,6 +36,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newMaterialRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get material stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getMaterialStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get materials history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getMaterialHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getMaterialRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newNoteTypeRouteHandler,
|
||||
deleteNoteTypeRouteHandler,
|
||||
listNoteTypesByPropertiesRouteHandler,
|
||||
getNoteTypeStatsRouteHandler,
|
||||
getNoteTypeHistoryRouteHandler,
|
||||
} from '../../services/management/notetypes.js';
|
||||
|
||||
// list of note types
|
||||
@ -35,6 +37,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newNoteTypeRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get note type stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getNoteTypeStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get notetypes history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getNoteTypeHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getNoteTypeRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newPartRouteHandler,
|
||||
deletePartRouteHandler,
|
||||
listPartsByPropertiesRouteHandler,
|
||||
getPartStatsRouteHandler,
|
||||
getPartHistoryRouteHandler,
|
||||
} from '../../services/management/parts.js';
|
||||
|
||||
// list of parts
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newPartRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get part stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getPartStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get parts history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getPartHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getPartRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newProductRouteHandler,
|
||||
deleteProductRouteHandler,
|
||||
listProductsByPropertiesRouteHandler,
|
||||
getProductStatsRouteHandler,
|
||||
getProductHistoryRouteHandler,
|
||||
} from '../../services/management/products.js';
|
||||
|
||||
// list of products
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newProductRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get product stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getProductStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get products history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getProductHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getProductRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newTaxRateRouteHandler,
|
||||
deleteTaxRateRouteHandler,
|
||||
listTaxRatesByPropertiesRouteHandler,
|
||||
getTaxRateStatsRouteHandler,
|
||||
getTaxRateHistoryRouteHandler,
|
||||
} from '../../services/management/taxrates.js';
|
||||
|
||||
// list of tax rates
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newTaxRateRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get tax rate stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getTaxRateStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get tax rate history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getTaxRateHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getTaxRateRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newTaxRecordRouteHandler,
|
||||
deleteTaxRecordRouteHandler,
|
||||
listTaxRecordsByPropertiesRouteHandler,
|
||||
getTaxRecordStatsRouteHandler,
|
||||
getTaxRecordHistoryRouteHandler,
|
||||
} from '../../services/management/taxrecords.js';
|
||||
|
||||
// list of tax records
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newTaxRecordRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get tax record stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getTaxRecordStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get tax record history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getTaxRecordHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getTaxRecordRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -8,6 +8,8 @@ import {
|
||||
listUsersByPropertiesRouteHandler,
|
||||
getUserRouteHandler,
|
||||
editUserRouteHandler,
|
||||
getUserStatsRouteHandler,
|
||||
getUserHistoryRouteHandler,
|
||||
} from '../../services/management/users.js';
|
||||
|
||||
// list of document templates
|
||||
@ -29,6 +31,16 @@ router.get('/properties', isAuthenticated, (req, res) => {
|
||||
listUsersByPropertiesRouteHandler(req, res, properties, filter, masterFilter);
|
||||
});
|
||||
|
||||
// get user stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getUserStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get user history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getUserHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getUserRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -10,6 +10,8 @@ import {
|
||||
newVendorRouteHandler,
|
||||
deleteVendorRouteHandler,
|
||||
listVendorsByPropertiesRouteHandler,
|
||||
getVendorStatsRouteHandler,
|
||||
getVendorHistoryRouteHandler,
|
||||
} from '../../services/management/vendors.js';
|
||||
|
||||
// list of vendors
|
||||
@ -31,6 +33,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newVendorRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get vendor stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getVendorStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get vendors history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getVendorHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getVendorRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -6,8 +6,11 @@ import {
|
||||
editNoteRouteHandler,
|
||||
newNoteRouteHandler,
|
||||
deleteNoteRouteHandler,
|
||||
listNotesByPropertiesRouteHandler,
|
||||
getNoteStatsRouteHandler,
|
||||
getNoteHistoryRouteHandler,
|
||||
} from '../../services/misc/notes.js';
|
||||
import { getFilter } from '../../utils.js';
|
||||
import { getFilter, convertPropertiesString } from '../../utils.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@ -31,6 +34,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newNoteRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get note stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getNoteStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get note history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getNoteHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getNoteRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
newGCodeFileRouteHandler,
|
||||
listGCodeFilesByPropertiesRouteHandler,
|
||||
getGCodeFileContentRouteHandler,
|
||||
getGCodeFileStatsRouteHandler,
|
||||
} from '../../services/production/gcodefiles.js';
|
||||
import { convertPropertiesString, getFilter } from '../../utils.js';
|
||||
|
||||
@ -32,6 +33,11 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newGCodeFileRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get gcodeFile stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getGCodeFileStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getGCodeFileRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
newJobRouteHandler,
|
||||
deleteJobRouteHandler,
|
||||
getJobStatsRouteHandler,
|
||||
getJobHistoryRouteHandler,
|
||||
} from '../../services/production/jobs.js';
|
||||
import { convertPropertiesString, getFilter } from '../../utils.js';
|
||||
|
||||
@ -31,6 +32,16 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newJobRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get job stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getJobStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get job history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getJobHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getJobRouteHandler(req, res);
|
||||
});
|
||||
@ -39,9 +50,4 @@ router.delete('/:id', isAuthenticated, async (req, res) => {
|
||||
deleteJobRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get printer stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getJobStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
newPrinterRouteHandler,
|
||||
getPrinterStatsRouteHandler,
|
||||
listPrintersByPropertiesRouteHandler,
|
||||
getPrinterHistoryRouteHandler,
|
||||
} from '../../services/production/printers.js';
|
||||
import { convertPropertiesString, getFilter } from '../../utils.js';
|
||||
|
||||
@ -32,6 +33,11 @@ router.post('/', isAuthenticated, (req, res) => {
|
||||
newPrinterRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get printer history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getPrinterHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get printer stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getPrinterStatsRouteHandler(req, res);
|
||||
|
||||
@ -6,6 +6,8 @@ import {
|
||||
listSubJobsRouteHandler,
|
||||
listSubJobsByPropertiesRouteHandler,
|
||||
getSubJobRouteHandler,
|
||||
getSubJobStatsRouteHandler,
|
||||
getSubJobHistoryRouteHandler,
|
||||
} from '../../services/production/subjobs.js';
|
||||
import { getFilter, convertPropertiesString } from '../../utils.js';
|
||||
|
||||
@ -24,6 +26,16 @@ router.get('/properties', isAuthenticated, (req, res) => {
|
||||
listSubJobsByPropertiesRouteHandler(req, res, properties, filter);
|
||||
});
|
||||
|
||||
// get sub job stats
|
||||
router.get('/stats', isAuthenticated, (req, res) => {
|
||||
getSubJobStatsRouteHandler(req, res);
|
||||
});
|
||||
|
||||
// get sub job history
|
||||
router.get('/history', isAuthenticated, (req, res) => {
|
||||
getSubJobHistoryRouteHandler(req, res);
|
||||
});
|
||||
|
||||
router.get('/:id', isAuthenticated, (req, res) => {
|
||||
getSubJobRouteHandler(req, res);
|
||||
});
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
const orderItemSchema = new Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
orderType: { type: String, required: true },
|
||||
order: { type: Schema.Types.ObjectId, refPath: 'orderType', required: true },
|
||||
itemType: { type: String, required: true },
|
||||
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true },
|
||||
syncAmount: { type: String, required: true, default: null },
|
||||
itemAmount: { type: Number, required: true },
|
||||
quantity: { type: Number, required: true },
|
||||
totalAmount: { type: Number, required: true },
|
||||
taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
|
||||
totalAmountWithTax: { type: Number, required: true },
|
||||
timestamp: { type: Date, default: Date.now },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
// Add virtual id getter
|
||||
orderItemSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
});
|
||||
|
||||
// Configure JSON serialization to include virtuals
|
||||
orderItemSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
// Create and export the model
|
||||
export const orderItemModel = mongoose.model('orderItem', orderItemSchema);
|
||||
@ -1,40 +0,0 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
const jobSchema = new mongoose.Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
state: {
|
||||
type: { required: true, type: String },
|
||||
progress: { type: Number, required: false },
|
||||
},
|
||||
printers: [{ type: Schema.Types.ObjectId, ref: 'printer', required: false }],
|
||||
createdAt: { required: true, type: Date },
|
||||
updatedAt: { required: true, type: Date },
|
||||
startedAt: { required: false, type: Date, default: null },
|
||||
finishedAt: { required: false, type: Date, default: null },
|
||||
gcodeFile: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'gcodeFile',
|
||||
required: false,
|
||||
},
|
||||
quantity: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 1,
|
||||
min: 1,
|
||||
},
|
||||
subJobs: [{ type: Schema.Types.ObjectId, ref: 'subJob', required: false }],
|
||||
notes: [{ type: Schema.Types.ObjectId, ref: 'note', required: false }],
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
jobSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
});
|
||||
|
||||
jobSchema.set('toJSON', { virtuals: true });
|
||||
|
||||
export const jobModel = mongoose.model('job', jobSchema);
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { filamentStockModel } from '../../schemas/inventory/filamentstock.schema.js';
|
||||
import { filamentStockModel } from '../../database/schemas/inventory/filamentstock.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -157,3 +159,25 @@ export const deleteFilamentStockRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getFilamentStockStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: filamentStockModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching filament stock stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Filament stock stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getFilamentStockHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: filamentStockModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching filament stock history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Filament stock history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { orderItemModel } from '../../schemas/inventory/orderitem.schema.js';
|
||||
import { orderItemModel } from '../../database/schemas/inventory/orderitem.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -45,11 +47,11 @@ export const listOrderItemsRouteHandler = async (
|
||||
},
|
||||
{
|
||||
path: 'item',
|
||||
populate: { path: 'costTaxRate' },
|
||||
populate: { path: 'costTaxRate', strictPopulate: false },
|
||||
},
|
||||
{
|
||||
path: 'item',
|
||||
populate: { path: 'priceTaxRate' },
|
||||
populate: { path: 'priceTaxRate', strictPopulate: false },
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -104,11 +106,13 @@ export const getOrderItemRouteHandler = async (req, res) => {
|
||||
},
|
||||
{
|
||||
path: 'item',
|
||||
populate: { path: 'costTaxRate' },
|
||||
populate: { path: 'costTaxRate', strictPopulate: false },
|
||||
strictPopulate: false,
|
||||
},
|
||||
{
|
||||
path: 'item',
|
||||
populate: { path: 'priceTaxRate' },
|
||||
populate: { path: 'priceTaxRate', strictPopulate: false },
|
||||
strictPopulate: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -128,9 +132,10 @@ export const editOrderItemRouteHandler = async (req, res) => {
|
||||
|
||||
const updateData = {
|
||||
updatedAt: new Date(),
|
||||
purchaseOrder: req.body.purchaseOrder,
|
||||
itemType: req.body.itemType,
|
||||
item: req.body.item,
|
||||
orderType: req.body.orderType,
|
||||
order: req.body.order,
|
||||
syncAmount: req.body.syncAmount,
|
||||
itemAmount: req.body.itemAmount,
|
||||
quantity: req.body.quantity,
|
||||
@ -161,6 +166,7 @@ export const newOrderItemRouteHandler = async (req, res) => {
|
||||
const newData = {
|
||||
updatedAt: new Date(),
|
||||
purchaseOrder: req.body.purchaseOrder,
|
||||
state: { type: 'draft' },
|
||||
itemType: req.body.itemType,
|
||||
item: req.body.item,
|
||||
orderType: req.body.orderType,
|
||||
@ -207,3 +213,25 @@ export const deleteOrderItemRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getOrderItemStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: orderItemModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching order item stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Order item stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getOrderItemHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: orderItemModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching order item history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Order item history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { partStockModel } from '../../schemas/inventory/partstock.schema.js';
|
||||
import { partStockModel } from '../../database/schemas/inventory/partstock.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -157,3 +159,25 @@ export const deletePartStockRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getPartStockStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: partStockModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching part stock stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Part stock stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getPartStockHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: partStockModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching part stock history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Part stock history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { purchaseOrderModel } from '../../schemas/inventory/purchaseorder.schema.js';
|
||||
import { purchaseOrderModel } from '../../database/schemas/inventory/purchaseorder.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -78,7 +80,7 @@ export const getPurchaseOrderRouteHandler = async (req, res) => {
|
||||
const result = await getObject({
|
||||
model: purchaseOrderModel,
|
||||
id,
|
||||
populate: ['vendor', 'items.item', 'items.taxRate'],
|
||||
populate: ['vendor'],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`Purchase Order not found with supplied id.`);
|
||||
@ -97,8 +99,6 @@ export const editPurchaseOrderRouteHandler = async (req, res) => {
|
||||
const updateData = {
|
||||
updatedAt: new Date(),
|
||||
vendor: req.body.vendor,
|
||||
items: req.body.items,
|
||||
cost: req.body.cost,
|
||||
};
|
||||
// Create audit log before updating
|
||||
const result = await editObject({
|
||||
@ -123,8 +123,6 @@ export const newPurchaseOrderRouteHandler = async (req, res) => {
|
||||
const newData = {
|
||||
updatedAt: new Date(),
|
||||
vendor: req.body.vendor,
|
||||
items: req.body.items,
|
||||
cost: req.body.cost,
|
||||
};
|
||||
const result = await newObject({
|
||||
model: purchaseOrderModel,
|
||||
@ -161,3 +159,25 @@ export const deletePurchaseOrderRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getPurchaseOrderStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: purchaseOrderModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching purchase order stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Purchase order stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getPurchaseOrderHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: purchaseOrderModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching purchase order history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Purchase order history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { shipmentModel } from '../../schemas/inventory/shipment.schema.js';
|
||||
import { shipmentModel } from '../../database/schemas/inventory/shipment.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -175,3 +177,25 @@ export const deleteShipmentRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getShipmentStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: shipmentModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching shipment stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Shipment stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getShipmentHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: shipmentModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching shipment history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Shipment history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { stockAuditModel } from '../../schemas/inventory/stockaudit.schema.js';
|
||||
import { stockAuditModel } from '../../database/schemas/inventory/stockaudit.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import { getAuditLogs } from '../../utils.js';
|
||||
import { getModelStats, getModelHistory } from '../../database/database.js';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
@ -168,3 +169,25 @@ export const deleteStockAuditRouteHandler = async (req, res) => {
|
||||
res.status(500).send({ error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
export const getStockAuditStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: stockAuditModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching stock audit stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Stock audit stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getStockAuditHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: stockAuditModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching stock audit history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Stock audit history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { stockEventModel } from '../../schemas/inventory/stockevent.schema.js';
|
||||
import { stockEventModel } from '../../database/schemas/inventory/stockevent.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -165,3 +167,25 @@ export const deleteStockEventRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getStockEventStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: stockEventModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching stock event stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Stock event stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getStockEventHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: stockEventModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching stock event history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Stock event history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { auditLogModel } from '../../schemas/management/auditlog.schema.js';
|
||||
import { auditLogModel } from '../../database/schemas/management/auditlog.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import { getModelStats, getModelHistory } from '../../database/database.js';
|
||||
|
||||
dotenv.config();
|
||||
const logger = log4js.getLogger('AuditLogs');
|
||||
@ -88,3 +89,25 @@ export const getAuditLogRouteHandler = async (req, res) => {
|
||||
res.status(500).send({ error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
export const getAuditLogStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: auditLogModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching audit log stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Audit log stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getAuditLogHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: auditLogModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching audit log history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Audit log history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { courierModel } from '../../schemas/management/courier.schema.js';
|
||||
import { courierModel } from '../../database/schemas/management/courier.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -162,3 +164,25 @@ export const deleteCourierRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getCourierStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: courierModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching courier stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Courier stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getCourierHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: courierModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching courier history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Courier history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { courierServiceModel } from '../../schemas/management/courierservice.schema.js';
|
||||
import { courierServiceModel } from '../../database/schemas/management/courierservice.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -165,3 +167,25 @@ export const deleteCourierServiceRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getCourierServiceStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: courierServiceModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching courier service stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Courier service stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getCourierServiceHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: courierServiceModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching courier service history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Courier service history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { documentJobModel } from '../../schemas/management/documentjob.schema.js';
|
||||
import { documentJobModel } from '../../database/schemas/management/documentjob.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -158,3 +160,25 @@ export const deleteDocumentJobRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getDocumentJobStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: documentJobModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching document job stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Document job stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getDocumentJobHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: documentJobModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching document job history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Document job history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { documentPrinterModel } from '../../schemas/management/documentprinter.schema.js';
|
||||
import { documentPrinterModel } from '../../database/schemas/management/documentprinter.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -167,3 +169,25 @@ export const deleteDocumentPrinterRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getDocumentPrinterStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: documentPrinterModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching document printer stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Document printer stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getDocumentPrinterHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: documentPrinterModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching document printer history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Document printer history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { documentSizeModel } from '../../schemas/management/documentsize.schema.js';
|
||||
import { documentSizeModel } from '../../database/schemas/management/documentsize.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -158,3 +160,25 @@ export const deleteDocumentSizeRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getDocumentSizeStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: documentSizeModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching document size stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Document size stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getDocumentSizeHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: documentSizeModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching document size history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Document size history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { documentTemplateModel } from '../../schemas/management/documenttemplate.schema.js';
|
||||
import { documentTemplateModel } from '../../database/schemas/management/documenttemplate.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -184,3 +186,25 @@ export const deleteDocumentTemplateRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getDocumentTemplateStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: documentTemplateModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching document template stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Document template stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getDocumentTemplateHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: documentTemplateModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching document template history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Document template history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv, { populate } from 'dotenv';
|
||||
import { filamentModel } from '../../schemas/management/filament.schema.js';
|
||||
import { filamentModel } from '../../database/schemas/management/filament.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -8,6 +8,8 @@ import {
|
||||
listObjectsByProperties,
|
||||
editObject,
|
||||
newObject,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
|
||||
dotenv.config();
|
||||
@ -34,7 +36,7 @@ export const listFilamentsRouteHandler = async (
|
||||
search,
|
||||
sort,
|
||||
order,
|
||||
populate: ['vendor'],
|
||||
populate: ['vendor', 'costTaxRate'],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -75,7 +77,7 @@ export const getFilamentRouteHandler = async (req, res) => {
|
||||
const result = await getObject({
|
||||
model: filamentModel,
|
||||
id,
|
||||
populate: 'vendor',
|
||||
populate: ['vendor', 'costTaxRate'],
|
||||
});
|
||||
if (result?.error) {
|
||||
logger.warn(`Filament not found with supplied id.`);
|
||||
@ -101,6 +103,8 @@ export const editFilamentRouteHandler = async (req, res) => {
|
||||
vendor: req.body.vendor,
|
||||
type: req.body.type,
|
||||
cost: req.body.cost,
|
||||
costTaxRate: req.body.costTaxRate,
|
||||
costWithTax: req.body.costWithTax,
|
||||
diameter: req.body.diameter,
|
||||
density: req.body.density,
|
||||
emptySpoolWeight: req.body.emptySpoolWeight,
|
||||
@ -135,6 +139,8 @@ export const newFilamentRouteHandler = async (req, res) => {
|
||||
vendor: req.body.vendor,
|
||||
type: req.body.type,
|
||||
cost: req.body.cost,
|
||||
costTaxRate: req.body.costTaxRate,
|
||||
costWithTax: req.body.costWithTax,
|
||||
diameter: req.body.diameter,
|
||||
density: req.body.density,
|
||||
emptySpoolWeight: req.body.emptySpoolWeight,
|
||||
@ -154,3 +160,25 @@ export const newFilamentRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getFilamentStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: filamentModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching filament stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Filament stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getFilamentHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: filamentModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching filament history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Filament history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { fileModel } from '../../schemas/management/file.schema.js';
|
||||
import { fileModel } from '../../database/schemas/management/file.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import multer from 'multer';
|
||||
import path from 'path';
|
||||
@ -13,6 +13,8 @@ import {
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
flushFile,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
import {
|
||||
uploadFile,
|
||||
@ -421,3 +423,25 @@ export const parseFileHandler = async (req, res) => {
|
||||
res.status(500).send({ error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
export const getFileStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: fileModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching file stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('File stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getFileHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: fileModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching file history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('File history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { hostModel } from '../../schemas/management/host.schema.js';
|
||||
import { hostModel } from '../../database/schemas/management/host.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -159,3 +161,25 @@ export const deleteHostRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getHostStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: hostModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching host stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Host stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getHostHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: hostModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching host history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Host history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { materialModel } from '../../schemas/management/material.schema.js';
|
||||
import { materialModel } from '../../database/schemas/management/material.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import { getModelStats, getModelHistory } from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
const logger = log4js.getLogger('Materials');
|
||||
@ -128,3 +129,25 @@ export const newMaterialRouteHandler = async (req, res) => {
|
||||
res.status(500).send({ error: updateError.message });
|
||||
}
|
||||
};
|
||||
|
||||
export const getMaterialStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: materialModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching material stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Material stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getMaterialHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: materialModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching material history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Material history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { noteTypeModel } from '../../schemas/management/notetype.schema.js';
|
||||
import { noteTypeModel } from '../../database/schemas/management/notetype.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -158,3 +160,25 @@ export const deleteNoteTypeRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getNoteTypeStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: noteTypeModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching note type stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Note type stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getNoteTypeHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: noteTypeModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching note type history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Note type history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { partModel } from '../../schemas/management/part.schema.js';
|
||||
import { partModel } from '../../database/schemas/management/part.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -53,7 +55,20 @@ export const listPartsByPropertiesRouteHandler = async (req, res, properties = '
|
||||
model: partModel,
|
||||
properties,
|
||||
filter,
|
||||
populate: ['vendor', 'priceTaxRate', 'costTaxRate'],
|
||||
populate: [
|
||||
{
|
||||
path: 'vendor',
|
||||
from: 'vendors',
|
||||
},
|
||||
{
|
||||
path: 'priceTaxRate',
|
||||
from: 'taxrates',
|
||||
},
|
||||
{
|
||||
path: 'costTaxRate',
|
||||
from: 'taxrates',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
@ -171,3 +186,25 @@ export const deletePartRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getPartStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: partModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching part stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Part stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getPartHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: partModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching part history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Part history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { productModel } from '../../schemas/management/product.schema.js';
|
||||
import { productModel } from '../../database/schemas/management/product.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -170,3 +172,25 @@ export const deleteProductRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getProductStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: productModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching product stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Product stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getProductHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: productModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching product history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Product history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { jobModel } from '../../schemas/production/job.schema.js';
|
||||
import { subJobModel } from '../../schemas/production/subjob.schema.js';
|
||||
import { jobModel } from '../../database/schemas/production/job.schema.js';
|
||||
import { subJobModel } from '../../database/schemas/production/subjob.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import { printerModel } from '../../schemas/production/printer.schema.js';
|
||||
import { filamentModel } from '../../schemas/management/filament.schema.js';
|
||||
import { gcodeFileModel } from '../../schemas/production/gcodefile.schema.js';
|
||||
import { partModel } from '../../schemas/management/part.schema.js';
|
||||
import { productModel } from '../../schemas/management/product.schema.js';
|
||||
import { vendorModel } from '../../schemas/management/vendor.schema.js';
|
||||
import { filamentStockModel } from '../../schemas/inventory/filamentstock.schema.js';
|
||||
import { stockEventModel } from '../../schemas/inventory/stockevent.schema.js';
|
||||
import { stockAuditModel } from '../../schemas/inventory/stockaudit.schema.js';
|
||||
import { partStockModel } from '../../schemas/inventory/partstock.schema.js';
|
||||
import { auditLogModel } from '../../schemas/management/auditlog.schema.js';
|
||||
import { userModel } from '../../schemas/management/user.schema.js';
|
||||
import { noteTypeModel } from '../../schemas/management/notetype.schema.js';
|
||||
import { noteModel } from '../../schemas/misc/note.schema.js';
|
||||
import { printerModel } from '../../database/schemas/production/printer.schema.js';
|
||||
import { filamentModel } from '../../database/schemas/management/filament.schema.js';
|
||||
import { gcodeFileModel } from '../../database/schemas/production/gcodefile.schema.js';
|
||||
import { partModel } from '../../database/schemas/management/part.schema.js';
|
||||
import { productModel } from '../../database/schemas/management/product.schema.js';
|
||||
import { vendorModel } from '../../database/schemas/management/vendor.schema.js';
|
||||
import { filamentStockModel } from '../../database/schemas/inventory/filamentstock.schema.js';
|
||||
import { stockEventModel } from '../../database/schemas/inventory/stockevent.schema.js';
|
||||
import { stockAuditModel } from '../../database/schemas/inventory/stockaudit.schema.js';
|
||||
import { partStockModel } from '../../database/schemas/inventory/partstock.schema.js';
|
||||
import { auditLogModel } from '../../database/schemas/management/auditlog.schema.js';
|
||||
import { userModel } from '../../database/schemas/management/user.schema.js';
|
||||
import { noteTypeModel } from '../../database/schemas/management/notetype.schema.js';
|
||||
import { noteModel } from '../../database/schemas/misc/note.schema.js';
|
||||
import mongoose from 'mongoose';
|
||||
dotenv.config();
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { taxRateModel } from '../../schemas/management/taxrates.schema.js';
|
||||
import { taxRateModel } from '../../database/schemas/management/taxrates.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -166,3 +168,25 @@ export const deleteTaxRateRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getTaxRateStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: taxRateModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching tax rate stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Tax rate stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getTaxRateHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: taxRateModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching tax rate history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Tax rate history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { taxRecordModel } from '../../schemas/management/taxrecord.schema.js';
|
||||
import { taxRecordModel } from '../../database/schemas/management/taxrecord.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -162,3 +164,25 @@ export const deleteTaxRecordRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getTaxRecordStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: taxRecordModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching tax record stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Tax record stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getTaxRecordHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: taxRecordModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching tax record history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Tax record history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { userModel } from '../../schemas/management/user.schema.js';
|
||||
import { userModel } from '../../database/schemas/management/user.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -7,6 +7,8 @@ import {
|
||||
listObjectsByProperties,
|
||||
getObject,
|
||||
editObject,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
|
||||
dotenv.config();
|
||||
@ -117,3 +119,25 @@ export const editUserRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getUserStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: userModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching user stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('User stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getUserHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: userModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching user history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('User history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { vendorModel } from '../../schemas/management/vendor.schema.js';
|
||||
import { vendorModel } from '../../database/schemas/management/vendor.schema.js';
|
||||
import log4js from 'log4js';
|
||||
import mongoose from 'mongoose';
|
||||
import {
|
||||
@ -9,6 +9,8 @@ import {
|
||||
editObject,
|
||||
newObject,
|
||||
listObjectsByProperties,
|
||||
getModelStats,
|
||||
getModelHistory,
|
||||
} from '../../database/database.js';
|
||||
dotenv.config();
|
||||
|
||||
@ -166,3 +168,25 @@ export const deleteVendorRouteHandler = async (req, res) => {
|
||||
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getVendorStatsRouteHandler = async (req, res) => {
|
||||
const result = await getModelStats({ model: vendorModel });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching vendor stats:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Vendor stats:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
export const getVendorHistoryRouteHandler = async (req, res) => {
|
||||
const from = req.query.from;
|
||||
const to = req.query.to;
|
||||
const result = await getModelHistory({ model: vendorModel, from, to });
|
||||
if (result?.error) {
|
||||
logger.error('Error fetching vendor history:', result.error);
|
||||
return res.status(result.code).send(result);
|
||||
}
|
||||
logger.trace('Vendor history:', result);
|
||||
res.send(result);
|
||||
};
|
||||
|
||||
@ -2,7 +2,7 @@ import dotenv from 'dotenv';
|
||||
import { keycloak } from '../../keycloak.js';
|
||||
import log4js from 'log4js';
|
||||
import axios from 'axios';
|
||||
import { userModel } from '../../schemas/management/user.schema.js';
|
||||
import { userModel } from '../../database/schemas/management/user.schema.js';
|
||||
import { readFileSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import NodeCache from 'node-cache';
|
||||
@ -32,16 +32,16 @@ const lookupUserByToken = async (token) => {
|
||||
// Check cache first
|
||||
const cachedUser = tokenUserCache.get(token);
|
||||
if (cachedUser) {
|
||||
logger.debug(`User found in token cache for token: ${token.substring(0, 20)}...`);
|
||||
logger.trace(`User found in token cache for token: ${token.substring(0, 20)}...`);
|
||||
return cachedUser;
|
||||
}
|
||||
|
||||
// If not in cache, decode token and lookup user
|
||||
logger.debug(`User not in token cache, decoding token: ${token.substring(0, 20)}...`);
|
||||
logger.trace(`User not in token cache, decoding token: ${token.substring(0, 20)}...`);
|
||||
const decodedToken = jwt.decode(token);
|
||||
|
||||
if (!decodedToken || !decodedToken.preferred_username) {
|
||||
logger.warn('Invalid token or missing preferred_username');
|
||||
logger.trace('Invalid token or missing preferred_username');
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ const lookupUserByToken = async (token) => {
|
||||
if (user) {
|
||||
// Store in cache using token as key
|
||||
tokenUserCache.set(token, user);
|
||||
logger.debug(`User stored in token cache for token: ${token.substring(0, 20)}...`);
|
||||
logger.trace(`User stored in token cache for token: ${token.substring(0, 20)}...`);
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user