113 lines
4.0 KiB
JavaScript
113 lines
4.0 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: ['filamentSku'],
|
|
filament: ['material', 'material._id', 'name', 'diameter', 'cost'],
|
|
filamentSku: ['filament', 'vendor', 'costTaxRate'],
|
|
material: ['name', 'tags'],
|
|
partStock: ['partSku'],
|
|
partSku: ['part', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
|
productStock: ['productSku'],
|
|
productSku: ['product', 'vendor', 'priceTaxRate', 'costTaxRate'],
|
|
purchaseOrder: ['vendor'],
|
|
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'],
|
|
stockTransfer: ['state.type', 'postedAt'],
|
|
stockAudit: ['filamentStock._id', 'partStock._id'],
|
|
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;
|
|
}
|