Some checks failed
farmcontrol/farmcontrol-api/pipeline/head There was a failure building this commit
This commit modifies the `stockTransfer` schema by removing the `toStockLocation` field and introducing `fromLocation` and `toLocation` fields, ensuring better clarity in stock transfer operations. The routes and services are updated to reflect these changes, including adjustments in the `executePostedLine` function to validate stock locations. Additionally, the allowed filters and sorters in the stock transfer routes are refined, enhancing the overall functionality and maintainability of the inventory management system.
125 lines
4.5 KiB
JavaScript
125 lines
4.5 KiB
JavaScript
/**
|
|
* Shared export utilities for OData, CSV, and Excel.
|
|
* Centralizes filter fields, order-by parsing, and row flattening.
|
|
*/
|
|
|
|
/** Allowed filter fields per object type for OData/CSV/Excel exports */
|
|
export const EXPORT_FILTER_BY_TYPE = {
|
|
note: ['parent._id', 'noteType', 'user'],
|
|
notification: ['user'],
|
|
userNotifier: ['user', 'object', 'objectType'],
|
|
printer: ['host'],
|
|
job: ['printer', 'gcodeFile'],
|
|
subJob: ['job'],
|
|
filamentStock: ['filament', 'filament._id', 'filamentSku'],
|
|
gcodeFile: ['filament', 'filament._id', 'filamentSku'],
|
|
filament: ['material', 'material._id', 'vendor', 'name', 'diameter', 'cost'],
|
|
filamentSku: ['filament', 'filament.vendor', 'costTaxRate'],
|
|
material: ['name', 'tags'],
|
|
partStock: ['part', 'partSku'],
|
|
partSku: ['part', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
|
productCategory: ['name', 'marketplaces.marketplace'],
|
|
product: ['productCategory', 'productCategory._id', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
|
productStock: ['productSku'],
|
|
productSku: ['product', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
|
purchaseOrder: [
|
|
'vendor',
|
|
'totalAmount',
|
|
'totalAmountWithTax',
|
|
'totalTaxAmount',
|
|
'shippingAmount',
|
|
'shippingAmountWithTax',
|
|
'grandTotalAmount',
|
|
],
|
|
orderItem: ['order._id', 'orderType', 'item._id', 'itemType', 'sku._id', 'shipment._id'],
|
|
shipment: ['order._id', 'orderType', 'courierService._id'],
|
|
stockEvent: ['parent._id', 'parentType', 'owner._id', 'ownerType'],
|
|
stockLocation: ['name', 'address'],
|
|
stockTransfer: ['state.type', 'postedAt'],
|
|
stockAudit: ['auditLevel._id', 'stockLocation._id', 'state.type', 'postedAt'],
|
|
stockAuditLevel: ['name', 'tags'],
|
|
documentJob: ['documentTemplate', 'documentPrinter', 'object._id', 'objectType'],
|
|
documentTemplate: ['parent._id', 'documentSize._id'],
|
|
salesOrder: ['client'],
|
|
invoice: ['to._id', 'from._id', 'order._id', 'orderType'],
|
|
auditLog: ['parent._id', 'parentType', 'owner._id', 'ownerType'],
|
|
appPassword: ['name', 'user', 'active'],
|
|
};
|
|
|
|
/**
|
|
* Get allowed filter fields for a given object type.
|
|
* @param {string} objectType - Model type (e.g. 'filament', 'material')
|
|
* @returns {string[]} Allowed filter field names
|
|
*/
|
|
export function getModelFilterFields(objectType) {
|
|
const base = ['_id'];
|
|
const extra = EXPORT_FILTER_BY_TYPE[objectType] || [];
|
|
return [...base, ...extra];
|
|
}
|
|
|
|
/**
|
|
* Parse OData $orderby or orderby string into sort and order.
|
|
* Supports "field asc", "field desc", or just "field" (defaults asc).
|
|
* @param {string} [orderby] - Orderby string (e.g. "createdAt desc")
|
|
* @returns {{ sort: string, order: 'ascend'|'descend' }}
|
|
*/
|
|
export function parseOrderBy(orderby) {
|
|
if (!orderby || typeof orderby !== 'string') {
|
|
return { sort: 'createdAt', order: 'ascend' };
|
|
}
|
|
const trimmed = orderby.trim();
|
|
const parts = trimmed.split(/\s+/);
|
|
const sort = parts[0] || 'createdAt';
|
|
const dir = (parts[1] || 'asc').toLowerCase();
|
|
const order = dir === 'desc' ? 'descend' : 'ascend';
|
|
return { sort, order };
|
|
}
|
|
|
|
/**
|
|
* Flatten nested objects for export display.
|
|
* Objects become "key.subkey: value"; arrays become comma-separated strings.
|
|
* @param {*} obj - Value to flatten
|
|
* @param {string} [prefix=''] - Key prefix for nested values
|
|
* @returns {Object} Flat key-value object
|
|
*/
|
|
export function flattenForExport(obj, prefix = '') {
|
|
if (obj === null || obj === undefined) return {};
|
|
if (typeof obj !== 'object') return { [prefix]: obj };
|
|
if (obj instanceof Date) return { [prefix]: obj };
|
|
if (Array.isArray(obj)) {
|
|
const str = obj
|
|
.map((v) => (v && typeof v === 'object' && !(v instanceof Date) ? JSON.stringify(v) : v))
|
|
.join(', ');
|
|
return { [prefix]: str };
|
|
}
|
|
const result = {};
|
|
for (const [k, v] of Object.entries(obj)) {
|
|
const key = prefix ? `${prefix}.${k}` : k;
|
|
if (v !== null && typeof v === 'object' && !(v instanceof Date) && !Array.isArray(v)) {
|
|
Object.assign(result, flattenForExport(v, key));
|
|
} else {
|
|
result[key] = v;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Convert a row (e.g. OData value item) to flat key-value for CSV/Excel.
|
|
* Nested objects are flattened; @odata.* keys are skipped.
|
|
* @param {Object} row - Row object
|
|
* @returns {Object} Flat key-value object
|
|
*/
|
|
export function rowToFlat(row) {
|
|
const flat = {};
|
|
for (const [key, val] of Object.entries(row)) {
|
|
if (key.startsWith('@')) continue;
|
|
if (val !== null && typeof val === 'object' && !(val instanceof Date) && !Array.isArray(val)) {
|
|
Object.assign(flat, flattenForExport(val, key));
|
|
} else {
|
|
flat[key] = val;
|
|
}
|
|
}
|
|
return flat;
|
|
}
|