Add reporting features with new report engine and bookmark management
- Introduced a comprehensive report engine for generating and managing reports, including sales and logistics reports. - Added new API endpoints for retrieving report configurations, data, and metadata, ensuring secure access with privilege checks. - Implemented a report bookmarks system to allow users to save and manage report filters and configurations. - Created database migrations for the `report_bookmarks` table and updated the schema to support new report functionalities. - Developed services and controllers for handling report queries and bookmarks, including CRUD operations for bookmarks. - Enhanced API documentation to reflect the new reporting features and endpoints. - Added unit and integration tests to validate the new functionalities and ensure data integrity across report operations.
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import { DateTime } from '../../../../common/value-objects/date-time/date-time';
|
||||
import { Decimal } from '../../../../common/value-objects/decimal/decimal';
|
||||
import { DATA_FORMAT } from '../constants/data-format';
|
||||
import type { DataFormat } from '../constants/data-format';
|
||||
import type { ReportColumnConfigEntity } from '../entities/report-config.entity';
|
||||
|
||||
export function formatReportCell(raw: unknown, format: DataFormat): unknown {
|
||||
if (raw === null || raw === undefined) {
|
||||
switch (format) {
|
||||
case DATA_FORMAT.NUMBER:
|
||||
case DATA_FORMAT.CURRENCY:
|
||||
case DATA_FORMAT.MINUS_CURRENCY:
|
||||
return Decimal.zero().toString();
|
||||
default:
|
||||
return raw;
|
||||
}
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case DATA_FORMAT.TEXT:
|
||||
return String(raw);
|
||||
case DATA_FORMAT.TEXT_UPPERCASE:
|
||||
return String(raw).toUpperCase();
|
||||
case DATA_FORMAT.TEXT_LOWERCASE:
|
||||
return String(raw).toLowerCase();
|
||||
case DATA_FORMAT.NUMBER:
|
||||
return formatDecimalOrZero(raw);
|
||||
case DATA_FORMAT.CURRENCY:
|
||||
return formatDecimalOrZero(raw);
|
||||
case DATA_FORMAT.MINUS_CURRENCY:
|
||||
return negateDecimalString(formatDecimalOrZero(raw));
|
||||
case DATA_FORMAT.PERCENTAGE:
|
||||
return `${raw}%`;
|
||||
case DATA_FORMAT.BOOLEAN:
|
||||
return raw === true || raw === 1 || raw === '1' ? 'Yes' : 'No';
|
||||
case DATA_FORMAT.STATUS:
|
||||
return String(raw);
|
||||
case DATA_FORMAT.DATE_EPOCH:
|
||||
return formatEpoch(raw);
|
||||
case DATA_FORMAT.DATE_TIMESTAMP:
|
||||
return formatTimestamp(raw);
|
||||
default:
|
||||
return raw;
|
||||
}
|
||||
}
|
||||
|
||||
export function formatReportRow(
|
||||
row: Record<string, unknown>,
|
||||
columnConfigs: ReportColumnConfigEntity[],
|
||||
): Record<string, unknown> {
|
||||
const formatted: Record<string, unknown> = { ...row };
|
||||
for (const col of columnConfigs) {
|
||||
if (col.column in formatted) {
|
||||
formatted[col.column] = formatReportCell(
|
||||
formatted[col.column],
|
||||
col.format,
|
||||
);
|
||||
}
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
|
||||
function formatDecimalOrZero(raw: unknown): string {
|
||||
try {
|
||||
if (raw === null || raw === undefined || raw === '') {
|
||||
return Decimal.zero().toString();
|
||||
}
|
||||
return Decimal.create(String(raw)).toString();
|
||||
} catch {
|
||||
return Decimal.zero().toString();
|
||||
}
|
||||
}
|
||||
|
||||
function negateDecimalString(value: string): string {
|
||||
try {
|
||||
const decimal = Decimal.create(value);
|
||||
if (decimal.isZero()) {
|
||||
return decimal.toString();
|
||||
}
|
||||
return Decimal.create(`-${value.replace(/^-/, '')}`).toString();
|
||||
} catch {
|
||||
return Decimal.zero().toString();
|
||||
}
|
||||
}
|
||||
|
||||
function formatEpoch(raw: unknown): string {
|
||||
const ms = Number(raw);
|
||||
if (!Number.isFinite(ms)) {
|
||||
return String(raw);
|
||||
}
|
||||
return DateTime.fromUnixMs(ms).format();
|
||||
}
|
||||
|
||||
function formatTimestamp(raw: unknown): string {
|
||||
if (typeof raw === 'string') {
|
||||
try {
|
||||
return DateTime.create(raw).format();
|
||||
} catch {
|
||||
return raw;
|
||||
}
|
||||
}
|
||||
const ms = Number(raw);
|
||||
if (Number.isFinite(ms)) {
|
||||
return DateTime.fromUnixMs(ms).format();
|
||||
}
|
||||
return String(raw);
|
||||
}
|
||||
Reference in New Issue
Block a user