forked from Yara724/api
fanavaran parsian done
This commit is contained in:
@@ -16,6 +16,10 @@ import { distance as stringDistance } from "fastest-levenshtein"; // حتما ن
|
||||
import { Types } from "mongoose";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { ClaimRequestManagementDbService } from "src/claim-request-management/entites/db-service/claim-request-management.db.service";
|
||||
import {
|
||||
ClaimRequestManagementService,
|
||||
FanavaranAutoSubmitResult,
|
||||
} from "src/claim-request-management/claim-request-management.service";
|
||||
import { ClaimSignDbService } from "src/claim-request-management/entites/db-service/claim-sign.db.service";
|
||||
import { DamageImageDbService } from "src/claim-request-management/entites/db-service/damage-image.db.service";
|
||||
import { VideoCaptureDbService } from "src/claim-request-management/entites/db-service/video-capture.db.service";
|
||||
@@ -135,14 +139,12 @@ import {
|
||||
} from "src/users/entities/schema/expert-file-activity.schema";
|
||||
|
||||
/** 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";
|
||||
import { getClaimV2TotalPaymentCapToman } from "src/constants/repair-amount-limits";
|
||||
import { ListQueryV2Dto } from "src/common/dto/list-query-v2.dto";
|
||||
import { applyListQueryV2 } from "src/helpers/list-query-v2";
|
||||
import { buildEnrichedDamagedParts } from "./dto/claim-damaged-part.enricher";
|
||||
import { canonicalizeResendDocumentKey } from "src/helpers/claim-resend-document-keys";
|
||||
|
||||
const CLAIM_V2_TOTAL_PAYMENT_CAP = CLAIM_V2_TOTAL_PAYMENT_CAP_TOMAN;
|
||||
|
||||
@Injectable()
|
||||
export class ExpertClaimService {
|
||||
private readonly logger = new Logger(ExpertClaimService.name);
|
||||
@@ -268,8 +270,22 @@ export class ExpertClaimService {
|
||||
private readonly userDbService: UserDbService,
|
||||
private readonly expertFileActivityDbService: ExpertFileActivityDbService,
|
||||
private readonly claimSignDbService: ClaimSignDbService,
|
||||
private readonly claimRequestManagementService: ClaimRequestManagementService,
|
||||
) {}
|
||||
|
||||
private appendFanavaranAutoSubmitToMessage(
|
||||
baseMessage: string,
|
||||
fanavaran: FanavaranAutoSubmitResult,
|
||||
): string {
|
||||
if (fanavaran.submitted) {
|
||||
return `${baseMessage} The claim was sent to Fanavaran successfully.`;
|
||||
}
|
||||
if (fanavaran.warning) {
|
||||
return `${baseMessage} ${fanavaran.warning}`;
|
||||
}
|
||||
return baseMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a `claim-sign` document id to a downloadable file URL.
|
||||
* Mirrors the helper used in `ExpertInsurerService` so signature links are
|
||||
@@ -1539,9 +1555,9 @@ export class ExpertClaimService {
|
||||
);
|
||||
}
|
||||
|
||||
// Validate total price cap (priced lines sum)
|
||||
if (reply.parts && reply.parts.length > 0) {
|
||||
const PRICE_CAP = CLAIM_V2_TOTAL_PAYMENT_CAP;
|
||||
// Validate total price cap (priced lines sum), when enabled.
|
||||
const priceCap = getClaimV2TotalPaymentCapToman();
|
||||
if (priceCap !== null && reply.parts && reply.parts.length > 0) {
|
||||
let totalPrice = 0;
|
||||
|
||||
for (const part of reply.parts) {
|
||||
@@ -1570,13 +1586,13 @@ export class ExpertClaimService {
|
||||
}
|
||||
}
|
||||
|
||||
if (totalPrice > PRICE_CAP) {
|
||||
if (totalPrice > priceCap) {
|
||||
throw new BadRequestException({
|
||||
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()}).`,
|
||||
message: `You have reached the maximum acceptable total price (Toman). The sum of priced parts and factor lines (${totalPrice.toLocaleString()}) exceeds the limit (${priceCap.toLocaleString()}).`,
|
||||
error: "PRICE_CAP_ERROR",
|
||||
code: "PRICE_CAP_ERROR",
|
||||
totalPrice: totalPrice,
|
||||
priceCap: PRICE_CAP,
|
||||
priceCap,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2138,7 +2154,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` Toman (53_000_000; same as initial expert reply).
|
||||
* When enabled by env, total of all repair lines must be ≤ the claim v2 total payment cap.
|
||||
* Response: `claimStatus` = `ClaimStatus`; `caseStatus` = `ClaimCaseStatus`.
|
||||
*/
|
||||
async validateClaimFactorsV2(
|
||||
@@ -2273,25 +2289,27 @@ export class ExpertClaimService {
|
||||
};
|
||||
}
|
||||
|
||||
const PRICE_CAP = CLAIM_V2_TOTAL_PAYMENT_CAP;
|
||||
let totalPrice = 0;
|
||||
for (const part of updatedReply.parts || []) {
|
||||
const line = this.claimReplyPartLineTotalForCap(part);
|
||||
if (isNaN(line)) {
|
||||
const priceCap = getClaimV2TotalPaymentCapToman();
|
||||
if (priceCap !== null) {
|
||||
let totalPrice = 0;
|
||||
for (const part of updatedReply.parts || []) {
|
||||
const line = this.claimReplyPartLineTotalForCap(part);
|
||||
if (isNaN(line)) {
|
||||
throw new BadRequestException({
|
||||
message: `Part ${String(part.partId ?? "")}: invalid amount for price total — use totalPayment or price and salary.`,
|
||||
error: "PRICE_CAP_ERROR",
|
||||
});
|
||||
}
|
||||
totalPrice += line;
|
||||
}
|
||||
if (totalPrice > priceCap) {
|
||||
throw new BadRequestException({
|
||||
message: `Part ${String(part.partId ?? "")}: invalid amount for price total — use totalPayment or price and salary.`,
|
||||
message: `You have reached the maximum acceptable total price (Toman). The sum of priced parts and factor lines (${totalPrice.toLocaleString()}) exceeds the limit (${priceCap.toLocaleString()}).`,
|
||||
error: "PRICE_CAP_ERROR",
|
||||
totalPrice,
|
||||
priceCap,
|
||||
});
|
||||
}
|
||||
totalPrice += line;
|
||||
}
|
||||
if (totalPrice > PRICE_CAP) {
|
||||
throw new BadRequestException({
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
const historyActor = {
|
||||
@@ -2309,13 +2327,20 @@ export class ExpertClaimService {
|
||||
historyActor,
|
||||
{ replyField },
|
||||
);
|
||||
const fanavaran =
|
||||
await this.claimRequestManagementService.autoSubmitToFanavaranParsianV2OnClaimCompleted(
|
||||
claimRequestId,
|
||||
);
|
||||
return {
|
||||
message:
|
||||
message: this.appendFanavaranAutoSubmitToMessage(
|
||||
"Factors were reviewed with expert repricing on rejected lines. The claim is completed without an owner signature (temporary policy; may require owner acceptance later).",
|
||||
fanavaran,
|
||||
),
|
||||
claimRequestId,
|
||||
claimStatus: ClaimStatus.APPROVED,
|
||||
caseStatus: ClaimCaseStatus.COMPLETED,
|
||||
outcome: "REJECTED_REPRICED_AUTO_COMPLETED",
|
||||
fanavaran,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2328,13 +2353,21 @@ export class ExpertClaimService {
|
||||
{ replyField },
|
||||
);
|
||||
|
||||
const fanavaran =
|
||||
await this.claimRequestManagementService.autoSubmitToFanavaranParsianV2OnClaimCompleted(
|
||||
claimRequestId,
|
||||
);
|
||||
|
||||
return {
|
||||
message:
|
||||
message: this.appendFanavaranAutoSubmitToMessage(
|
||||
"All factors were approved by the expert. The claim is completed without an additional owner signature.",
|
||||
fanavaran,
|
||||
),
|
||||
claimRequestId,
|
||||
claimStatus: ClaimStatus.APPROVED,
|
||||
caseStatus: ClaimCaseStatus.COMPLETED,
|
||||
outcome: "ALL_APPROVED_AUTO_COMPLETED",
|
||||
fanavaran,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2878,20 +2911,22 @@ export class ExpertClaimService {
|
||||
throw new ForbiddenException("This claim is locked by another expert");
|
||||
}
|
||||
|
||||
// Price cap validation
|
||||
const PRICE_CAP = CLAIM_V2_TOTAL_PAYMENT_CAP;
|
||||
let totalPrice = 0;
|
||||
for (const part of reply.parts || []) {
|
||||
const parsed = this.parsePersianNumber(String(part.totalPayment ?? "0"));
|
||||
if (!isNaN(parsed)) totalPrice += parsed;
|
||||
}
|
||||
if (totalPrice > PRICE_CAP) {
|
||||
throw new BadRequestException({
|
||||
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,
|
||||
});
|
||||
// Price cap validation, when enabled.
|
||||
const priceCap = getClaimV2TotalPaymentCapToman();
|
||||
if (priceCap !== null) {
|
||||
let totalPrice = 0;
|
||||
for (const part of reply.parts || []) {
|
||||
const parsed = this.parsePersianNumber(String(part.totalPayment ?? "0"));
|
||||
if (!isNaN(parsed)) totalPrice += parsed;
|
||||
}
|
||||
if (totalPrice > priceCap) {
|
||||
throw new BadRequestException({
|
||||
message: `You have reached the maximum acceptable total price (Toman). The sum of priced parts and factor lines (${totalPrice.toLocaleString()}) exceeds the limit (${priceCap.toLocaleString()}).`,
|
||||
error: "PRICE_CAP_ERROR",
|
||||
totalPrice,
|
||||
priceCap,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const carTypeSubmit = claim.vehicle?.carType as
|
||||
|
||||
Reference in New Issue
Block a user