import { REPAIR_LINE_AMOUNT_TOMAN } from "src/constants/repair-amount-limits"; import { parseMoneyAmountToman } from "src/utils/unicode-digits"; type ExpertReplyPricingPart = { partId?: unknown; price?: unknown; salary?: unknown; totalPayment?: unknown; }; /** * Validates the pricing that an expert must provide for every submitted * damaged-part line. This is deliberately independent of DTO validation: * legacy endpoints and deployments without a global ValidationPipe call the * service directly. */ export function getExpertReplyPricingValidationError( parts: unknown, ): string | null { if (!Array.isArray(parts) || parts.length === 0) { return "At least one damaged part with pricing is required to submit an expert reply."; } for (const [index, rawPart] of parts.entries()) { const part = rawPart as ExpertReplyPricingPart | null; const label = part && part.partId != null && String(part.partId).trim() !== "" ? `Part ${String(part.partId)}` : `Damaged part ${index + 1}`; if (!part || typeof part !== "object") { return `${label} must include price, salary, and totalPayment.`; } const price = parseMoneyAmountToman(part.price); const salary = parseMoneyAmountToman(part.salary); const totalPayment = parseMoneyAmountToman(part.totalPayment); const splitAmountIsValid = (amount: number | null) => amount !== null && (amount === 0 || (amount >= REPAIR_LINE_AMOUNT_TOMAN.MIN && amount <= REPAIR_LINE_AMOUNT_TOMAN.MAX)); const totalIsValid = totalPayment !== null && totalPayment >= REPAIR_LINE_AMOUNT_TOMAN.MIN && totalPayment <= REPAIR_LINE_AMOUNT_TOMAN.MAX; if ( !splitAmountIsValid(price) || !splitAmountIsValid(salary) || !totalIsValid ) { return `${label} requires valid price, salary, and totalPayment. Price and salary may be 0; totalPayment must be between ${REPAIR_LINE_AMOUNT_TOMAN.MIN.toLocaleString("en-US")} and ${REPAIR_LINE_AMOUNT_TOMAN.MAX.toLocaleString("en-US")} Toman.`; } } return null; }