diff --git a/fcdev.js b/fcdev.js index bddf84b..f74408f 100644 --- a/fcdev.js +++ b/fcdev.js @@ -25,6 +25,25 @@ async function syncModelsWithWS() { } } +async function syncModelsWithScheduler() { + const sourceDir = path.resolve(__dirname, 'src/database/schemas'); + const targetDir = path.resolve(__dirname, '../farmcontrol-scheduler/src/database/schemas'); + + console.log(`Syncing schemas from ${sourceDir} to ${targetDir}...`); + + const stats = { copied: 0, added: 0, skipped: 0 }; + + try { + await syncDirectory(sourceDir, targetDir, sourceDir, stats); + console.log( + `✅ Schema sync completed successfully! (${stats.added} added, ${stats.copied} updated, ${stats.skipped} unchanged)` + ); + } catch (error) { + console.error('❌ Error syncing schemas:', error); + process.exit(1); + } +} + function fileHasChanges(oldContent, newContent) { return diffLines(oldContent, newContent).some((part) => part.added || part.removed); } @@ -77,5 +96,6 @@ async function syncDirectory(source, target, rootSource, stats) { // Run the sync function when executed directly syncModelsWithWS(); +syncModelsWithScheduler(); -export { syncModelsWithWS }; +export { syncModelsWithWS, syncModelsWithScheduler }; diff --git a/src/database/schemas/finance/invoice.schema.js b/src/database/schemas/finance/invoice.schema.js index 954d09a..c09bbb7 100644 --- a/src/database/schemas/finance/invoice.schema.js +++ b/src/database/schemas/finance/invoice.schema.js @@ -1,7 +1,12 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; const { Schema } = mongoose; -import { aggregateRollups, aggregateRollupsHistory, editObject, getObject } from '../../database.js'; +import { + aggregateRollups, + aggregateRollupsHistory, + editObject, + getObject, +} from '../../database.js'; import { taxRateModel } from '../management/taxrate.schema.js'; import { amountWithTax, resolveTaxRate } from '../../tax.js'; @@ -136,6 +141,33 @@ invoiceSchema.statics.history = async function (from, to) { return results; }; +invoiceSchema.statics.scheduledProperties = [ + { + name: 'dueAt', + filter: { state: 'due|sent|acknowledged' }, + type: 'dateTime', + }, +]; + +invoiceSchema.statics.onSchedulerEvent = async function (invoice, property) { + const invoiceId = invoice._id || invoice; + if (!invoiceId) { + return; + } + + if (property === 'dueAt' && invoice.dueAt && invoice.dueAt < new Date()) { + await editObject({ + model: this, + id: invoiceId, + updateData: { + state: { type: 'overdue' }, + }, + user: 'system', + recalculate: false, + }); + } +}; + invoiceSchema.statics.recalculate = async function (invoice, user) { const invoiceId = invoice._id || invoice; if (!invoiceId) { diff --git a/src/routes/sales/listings.js b/src/routes/sales/listings.js index 766edd7..d0a67cf 100644 --- a/src/routes/sales/listings.js +++ b/src/routes/sales/listings.js @@ -38,21 +38,21 @@ const listAllowedSorters = [ '_id', ]; const propertiesAllowedFilters = [ - 'product', - 'vendor', - 'stockLocation', - 'stockQuantity', - 'marketplace', - 'courierServices', - 'fulfillmentPolicy', - 'paymentPolicy', - 'returnPolicy', - 'state', - 'state.type', - 'condition', - 'createdAt', - 'updatedAt', - ]; + 'product', + 'vendor', + 'stockLocation', + 'stockQuantity', + 'marketplace', + 'courierServices', + 'fulfillmentPolicy', + 'paymentPolicy', + 'returnPolicy', + 'state', + 'state.type', + 'condition', + 'createdAt', + 'updatedAt', +]; import { listListingsRouteHandler, getListingRouteHandler, @@ -66,44 +66,49 @@ import { unpublishListingRouteHandler, searchListingsRouteHandler, getListingPropertyValuesRouteHandler, - - getListingNeighborsRouteHandler + getListingNeighborsRouteHandler, } from '../../services/sales/listings.js'; router.get('/', isAuthenticated, checkPermissions('listing', 'list'), async (req, res) => { const { page, limit, property, search, sortProperty, sortOrder } = req.query; - const filter = await getFilter(req.query, listAllowedFilters); - listListingsRouteHandler(req, res, page, limit, property, filter, search, getSort(sortProperty, listAllowedSorters), sortOrder); -}); - -router.get('/properties', checkPermissions('listing', 'list'), isAuthenticated, async (req, res) => { - let properties = convertPropertiesString(req.query.properties); - const filter = await getFilter(req.query, propertiesAllowedFilters, false); - var masterFilter = {}; - if (req.query.masterFilter) { - masterFilter = JSON.parse(req.query.masterFilter); - } - listListingsByPropertiesRouteHandler(req, res, properties, filter, masterFilter); + const filter = await getFilter(req.query, listAllowedFilters); + listListingsRouteHandler( + req, + res, + page, + limit, + property, + filter, + search, + getSort(sortProperty, listAllowedSorters), + sortOrder + ); }); router.get( - '/values', - checkPermissions('listing', 'list'), + '/properties', isAuthenticated, + checkPermissions('listing', 'list'), async (req, res) => { - const { property } = req.query; - const filter = await getFilter(req.query, listAllowedFilters, true); + let properties = convertPropertiesString(req.query.properties); + const filter = await getFilter(req.query, propertiesAllowedFilters, false); var masterFilter = {}; if (req.query.masterFilter) { - masterFilter = await getFilter( - JSON.parse(req.query.masterFilter), - listAllowedFilters, - true - ); + masterFilter = JSON.parse(req.query.masterFilter); } - getListingPropertyValuesRouteHandler(req, res, property, filter, masterFilter); + listListingsByPropertiesRouteHandler(req, res, properties, filter, masterFilter); } ); + +router.get('/values', checkPermissions('listing', 'list'), isAuthenticated, async (req, res) => { + const { property } = req.query; + const filter = await getFilter(req.query, listAllowedFilters, true); + var masterFilter = {}; + if (req.query.masterFilter) { + masterFilter = await getFilter(JSON.parse(req.query.masterFilter), listAllowedFilters, true); + } + getListingPropertyValuesRouteHandler(req, res, property, filter, masterFilter); +}); router.get('/search', checkPermissions('listing', 'list'), isAuthenticated, async (req, res) => { const { search } = req.query; searchListingsRouteHandler(req, res, search); @@ -121,18 +126,37 @@ router.get('/history', isAuthenticated, async (req, res) => { getListingHistoryRouteHandler(req, res); }); -router.post('/:id/publish', isAuthenticated, checkPermissions('listing', 'publish'), async (req, res) => { - publishListingRouteHandler(req, res); -}); +router.post( + '/:id/publish', + isAuthenticated, + checkPermissions('listing', 'publish'), + async (req, res) => { + publishListingRouteHandler(req, res); + } +); -router.post('/:id/unpublish', isAuthenticated, checkPermissions('listing', 'unpublish'), async (req, res) => { - unpublishListingRouteHandler(req, res); -}); +router.post( + '/:id/unpublish', + isAuthenticated, + checkPermissions('listing', 'unpublish'), + async (req, res) => { + unpublishListingRouteHandler(req, res); + } +); router.get('/neighbors', isAuthenticated, async (req, res) => { const { property, search, sortProperty, sortOrder, id } = req.query; const filter = await getFilter(req.query, listAllowedFilters); - getListingNeighborsRouteHandler(req, res, property, filter, search, getSort(sortProperty, listAllowedSorters), sortOrder, id); + getListingNeighborsRouteHandler( + req, + res, + property, + filter, + search, + getSort(sortProperty, listAllowedSorters), + sortOrder, + id + ); }); router.get('/:id', isAuthenticated, checkPermissions('listing', 'info'), async (req, res) => { diff --git a/src/services/finance/invoices.js b/src/services/finance/invoices.js index 2a650f6..0ba7f40 100644 --- a/src/services/finance/invoices.js +++ b/src/services/finance/invoices.js @@ -159,7 +159,7 @@ export const editInvoiceRouteHandler = async (req, res) => { client: req.body.client, invoiceType: req.body.invoiceType, invoiceDate: req.body.invoiceDate, - dueAt: req.body.dueDate, + dueAt: req.body.dueAt, issuedAt: req.body.issuedAt, orderType: req.body.orderType, order: req.body.order, @@ -613,4 +613,3 @@ export const getInvoiceNeighborsRouteHandler = async ( logger.debug(`Retrieved invoice neighbors for ID: ${id}`); res.send(result); }; - diff --git a/src/services/sales/listings.js b/src/services/sales/listings.js index 1418765..1079c0c 100644 --- a/src/services/sales/listings.js +++ b/src/services/sales/listings.js @@ -58,6 +58,8 @@ const LISTING_POPULATE = [ }, ]; +const LISTING_PROPERTIES_POPULATE = ['marketplace', 'vendor', 'stockLocation', 'product']; + function pushToMarketplace( marketplaceId, listingData, @@ -131,7 +133,7 @@ export const listListingsByPropertiesRouteHandler = async ( properties, filter, masterFilter, - populate: LISTING_POPULATE, + populate: LISTING_PROPERTIES_POPULATE, }); if (result?.error) { @@ -393,10 +395,7 @@ export const publishListingRouteHandler = async (req, res) => { }); } - const listing = await listingModel - .findById(id) - .populate(LISTING_POPULATE) - .lean(); + const listing = await listingModel.findById(id).populate(LISTING_POPULATE).lean(); if (!listing) { return res.status(404).send({ error: 'Listing not found.', code: 404 }); }