YARA-1257, YARA-1272, YARA-985

This commit is contained in:
SepehrYahyaee
2026-09-12 11:19:57 +03:30
parent ebe45646c1
commit 15342e16d8
18 changed files with 279 additions and 207 deletions

View File

@@ -207,14 +207,12 @@ export class ClaimDetailV2ResponseDto {
damageExpertResend: unknown;
ownerInsurerApproval?: {
agree: boolean;
branchId?: string;
signDetailId?: string;
signLink?: string;
signedAt?: Date | string;
};
ownerPricedPartsApproval?: {
agree: boolean;
branchId?: string;
signDetailId?: string;
signLink?: string;
signedAt?: Date | string;

View File

@@ -38,12 +38,6 @@ export class DaghiDetailsV2Dto {
@IsMoneyAmountString()
price?: string;
@ApiPropertyOptional({
description: `Required when option is '${DaghiOption.DELIVER_DAMAGED_PART}' (Mongo ObjectId string)`,
})
@IsOptional()
@IsString()
branchId?: string;
}
export class PartPricingV2Dto {

View File

@@ -25,12 +25,6 @@ export class DaghiDetailsDto {
})
price?: string;
@ApiProperty({
required: false,
type: String,
description: "Branch ID required when option is 'تحویل داغی'",
})
branchId?: string;
}
export class PartsList {

View File

@@ -52,6 +52,32 @@ describe("ExpertClaimService expert-reply pricing", () => {
]);
});
it("allows a deliver-damaged-part line without a branch", () => {
const service = createService() as any;
expect(
service.validateAndNormalizeDaghiForExpertReplyV2([
{
partId: 201,
typeOfDamage: TypeOfDamage.Change,
price: "100000",
salary: "100000",
totalPayment: "200000",
daghi: { option: DaghiOption.DELIVER_DAMAGED_PART },
},
]),
).toEqual([
{
partId: 201,
typeOfDamage: TypeOfDamage.Change,
price: "100000",
salary: "100000",
totalPayment: "200000",
daghi: { option: DaghiOption.DELIVER_DAMAGED_PART },
},
]);
});
it("rejects a blank pricing line on the legacy submit endpoint before changing status", async () => {
const service = createService() as any;
const findAndUpdate = jest.fn();

View File

@@ -957,7 +957,7 @@ export class ExpertClaimService {
return pr + sa;
}
/** Same rules as V1 `submitReplyRequest`: daghi option + conditional price / branchId; `branchId` stored as ObjectId. */
/** Same rules as V1 `submitReplyRequest`: daghi option plus conditional price. */
private validateAndNormalizeDaghiForExpertReplyV2(
parts: import("./dto/expert-claim-v2.dto").PartPricingV2Dto[],
) {
@@ -985,31 +985,6 @@ export class ExpertClaimService {
),
);
}
} else if (part.daghi.option === DaghiOption.DELIVER_DAMAGED_PART) {
if (!part.daghi.branchId) {
throw new BadRequestException(
this.expertReplySubmissionError(
`شعبه تحویل داغی برای قطعه ${part.partId} الزامی است.`,
"DAGHI_BRANCH_REQUIRED",
{
field: `parts[${partIndex}].daghi.branchId`,
partId: part.partId,
},
),
);
}
if (!Types.ObjectId.isValid(part.daghi.branchId)) {
throw new BadRequestException(
this.expertReplySubmissionError(
`شناسه شعبه برای قطعه ${part.partId} معتبر نیست.`,
"DAGHI_BRANCH_INVALID",
{
field: `parts[${partIndex}].daghi.branchId`,
partId: part.partId,
},
),
);
}
}
}
@@ -1023,10 +998,6 @@ export class ExpertClaimService {
daghi: {
option: part.daghi!.option,
...(part.daghi!.price && { price: part.daghi!.price }),
...(part.daghi!.branchId &&
Types.ObjectId.isValid(part.daghi!.branchId) && {
branchId: new Types.ObjectId(part.daghi!.branchId),
}),
},
};
});
@@ -1773,18 +1744,6 @@ export class ExpertClaimService {
`Price is required for part ${part.partId} when option is '${DaghiOption.RECYCLED_PARTS_VALUE}'`,
);
}
} else if (part.daghi.option === DaghiOption.DELIVER_DAMAGED_PART) {
if (!part.daghi.branchId) {
throw new BadRequestException(
`Branch ID is required for part ${part.partId} when option is '${DaghiOption.DELIVER_DAMAGED_PART}'`,
);
}
// Validate branchId is a valid ObjectId
if (!Types.ObjectId.isValid(part.daghi.branchId)) {
throw new BadRequestException(
`Invalid branch ID format for part ${part.partId}`,
);
}
}
// For NO_VALUE and WITH_DAMAGED_PART_CALCULATION, no additional fields needed
}
@@ -1806,7 +1765,7 @@ export class ExpertClaimService {
? ClaimStepsEnum.WaitingForFactorUpload
: ClaimStepsEnum.WaitingForUserToReact;
// Process parts: convert branchId string to ObjectId if present
// Branch selection is no longer part of claim pricing.
const processedParts = reply.parts.map((part) => {
if (part.typeOfDamage === TypeOfDamage.Repair) {
const { daghi: _daghi, ...repairPart } = part;
@@ -1817,9 +1776,6 @@ export class ExpertClaimService {
daghi: {
option: part.daghi!.option,
...(part.daghi!.price && { price: part.daghi!.price }),
...(part.daghi!.branchId && {
branchId: new Types.ObjectId(part.daghi!.branchId),
}),
},
};
});
@@ -3290,7 +3246,7 @@ export class ExpertClaimService {
* - Must be locked by this expert (workflow.lockedBy.actorId === actor.sub)
* - Must be in EXPERT_REVIEWING status
* - Total payment across all parts must not exceed 53,000,000 (same cap as factor validation totals)
* - Each part must include `daghi` (option + conditional price/branchId) like V1
* - Each part must include `daghi` (option + conditional price) like V1
*
* On success:
* - Stores reply; clears owner signature fields (`ownerInsurerApproval`, `ownerPricedPartsApproval`)