Add rollup configurations and statistics methods to finance and inventory schemas
All checks were successful
farmcontrol/farmcontrol-api/pipeline/head This commit looks good

This commit enhances the `invoice`, `taxrecord`, `orderitem`, `purchaseorder`, `shipment`, and `salesorder` schemas by introducing new rollup configurations for various states and values. It adds methods for aggregating statistics and historical data using `aggregateRollups` and `aggregateRollupsHistory`, improving data analysis capabilities across financial and inventory records. The new rollups include counts and sums for different transaction types and states, facilitating better reporting and insights into the application's financial and inventory management.
This commit is contained in:
Tom Butcher 2026-08-30 14:56:48 +01:00
parent 5e4830b036
commit 6393ed5e3e
6 changed files with 150 additions and 3 deletions

View File

@ -92,12 +92,18 @@ const rollupConfigs = [
{ {
name: 'paid', name: 'paid',
filter: { 'state.type': 'paid' }, filter: { 'state.type': 'paid' },
rollups: [{ name: 'paidCount', property: 'state.type', operation: 'count' }], rollups: [
{ name: 'paidCount', property: 'state.type', operation: 'count' },
{ name: 'paidGrandTotalAmount', property: 'grandTotalAmount', operation: 'sum' },
],
}, },
{ {
name: 'overdue', name: 'overdue',
filter: { 'state.type': 'overdue' }, filter: { 'state.type': 'overdue' },
rollups: [{ name: 'overdueCount', property: 'state.type', operation: 'count' }], rollups: [
{ name: 'overdueCount', property: 'state.type', operation: 'count' },
{ name: 'overdueGrandTotalAmount', property: 'grandTotalAmount', operation: 'sum' },
],
}, },
{ {
name: 'cancelled', name: 'cancelled',

View File

@ -1,5 +1,6 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
const { Schema } = mongoose; const { Schema } = mongoose;
const taxRecordSchema = new Schema( const taxRecordSchema = new Schema(
@ -21,6 +22,44 @@ const taxRecordSchema = new Schema(
taxRecordSchema.index({ transactionType: 'text' }); taxRecordSchema.index({ transactionType: 'text' });
const rollupConfigs = [
{
name: 'total',
filter: {},
rollups: [
{ name: 'count', property: 'amount', operation: 'count' },
{ name: 'amount', property: 'amount', operation: 'sum' },
{ name: 'taxAmount', property: 'taxAmount', operation: 'sum' },
],
},
{
name: 'salesOrder',
filter: { transactionType: 'salesOrder' },
rollups: [{ name: 'taxAmount', property: 'taxAmount', operation: 'sum' }],
},
{
name: 'purchaseOrder',
filter: { transactionType: 'purchaseOrder' },
rollups: [{ name: 'taxAmount', property: 'taxAmount', operation: 'sum' }],
},
];
taxRecordSchema.statics.stats = async function () {
return aggregateRollups({
model: this,
rollupConfigs,
});
};
taxRecordSchema.statics.history = async function (from, to) {
return aggregateRollupsHistory({
model: this,
startDate: from,
endDate: to,
rollupConfigs,
});
};
taxRecordSchema.virtual('id').get(function () { taxRecordSchema.virtual('id').get(function () {
return this._id; return this._id;
}); });

View File

@ -76,6 +76,16 @@ orderItemSchema.index({ name: 'text', itemType: 'text', orderType: 'text' });
orderItemSchema.index({ order: 1, externalReference: 1 }, { unique: true, sparse: true }); orderItemSchema.index({ order: 1, externalReference: 1 }, { unique: true, sparse: true });
const rollupConfigs = [ const rollupConfigs = [
{
name: 'draft',
filter: { 'state.type': 'draft' },
rollups: [{ name: 'draft', property: 'state.type', operation: 'count' }],
},
{
name: 'ordered',
filter: { 'state.type': 'ordered' },
rollups: [{ name: 'ordered', property: 'state.type', operation: 'count' }],
},
{ {
name: 'shipped', name: 'shipped',
filter: { 'state.type': 'shipped' }, filter: { 'state.type': 'shipped' },
@ -86,6 +96,16 @@ const rollupConfigs = [
filter: { 'state.type': 'received' }, filter: { 'state.type': 'received' },
rollups: [{ name: 'received', property: 'state.type', operation: 'count' }], rollups: [{ name: 'received', property: 'state.type', operation: 'count' }],
}, },
{
name: 'shippedValue',
filter: { 'state.type': 'shipped' },
rollups: [{ name: 'totalAmountWithTax', property: 'totalAmountWithTax', operation: 'sum' }],
},
{
name: 'receivedValue',
filter: { 'state.type': 'received' },
rollups: [{ name: 'totalAmountWithTax', property: 'totalAmountWithTax', operation: 'sum' }],
},
]; ];
orderItemSchema.statics.stats = async function () { orderItemSchema.statics.stats = async function () {

View File

@ -73,6 +73,20 @@ const rollupConfigs = [
filter: { 'state.type': 'completed' }, filter: { 'state.type': 'completed' },
rollups: [{ name: 'completed', property: 'state.type', operation: 'count' }], rollups: [{ name: 'completed', property: 'state.type', operation: 'count' }],
}, },
{
name: 'awaitingReceiptValue',
filter: {
'state.type': {
$in: ['sent', 'acknowledged', 'partiallyShipped', 'shipped', 'partiallyReceived'],
},
},
rollups: [{ name: 'grandTotalAmount', property: 'grandTotalAmount', operation: 'sum' }],
},
{
name: 'receivedValue',
filter: { 'state.type': { $in: ['received', 'completed'] } },
rollups: [{ name: 'grandTotalAmount', property: 'grandTotalAmount', operation: 'sum' }],
},
]; ];
purchaseOrderSchema.statics.stats = async function () { purchaseOrderSchema.statics.stats = async function () {

View File

@ -4,7 +4,12 @@ const { Schema } = mongoose;
import { purchaseOrderModel } from './purchaseorder.schema.js'; import { purchaseOrderModel } from './purchaseorder.schema.js';
import { salesOrderModel } from '../sales/salesorder.schema.js'; import { salesOrderModel } from '../sales/salesorder.schema.js';
import { taxRateModel } from '../management/taxrate.schema.js'; import { taxRateModel } from '../management/taxrate.schema.js';
import { aggregateRollups, editObject, getObject } from '../../database.js'; import {
aggregateRollups,
aggregateRollupsHistory,
editObject,
getObject,
} from '../../database.js';
const shipmentSchema = new Schema( const shipmentSchema = new Schema(
{ {
@ -38,6 +43,55 @@ const shipmentSchema = new Schema(
shipmentSchema.index({ trackingNumber: 'text', orderType: 'text' }); shipmentSchema.index({ trackingNumber: 'text', orderType: 'text' });
shipmentSchema.index({ order: 1, externalReference: 1 }, { unique: true, sparse: true }); shipmentSchema.index({ order: 1, externalReference: 1 }, { unique: true, sparse: true });
const rollupConfigs = [
{
name: 'draft',
filter: { 'state.type': 'draft' },
rollups: [{ name: 'draft', property: 'state.type', operation: 'count' }],
},
{
name: 'planned',
filter: { 'state.type': 'planned' },
rollups: [{ name: 'planned', property: 'state.type', operation: 'count' }],
},
{
name: 'shipped',
filter: { 'state.type': 'shipped' },
rollups: [{ name: 'shipped', property: 'state.type', operation: 'count' }],
},
{
name: 'delivered',
filter: { 'state.type': 'delivered' },
rollups: [{ name: 'delivered', property: 'state.type', operation: 'count' }],
},
{
name: 'cancelled',
filter: { 'state.type': 'cancelled' },
rollups: [{ name: 'cancelled', property: 'state.type', operation: 'count' }],
},
{
name: 'inTransitValue',
filter: { 'state.type': 'shipped' },
rollups: [{ name: 'amountWithTax', property: 'amountWithTax', operation: 'sum' }],
},
];
shipmentSchema.statics.stats = async function () {
return aggregateRollups({
model: this,
rollupConfigs,
});
};
shipmentSchema.statics.history = async function (from, to) {
return aggregateRollupsHistory({
model: this,
startDate: from,
endDate: to,
rollupConfigs,
});
};
shipmentSchema.statics.recalculate = async function (shipment, user) { shipmentSchema.statics.recalculate = async function (shipment, user) {
if (shipment.orderType !== 'purchaseOrder' && shipment.orderType !== 'salesOrder') { if (shipment.orderType !== 'purchaseOrder' && shipment.orderType !== 'salesOrder') {
return; return;

View File

@ -76,6 +76,20 @@ const rollupConfigs = [
filter: { 'state.type': 'completed' }, filter: { 'state.type': 'completed' },
rollups: [{ name: 'completed', property: 'state.type', operation: 'count' }], rollups: [{ name: 'completed', property: 'state.type', operation: 'count' }],
}, },
{
name: 'pipelineValue',
filter: {
'state.type': {
$in: ['sent', 'confirmed', 'partiallyShipped', 'shipped', 'partiallyDelivered'],
},
},
rollups: [{ name: 'grandTotalAmount', property: 'grandTotalAmount', operation: 'sum' }],
},
{
name: 'completedValue',
filter: { 'state.type': { $in: ['delivered', 'completed'] } },
rollups: [{ name: 'grandTotalAmount', property: 'grandTotalAmount', operation: 'sum' }],
},
]; ];
salesOrderSchema.statics.stats = async function () { salesOrderSchema.statics.stats = async function () {