forked from Yara724/api
Validation for prices and objection
This commit is contained in:
@@ -44,7 +44,7 @@ export class UpsertClaimPriceDropV2Dto {
|
||||
|
||||
@ApiProperty({
|
||||
example: 450000000,
|
||||
description: "Market price of the car (Rials)",
|
||||
description: "Market price of the car (Toman)",
|
||||
})
|
||||
carPrice: number | string;
|
||||
|
||||
|
||||
@@ -10,11 +10,10 @@ import {
|
||||
IsInt,
|
||||
} from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsRepairLineAmountToman } from 'src/common/validators/repair-line-amount-toman.validator';
|
||||
import { ClaimRequiredDocumentType } from 'src/Types&Enums/claim-request-management/required-document-type.enum';
|
||||
import { DamagedPartItem } from 'src/claim-request-management/dto/capture-requirements-v2.dto';
|
||||
import { DaghiOption } from 'src/Types&Enums/claim-request-management/daghi-option.enum';
|
||||
|
||||
/** Same shape as V1 {@link PartsList} `daghi` (damage expert reply). */
|
||||
export class DaghiDetailsV2Dto {
|
||||
@ApiProperty({
|
||||
enum: DaghiOption,
|
||||
@@ -25,10 +24,11 @@ export class DaghiDetailsV2Dto {
|
||||
option: DaghiOption;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: `Required when option is '${DaghiOption.RECYCLED_PARTS_VALUE}'`,
|
||||
description: `Required when option is '${DaghiOption.RECYCLED_PARTS_VALUE}' (Toman)`,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@IsRepairLineAmountToman()
|
||||
price?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
@@ -51,16 +51,28 @@ export class PartPricingV2Dto {
|
||||
@IsString()
|
||||
typeOfDamage: string;
|
||||
|
||||
@ApiProperty({ example: '5000000' })
|
||||
@ApiProperty({
|
||||
example: "5000000",
|
||||
description: "Part price in Toman (integer string). Use 0 if the full amount is in salary.",
|
||||
})
|
||||
@IsString()
|
||||
@IsRepairLineAmountToman({ allowZero: true })
|
||||
price: string;
|
||||
|
||||
@ApiProperty({ example: '2000000' })
|
||||
@ApiProperty({
|
||||
example: "2000000",
|
||||
description: "Labor in Toman (integer string). Use 0 if the full amount is in price.",
|
||||
})
|
||||
@IsString()
|
||||
@IsRepairLineAmountToman({ allowZero: true })
|
||||
salary: string;
|
||||
|
||||
@ApiProperty({ example: '7000000' })
|
||||
@ApiProperty({
|
||||
example: "7000000",
|
||||
description: "Line total in Toman (integer string).",
|
||||
})
|
||||
@IsString()
|
||||
@IsRepairLineAmountToman()
|
||||
totalPayment: string;
|
||||
|
||||
@ApiProperty({ type: DaghiDetailsV2Dto })
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from "class-validator";
|
||||
import { IsRepairLineAmountToman } from "src/common/validators/repair-line-amount-toman.validator";
|
||||
import { FactorStatus } from "src/Types&Enums/claim-request-management/factor-status.enum";
|
||||
|
||||
class FactorDecisionDto {
|
||||
@@ -50,26 +51,29 @@ class FactorDecisionV2Dto {
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description:
|
||||
"Part price (Persian/ASCII digits). For each factor line, send totalPayment **or** both price and salary. Required for **APPROVED** (accepted amount read from factor / expert) and **REJECTED** (expert’s replacement pricing).",
|
||||
"Part price (Toman). With totalPayment or price+salary for APPROVED/REJECTED factor lines. Use 0 if unused.",
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@IsRepairLineAmountToman({ allowZero: true })
|
||||
price?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description:
|
||||
"Salary portion when not using a single totalPayment (must be sent together with price for APPROVED/REJECTED factor lines).",
|
||||
"Salary in Toman. Send with price when not using only totalPayment. Use 0 if unused.",
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@IsRepairLineAmountToman({ allowZero: true })
|
||||
salary?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description:
|
||||
"Line total payment; preferred when the expert enters one number. Required together with APPROVED/REJECTED unless both price and salary are sent.",
|
||||
"Line total in Toman; or send both price and salary.",
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@IsRepairLineAmountToman()
|
||||
totalPayment?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -114,8 +114,10 @@ import {
|
||||
ExpertFileKind,
|
||||
} from "src/users/entities/schema/expert-file-activity.schema";
|
||||
|
||||
/** Maximum sum of line `totalPayment` across the claim (priced parts + factor lines after validation). */
|
||||
const CLAIM_V2_TOTAL_PAYMENT_CAP = 53_000_000;
|
||||
/** Maximum sum of line `totalPayment` across the claim (Toman; priced parts + factor lines after validation). */
|
||||
import { CLAIM_V2_TOTAL_PAYMENT_CAP_TOMAN } from "src/constants/repair-amount-limits";
|
||||
|
||||
const CLAIM_V2_TOTAL_PAYMENT_CAP = CLAIM_V2_TOTAL_PAYMENT_CAP_TOMAN;
|
||||
|
||||
@Injectable()
|
||||
export class ExpertClaimService {
|
||||
@@ -1523,7 +1525,7 @@ export class ExpertClaimService {
|
||||
|
||||
if (totalPrice > PRICE_CAP) {
|
||||
throw new BadRequestException({
|
||||
message: `You have reached the maximum acceptable total price. The sum of priced parts and factor lines (${totalPrice.toLocaleString()}) exceeds the limit (${PRICE_CAP.toLocaleString()}).`,
|
||||
message: `You have reached the maximum acceptable total price (Toman). The sum of priced parts and factor lines (${totalPrice.toLocaleString()}) exceeds the limit (${PRICE_CAP.toLocaleString()}).`,
|
||||
error: "PRICE_CAP_ERROR",
|
||||
code: "PRICE_CAP_ERROR",
|
||||
totalPrice: totalPrice,
|
||||
@@ -2089,7 +2091,7 @@ export class ExpertClaimService {
|
||||
* Preconditions: all `factorNeeded` parts have `factorLink`; case is UNDER_REVIEW at EXPERT_COST_EVALUATION.
|
||||
* — All approved → COMPLETED + APPROVED (expert-entered line totals; no extra owner signature).
|
||||
* — Any rejected (repriced) → COMPLETED + APPROVED (auto-close for now; owner sign may be added later).
|
||||
* Total of all repair lines must be ≤ `CLAIM_V2_TOTAL_PAYMENT_CAP` (53_000_000; same as initial expert reply).
|
||||
* Total of all repair lines must be ≤ `CLAIM_V2_TOTAL_PAYMENT_CAP` Toman (53_000_000; same as initial expert reply).
|
||||
* Response: `claimStatus` = `ClaimStatus`; `caseStatus` = `ClaimCaseStatus`.
|
||||
*/
|
||||
async validateClaimFactorsV2(
|
||||
@@ -2238,7 +2240,7 @@ export class ExpertClaimService {
|
||||
}
|
||||
if (totalPrice > PRICE_CAP) {
|
||||
throw new BadRequestException({
|
||||
message: `You have reached the maximum acceptable total price. The sum of priced parts and factor lines (${totalPrice.toLocaleString()}) exceeds the limit (${PRICE_CAP.toLocaleString()}).`,
|
||||
message: `You have reached the maximum acceptable total price (Toman). The sum of priced parts and factor lines (${totalPrice.toLocaleString()}) exceeds the limit (${PRICE_CAP.toLocaleString()}).`,
|
||||
error: "PRICE_CAP_ERROR",
|
||||
totalPrice,
|
||||
priceCap: PRICE_CAP,
|
||||
@@ -2700,7 +2702,7 @@ export class ExpertClaimService {
|
||||
}
|
||||
if (totalPrice > PRICE_CAP) {
|
||||
throw new BadRequestException({
|
||||
message: `You have reached the maximum acceptable total price. The sum of priced parts and factor lines (${totalPrice.toLocaleString()}) exceeds the limit (${PRICE_CAP.toLocaleString()}).`,
|
||||
message: `You have reached the maximum acceptable total price (Toman). The sum of priced parts and factor lines (${totalPrice.toLocaleString()}) exceeds the limit (${PRICE_CAP.toLocaleString()}).`,
|
||||
error: 'PRICE_CAP_ERROR',
|
||||
totalPrice,
|
||||
priceCap: PRICE_CAP,
|
||||
|
||||
@@ -176,7 +176,7 @@ export class ExpertClaimV2Controller {
|
||||
@ApiOperation({
|
||||
summary: "Submit expert damage assessment reply",
|
||||
description:
|
||||
"**Preconditions:** claim locked by this expert (`EXPERT_REVIEWING`). **Unlocks** the claim. Each `parts[]` line needs `partId` (from GET claim detail `damagedParts[].partId`), plus pricing, `daghi`, and optional `factorNeeded`. **Cap:** sum of line `totalPayment` values ≤ 53,000,000 (same limit as factor-validation totals across priced + factor lines). Clears any prior `evaluation.ownerInsurerApproval` / `ownerPricedPartsApproval`.\n\n" +
|
||||
"**Preconditions:** claim locked by this expert (`EXPERT_REVIEWING`). **Unlocks** the claim. Each `parts[]` line needs `partId` (from GET claim detail `damagedParts[].partId`), plus pricing, `daghi`, and optional `factorNeeded`. **Cap:** sum of line `totalPayment` values ≤ 53,000,000 **Toman** (same limit as factor-validation totals across priced + factor lines). Clears any prior `evaluation.ownerInsurerApproval` / `ownerPricedPartsApproval`.\n\n" +
|
||||
"**Frontend routing by `ClaimCaseStatus` (`status`):**\n" +
|
||||
"- **All parts `factorNeeded`:** `OWNER_REPAIR_FACTOR_UPLOAD_PENDING`, `claimStatus=NEEDS_REVISION`, `workflow.currentStep=OWNER_UPLOAD_FACTOR_DOCUMENTS`, `workflow.nextStep=EXPERT_COST_EVALUATION` → owner uploads all factors; then `status` becomes **`EXPERT_VALIDATING_REPAIR_FACTORS`**, `claimStatus=UNDER_REVIEW`, `currentStep=EXPERT_COST_EVALUATION` for expert **validate-factors**.\n" +
|
||||
"- **Mixed (some priced, some factorNeeded):** `INSURER_REVIEW_MIXED_FACTORS_PENDING`, `claimStatus=NEEDS_REVISION`, `currentStep=INSURER_REVIEW`, `nextStep=OWNER_UPLOAD_FACTOR_DOCUMENTS` → owner must call **owner-insurer-approval/sign** first (priced-line acceptance); `currentStep` then moves to `OWNER_UPLOAD_FACTOR_DOCUMENTS` (same case `status` until factors are done).\n" +
|
||||
@@ -239,7 +239,7 @@ export class ExpertClaimV2Controller {
|
||||
"**Response:** `claimStatus` = `ClaimStatus` (e.g. APPROVED). `caseStatus` = `ClaimCaseStatus` (e.g. COMPLETED vs insurer-review) — they are not interchangeable.\n\n" +
|
||||
"**Preconditions:** `status=EXPERT_VALIDATING_REPAIR_FACTORS` (or legacy `WAITING_FOR_INSURER_APPROVAL`), `claimStatus=UNDER_REVIEW`, `workflow.currentStep=EXPERT_COST_EVALUATION`, every `factorNeeded` line has `factorLink`.\n\n" +
|
||||
"**Decisions:** each factor line gets `APPROVED` or `REJECTED`. **Every** decided line must include expert-entered `totalPayment` **or** both `price` and `salary` (factor photos are not read for amounts).\n\n" +
|
||||
"**Cap (when every factor line is decided):** sum of **all** reply lines (priced parts + factor lines) must be ≤ **53,000,000**; otherwise `PRICE_CAP_ERROR` with message that the maximum acceptable total was exceeded.\n\n" +
|
||||
"**Cap (when every factor line is decided):** sum of **all** reply lines (priced parts + factor lines) must be ≤ **53,000,000 Toman**; otherwise `PRICE_CAP_ERROR` with message that the maximum acceptable total was exceeded.\n\n" +
|
||||
"**Outcomes:**\n" +
|
||||
"- **All approved:** `caseStatus=COMPLETED`, `claimStatus=APPROVED`, workflow `CLAIM_COMPLETED` — no owner signature.\n" +
|
||||
"- **Any rejected (repriced):** same auto-complete for now (owner acceptance may be added later).\n" +
|
||||
|
||||
Reference in New Issue
Block a user