Implement schema synchronization and enhance invoice handling
All checks were successful
farmcontrol/farmcontrol-api/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-api/pipeline/head This commit looks good
This commit introduces a new function, `syncModelsWithScheduler`, to synchronize database schemas with the farm control scheduler. It also adds scheduled properties and event handling for invoices, allowing for automatic state updates based on due dates. Additionally, minor refactoring is performed in the sales listings routes and services to improve code readability and maintainability. The changes enhance the application's data synchronization and invoice management capabilities.
This commit is contained in:
parent
9defa3e30b
commit
cb63d8dabb
22
fcdev.js
22
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 };
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -52,7 +52,7 @@ const propertiesAllowedFilters = [
|
||||
'condition',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
];
|
||||
];
|
||||
import {
|
||||
listListingsRouteHandler,
|
||||
getListingRouteHandler,
|
||||
@ -66,17 +66,30 @@ 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);
|
||||
listListingsRouteHandler(
|
||||
req,
|
||||
res,
|
||||
page,
|
||||
limit,
|
||||
property,
|
||||
filter,
|
||||
search,
|
||||
getSort(sortProperty, listAllowedSorters),
|
||||
sortOrder
|
||||
);
|
||||
});
|
||||
|
||||
router.get('/properties', checkPermissions('listing', 'list'), isAuthenticated, async (req, res) => {
|
||||
router.get(
|
||||
'/properties',
|
||||
isAuthenticated,
|
||||
checkPermissions('listing', 'list'),
|
||||
async (req, res) => {
|
||||
let properties = convertPropertiesString(req.query.properties);
|
||||
const filter = await getFilter(req.query, propertiesAllowedFilters, false);
|
||||
var masterFilter = {};
|
||||
@ -84,26 +97,18 @@ router.get('/properties', checkPermissions('listing', 'list'), isAuthenticated,
|
||||
masterFilter = JSON.parse(req.query.masterFilter);
|
||||
}
|
||||
listListingsByPropertiesRouteHandler(req, res, properties, filter, masterFilter);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/values',
|
||||
checkPermissions('listing', 'list'),
|
||||
isAuthenticated,
|
||||
async (req, res) => {
|
||||
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
|
||||
);
|
||||
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) => {
|
||||
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) => {
|
||||
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) => {
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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 });
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user