targo-backend/src/modules/expenses/utils/expenses.utils.ts
2025-09-30 10:43:48 -04:00

65 lines
2.0 KiB
TypeScript

import { BadRequestException } from "@nestjs/common";
import { DayExpenseResponse } from "../types and interfaces/expenses.types.interfaces";
//uppercase and trim for validation
export function normalizeType(type: string): string {
return (type ?? '').trim().toUpperCase();
};
//required comment after trim
export function assertAndTrimComment(comment: string): string {
const cmt = (comment ?? '').trim();
if(cmt.length === 0) {
throw new BadRequestException('A comment is required');
}
return cmt;
};
//rounding $ to 2 decimals
export function roundMoney2(num: number): number {
return Math.round((num + Number.EPSILON) * 100)/ 100;
};
export function computeMileageAmount(km: number, modifier: number): number {
if(km < 0) throw new BadRequestException('mileage must be positive');
if(modifier < 0) throw new BadRequestException('modifier must be positive');
return roundMoney2(km * modifier);
};
//compat. types with Prisma.Decimal. work around Prisma import in utils.
export type DecimalLike =
| number
| string
| { toNumber?: () => number }
| { toString?: () => string };
//safe conversion to number
export function toNumberSafe(value: DecimalLike): number {
if(typeof value === 'number') return value;
if(value && typeof (value as any).toNumber === 'function') return (value as any).toNumber();
return Number(
typeof (value as any)?.toString === 'function'
? (value as any).toString()
: value,
);
}
//map of a row for DayExpenseResponse
export function mapDbExpenseToDayResponse(row: {
date: Date;
amount: DecimalLike;
comment: string;
is_approved: boolean;
bank_code?: { type?: string | null } | null;
}): DayExpenseResponse {
const yyyyMmDd = row.date.toISOString().slice(0,10);
return {
date: yyyyMmDd,
type: normalizeType(row.bank_code?.type ?? 'UNKNOWN'),
amount: toNumberSafe(row.amount),
comment: row.comment,
is_approved: row.is_approved,
};
}