import dotenv from 'dotenv'; import { productModel } from '../../schemas/management/product.schema.js'; import { partModel } from '../../schemas/management/part.schema.js'; import log4js from 'log4js'; import mongoose from 'mongoose'; import { newAuditLog } from '../../utils.js'; import { auditLogModel } from '../../schemas/management/auditlog.schema.js'; dotenv.config(); const logger = log4js.getLogger('Products'); logger.level = process.env.LOG_LEVEL; export const listProductsRouteHandler = async ( req, res, page = 1, limit = 25, property = '', filter = {} ) => { try { // Calculate the skip value based on the page number and limit const skip = (page - 1) * limit; let product; let aggregateCommand = []; if (filter != {}) { // use filtering if present aggregateCommand.push({ $match: filter }); } if (property != '') { // Match documents where the specified property is either null, undefined, empty string, empty array or empty object aggregateCommand.push({ $match: { $or: [ { [property]: null }, { [property]: '' }, { [property]: [] }, { [property]: {} }, { [property]: { $exists: false } }, ], }, }); aggregateCommand.push({ $project: { _id: 1, [property]: 1 } }); } else { aggregateCommand.push({ $project: { image: 0, url: 0 } }); } aggregateCommand.push({ $skip: skip }); aggregateCommand.push({ $limit: Number(limit) }); console.log(aggregateCommand); product = await productModel.aggregate(aggregateCommand); logger.trace(`List of products (Page ${page}, Limit ${limit}, Property ${property}):`, product); res.send(product); } catch (error) { logger.error('Error listing products:', error); res.status(500).send({ error: error }); } }; export const getProductRouteHandler = async (req, res) => { try { // Get ID from params const id = new mongoose.Types.ObjectId(req.params.id); // Fetch the product with the given remote address const product = await productModel .findOne({ _id: id, }) .populate('vendor') .populate('parts'); if (!product) { logger.warn(`Product not found with supplied id.`); return res.status(404).send({ error: 'Print job not found.' }); } logger.trace(`Product with ID: ${id}:`, product); const auditLogs = await auditLogModel .find({ target: id, }) .populate('owner'); res.send({ ...product._doc, auditLogs: auditLogs }); } catch (error) { logger.error('Error fetching Product:', error); res.status(500).send({ error: error.message }); } }; export const editProductRouteHandler = async (req, res) => { // Get ID from params const id = new mongoose.Types.ObjectId(req.params.id); var product = null; try { // Fetch the product with the given remote address product = await productModel.findOne({ _id: id }); if (!product) { // Error handling logger.warn(`Product not found with supplied id.`); return res.status(404).send({ error: 'Print job not found.' }); } logger.trace(`Product with ID: ${id}:`, product); } catch (fetchError) { logger.error('Error fetching product:', fetchError); res.status(500).send({ error: fetchError.message }); } try { const updateData = { updatedAt: new Date(), name: req.body?.name, vendor: req.body?.vendor?.id, tags: req.body?.tags, version: req.body?.version, parts: req.body?.parts, margin: req.body.margin, price: req.body.price, marginOrPrice: req.body.marginOrPrice, }; // Create audit log before updating await newAuditLog(product.toObject(), updateData, id, 'Product', req.user._id, 'User'); const result = await productModel.updateOne({ _id: id }, { $set: updateData }); if (result.nModified === 0) { logger.error('No Product updated.'); res.status(500).send({ error: 'No products updated.' }); } } catch (updateError) { logger.error('Error updating product:', updateError); res.status(500).send({ error: updateError.message }); } res.send('OK'); }; export const newProductRouteHandler = async (req, res) => { try { const newProduct = { createdAt: new Date(), updatedAt: new Date(), name: req.body.name, vendor: req.body.vendor.id, parts: partIds, margin: req.body.margin, price: req.body.price, marginOrPrice: req.body.marginOrPrice, }; const newProductResult = await productModel.create(newProduct); if (newProductResult.nCreated === 0) { logger.error('No product created.'); res.status(500).send({ error: 'No product created.' }); } // Create audit log for new product await newAuditLog({}, newProduct, newProductResult._id, 'Product', req.user._id, 'User'); const parts = req.body.parts || []; const productId = newProductResult._id; var partIds = []; for (const part of parts) { const newPart = { createdAt: new Date(), updatedAt: new Date(), name: part.name, product: productId, }; const newPartResult = await partModel.create(newPart); if (newPartResult.nCreated === 0) { logger.error('No parts created.'); res.status(500).send({ error: 'No parts created.' }); } partIds.push(newPartResult._id); // Create audit log for each new part await newAuditLog({}, newPart, newPartResult._id, 'Part', req.user._id, 'User'); } const editProductResult = await productModel.updateOne( { _id: productId }, { $set: { parts: partIds } } ); if (editProductResult.nModified === 0) { logger.error('No product updated.'); res.status(500).send({ error: 'No products updated.' }); } res.status(200).send({ ...newProductResult, parts: partIds }); } catch (updateError) { logger.error('Error updating product:', updateError); res.status(500).send({ error: updateError.message }); } };