forked from Yara724/api
Compare commits
6 Commits
80122e7772
...
54ae82aa38
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54ae82aa38 | ||
|
|
7a3ddcc7be | ||
|
|
da3f57870e | ||
|
|
04f51167c2 | ||
|
|
2c8fd3960f | ||
|
|
e59058520c |
@@ -32,12 +32,17 @@ export class CaptchaChallengeService {
|
|||||||
this.captchaService.normalizeAnswer(generated.text),
|
this.captchaService.normalizeAnswer(generated.text),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// expireAt is the MongoDB TTL sentinel. The TTL reaper fires every ~60 s, so
|
||||||
|
// setting it equal to expiresAt means Mongo can delete the document up to 60 s
|
||||||
|
// BEFORE the application-level expiry check runs — causing the intermittent
|
||||||
|
// "captchaId not found" error under load. Adding a 120 s grace buffer ensures
|
||||||
|
// the document is always present when verify() runs its own expiresAt check.
|
||||||
await this.captchaChallengeDbService.create({
|
await this.captchaChallengeDbService.create({
|
||||||
captchaId,
|
captchaId,
|
||||||
answerHash,
|
answerHash,
|
||||||
image: generated.image,
|
image: generated.image,
|
||||||
expiresAt: generated.expiresAt,
|
expiresAt: generated.expiresAt,
|
||||||
expireAt: new Date(generated.expiresAt),
|
expireAt: new Date(generated.expiresAt + 120_000),
|
||||||
usedAt: null,
|
usedAt: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ export class CaptchaChallenge {
|
|||||||
@Prop({ required: true, unique: true, index: true })
|
@Prop({ required: true, unique: true, index: true })
|
||||||
captchaId: string;
|
captchaId: string;
|
||||||
|
|
||||||
@Prop()
|
@Prop({ required: true })
|
||||||
answerHash?: string;
|
answerHash: string;
|
||||||
|
|
||||||
@Prop({ required: true })
|
@Prop({ required: true })
|
||||||
image: string;
|
image: string;
|
||||||
|
|||||||
@@ -134,13 +134,16 @@ export class ClaimDetailV2ResponseDto {
|
|||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description:
|
description:
|
||||||
"Slice of `claim.evaluation` exposed to the damage expert. " +
|
"Slice of `claim.evaluation` exposed to the damage expert. " +
|
||||||
"`damageExpertReply` / `damageExpertReplyFinal` are returned only while " +
|
"`damageExpertReply` / `damageExpertReplyFinal` are returned whenever " +
|
||||||
"awaiting factor validation. `ownerInsurerApproval` and " +
|
"present, regardless of the current claim status — historical assessment " +
|
||||||
"`ownerPricedPartsApproval` are returned whenever they exist on the " +
|
"data remains visible once the expert has submitted it. " +
|
||||||
"claim — each carries `signLink` (resolved from `signDetailId`) so the " +
|
"`ownerInsurerApproval` and `ownerPricedPartsApproval` are returned " +
|
||||||
"front-end can render the user signature directly. Likewise, " +
|
"whenever they exist on the claim — each carries `signLink` (resolved " +
|
||||||
"`damageExpertReply.userComment` / `damageExpertReplyFinal.userComment` " +
|
"from `signDetailId`) so the front-end can render the user signature " +
|
||||||
"expose `signLink` when a user comment signature is present.",
|
"directly. Likewise, `damageExpertReply.userComment` / " +
|
||||||
|
"`damageExpertReplyFinal.userComment` expose `signLink` when a user " +
|
||||||
|
"comment signature is present. `priceDrop` is included whenever it " +
|
||||||
|
"has been saved, not only during the expert review phase.",
|
||||||
})
|
})
|
||||||
evaluation?: {
|
evaluation?: {
|
||||||
damageExpertReply?: unknown;
|
damageExpertReply?: unknown;
|
||||||
|
|||||||
25
src/expert-claim/exceptions/business-rule.exception.ts
Normal file
25
src/expert-claim/exceptions/business-rule.exception.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { HttpException, HttpStatus } from "@nestjs/common";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when a well-formed request violates a business rule that cannot be
|
||||||
|
* expressed as a generic validation error. Returns HTTP 422 with a structured
|
||||||
|
* body so the frontend can branch on `errorCode` without string-matching the
|
||||||
|
* human-readable `message`.
|
||||||
|
*
|
||||||
|
* Response body shape:
|
||||||
|
* ```json
|
||||||
|
* { "errorCode": "SOME_CODE", "message": "Human-readable explanation." }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class BusinessRuleException extends HttpException {
|
||||||
|
constructor(
|
||||||
|
public readonly errorCode: string,
|
||||||
|
message: string,
|
||||||
|
) {
|
||||||
|
super({ errorCode, message }, HttpStatus.UNPROCESSABLE_ENTITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BusinessErrorCode = {
|
||||||
|
DAMAGE_EXPERT_RESEND_LIMIT_EXCEEDED: "DAMAGE_EXPERT_RESEND_LIMIT_EXCEEDED",
|
||||||
|
} as const;
|
||||||
@@ -12,6 +12,10 @@ import {
|
|||||||
Logger,
|
Logger,
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
|
import {
|
||||||
|
BusinessErrorCode,
|
||||||
|
BusinessRuleException,
|
||||||
|
} from "./exceptions/business-rule.exception";
|
||||||
import { distance as stringDistance } from "fastest-levenshtein"; // حتما نصب بشه
|
import { distance as stringDistance } from "fastest-levenshtein"; // حتما نصب بشه
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { lastValueFrom } from "rxjs";
|
import { lastValueFrom } from "rxjs";
|
||||||
@@ -541,6 +545,23 @@ export class ExpertClaimService {
|
|||||||
return this.expertVehicleFromPartyVehicle(party?.vehicle);
|
return this.expertVehicleFromPartyVehicle(party?.vehicle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Extract car name / model from the inquiry snapshot embedded on the claim. */
|
||||||
|
private vehicleNamesFromClaimInquiries(claim: any): {
|
||||||
|
carName?: string;
|
||||||
|
carModel?: string;
|
||||||
|
} {
|
||||||
|
// Claim copies inquiries from blame at creation time.
|
||||||
|
// Try thirdParty first, then carBody.
|
||||||
|
const mapped =
|
||||||
|
claim?.inquiries?.thirdParty?.data?.FIRST?.mapped ??
|
||||||
|
claim?.inquiries?.carBody?.data?.FIRST?.mapped ??
|
||||||
|
{};
|
||||||
|
const carName: string | undefined =
|
||||||
|
mapped.MapTypNam || mapped.SystemField || undefined;
|
||||||
|
const carModel: string | undefined = mapped.TypeField || undefined;
|
||||||
|
return { carName, carModel };
|
||||||
|
}
|
||||||
|
|
||||||
private vehicleForExpertFromClaimAndBlameMap(
|
private vehicleForExpertFromClaimAndBlameMap(
|
||||||
claim: any,
|
claim: any,
|
||||||
blameById: Map<string, any>,
|
blameById: Map<string, any>,
|
||||||
@@ -554,10 +575,24 @@ export class ExpertClaimService {
|
|||||||
| undefined {
|
| undefined {
|
||||||
const cv = claim?.vehicle;
|
const cv = claim?.vehicle;
|
||||||
if (cv && (cv.carName || cv.carModel || cv.carType || (cv as any).plate)) {
|
if (cv && (cv.carName || cv.carModel || cv.carType || (cv as any).plate)) {
|
||||||
|
const carType: string | undefined = cv.carType;
|
||||||
|
// carName/carModel that match the enum value (e.g. "sedan") are invalid —
|
||||||
|
// the expert may have accidentally copied the carType value into those fields.
|
||||||
|
// Fall back to the inquiry snapshot for the real brand / variant strings.
|
||||||
|
let carName: string | undefined = cv.carName;
|
||||||
|
let carModel: string | undefined = cv.carModel;
|
||||||
|
if (
|
||||||
|
(!carName || carName === carType) ||
|
||||||
|
(!carModel || carModel === carType)
|
||||||
|
) {
|
||||||
|
const fromInquiry = this.vehicleNamesFromClaimInquiries(claim);
|
||||||
|
if (!carName || carName === carType) carName = fromInquiry.carName;
|
||||||
|
if (!carModel || carModel === carType) carModel = fromInquiry.carModel;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
carName: cv.carName,
|
carName,
|
||||||
carModel: cv.carModel,
|
carModel,
|
||||||
carType: cv.carType,
|
carType,
|
||||||
...((cv as any).plate ? { plate: (cv as any).plate } : {}),
|
...((cv as any).plate ? { plate: (cv as any).plate } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2982,7 +3017,8 @@ export class ExpertClaimService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (existingResend?.fulfilledAt) {
|
if (existingResend?.fulfilledAt) {
|
||||||
throw new BadRequestException(
|
throw new BusinessRuleException(
|
||||||
|
BusinessErrorCode.DAMAGE_EXPERT_RESEND_LIMIT_EXCEEDED,
|
||||||
"The owner has already fulfilled a damage-expert resend for this claim. You cannot request another resend.",
|
"The owner has already fulfilled a damage-expert resend for this claim. You cannot request another resend.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -4801,6 +4837,24 @@ export class ExpertClaimService {
|
|||||||
if (fromBlame) vehiclePayload = fromBlame;
|
if (fromBlame) vehiclePayload = fromBlame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Patch up carName/carModel when they equal carType (invalid — expert copied the enum value).
|
||||||
|
if (vehiclePayload) {
|
||||||
|
const carType: string | undefined = vehiclePayload.carType;
|
||||||
|
if (
|
||||||
|
carType &&
|
||||||
|
((!vehiclePayload.carName || vehiclePayload.carName === carType) ||
|
||||||
|
(!vehiclePayload.carModel || vehiclePayload.carModel === carType))
|
||||||
|
) {
|
||||||
|
const fromInquiry = this.vehicleNamesFromClaimInquiries(claim);
|
||||||
|
if (!vehiclePayload.carName || vehiclePayload.carName === carType) {
|
||||||
|
vehiclePayload = { ...vehiclePayload, carName: fromInquiry.carName };
|
||||||
|
}
|
||||||
|
if (!vehiclePayload.carModel || vehiclePayload.carModel === carType) {
|
||||||
|
vehiclePayload = { ...vehiclePayload, carModel: fromInquiry.carModel };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const blameFileContext = blameLean
|
const blameFileContext = blameLean
|
||||||
? this.blameFileContextForExpert(blameLean)
|
? this.blameFileContextForExpert(blameLean)
|
||||||
: {};
|
: {};
|
||||||
@@ -4853,7 +4907,11 @@ export class ExpertClaimService {
|
|||||||
let evaluationForApi: Record<string, unknown> | undefined;
|
let evaluationForApi: Record<string, unknown> | undefined;
|
||||||
if (enrichedEvaluation) {
|
if (enrichedEvaluation) {
|
||||||
evaluationForApi = {};
|
evaluationForApi = {};
|
||||||
if (isFactorValidationPending) {
|
// damageExpertReply / damageExpertReplyFinal: include whenever present.
|
||||||
|
// Previously these were gated on isFactorValidationPending, which hid the
|
||||||
|
// expert assessment once the claim moved to user-side statuses such as
|
||||||
|
// INSURER_REVIEW_AWAITING_OWNER_SIGN. Historical assessment data should
|
||||||
|
// always be visible once submitted.
|
||||||
if (enrichedEvaluation.damageExpertReply !== undefined) {
|
if (enrichedEvaluation.damageExpertReply !== undefined) {
|
||||||
evaluationForApi.damageExpertReply =
|
evaluationForApi.damageExpertReply =
|
||||||
enrichedEvaluation.damageExpertReply;
|
enrichedEvaluation.damageExpertReply;
|
||||||
@@ -4862,7 +4920,6 @@ export class ExpertClaimService {
|
|||||||
evaluationForApi.damageExpertReplyFinal =
|
evaluationForApi.damageExpertReplyFinal =
|
||||||
enrichedEvaluation.damageExpertReplyFinal;
|
enrichedEvaluation.damageExpertReplyFinal;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (enrichedEvaluation.ownerInsurerApproval !== undefined) {
|
if (enrichedEvaluation.ownerInsurerApproval !== undefined) {
|
||||||
evaluationForApi.ownerInsurerApproval =
|
evaluationForApi.ownerInsurerApproval =
|
||||||
enrichedEvaluation.ownerInsurerApproval;
|
enrichedEvaluation.ownerInsurerApproval;
|
||||||
@@ -4871,7 +4928,8 @@ export class ExpertClaimService {
|
|||||||
evaluationForApi.ownerPricedPartsApproval =
|
evaluationForApi.ownerPricedPartsApproval =
|
||||||
enrichedEvaluation.ownerPricedPartsApproval;
|
enrichedEvaluation.ownerPricedPartsApproval;
|
||||||
}
|
}
|
||||||
if (isDamageExpertPhase && enrichedEvaluation.priceDrop !== undefined) {
|
// priceDrop: include whenever present, not only during the expert phase.
|
||||||
|
if (enrichedEvaluation.priceDrop !== undefined) {
|
||||||
evaluationForApi.priceDrop = enrichedEvaluation.priceDrop;
|
evaluationForApi.priceDrop = enrichedEvaluation.priceDrop;
|
||||||
}
|
}
|
||||||
if (Object.keys(evaluationForApi).length === 0) {
|
if (Object.keys(evaluationForApi).length === 0) {
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ export class ExpertClaimV2Controller {
|
|||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Get claim request detail for damage expert",
|
summary: "Get claim request detail for damage expert",
|
||||||
description:
|
description:
|
||||||
"Returns full claim details including captured images, required documents, damage selections, `evaluation.priceDrop` during damage review, `videoCapture` (from claim-video-capture via media.videoCaptureId), and `blameCase` (linked blameCases document with party video/voice URLs like expert-blame detail). Allowed when status is WAITING_FOR_DAMAGE_EXPERT (if locked, only the locking expert) or when awaiting factor validation.",
|
"Returns full claim details including captured images, required documents, damage selections, `evaluation.priceDrop` (included whenever saved, regardless of current status), `videoCapture` (from claim-video-capture via media.videoCaptureId), and `blameCase` (linked blameCases document with party video/voice URLs like expert-blame detail). `evaluation.damageExpertReply` / `damageExpertReplyFinal` are always returned once submitted. Allowed when status is WAITING_FOR_DAMAGE_EXPERT (if locked, only the locking expert) or when awaiting factor validation.",
|
||||||
})
|
})
|
||||||
@ApiParam({ name: "claimRequestId" })
|
@ApiParam({ name: "claimRequestId" })
|
||||||
async getClaimDetailV2(
|
async getClaimDetailV2(
|
||||||
@@ -281,7 +281,20 @@ export class ExpertClaimV2Controller {
|
|||||||
description:
|
description:
|
||||||
"Claim must be locked by this expert (`EXPERT_REVIEWING`). Sets `WAITING_FOR_USER_RESEND`, `USER_EXPERT_RESEND`, `NEEDS_REVISION`, clears the lock, and stores `evaluation.damageExpertResend`. " +
|
"Claim must be locked by this expert (`EXPERT_REVIEWING`). Sets `WAITING_FOR_USER_RESEND`, `USER_EXPERT_RESEND`, `NEEDS_REVISION`, clears the lock, and stores `evaluation.damageExpertResend`. " +
|
||||||
"Owner completes via document/capture endpoints or `POST .../expert-resend/acknowledge` when only instructions were given.\n\n" +
|
"Owner completes via document/capture endpoints or `POST .../expert-resend/acknowledge` when only instructions were given.\n\n" +
|
||||||
"**One resend per claim lifecycle:** if the owner has already fulfilled a resend (`damageExpertResend.fulfilledAt`), this endpoint returns **400**—the expert may only submit a priced reply or request in-person visit afterward.",
|
"**One resend per claim lifecycle:** if the owner has already fulfilled a resend (`damageExpertResend.fulfilledAt`), this endpoint returns **422** with `errorCode: DAMAGE_EXPERT_RESEND_LIMIT_EXCEEDED`—the expert may only submit a priced reply or request in-person visit afterward.",
|
||||||
|
})
|
||||||
|
@ApiResponse({
|
||||||
|
status: 422,
|
||||||
|
description:
|
||||||
|
"Business rule violation: resend limit exceeded. " +
|
||||||
|
"`errorCode: DAMAGE_EXPERT_RESEND_LIMIT_EXCEEDED` — the owner has already fulfilled a prior resend request for this claim.",
|
||||||
|
schema: {
|
||||||
|
example: {
|
||||||
|
errorCode: "DAMAGE_EXPERT_RESEND_LIMIT_EXCEEDED",
|
||||||
|
message:
|
||||||
|
"The owner has already fulfilled a damage-expert resend for this claim. You cannot request another resend.",
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
@ApiParam({ name: "claimRequestId" })
|
@ApiParam({ name: "claimRequestId" })
|
||||||
@ApiBody({ type: ClaimSubmitResendV2Dto })
|
@ApiBody({ type: ClaimSubmitResendV2Dto })
|
||||||
|
|||||||
@@ -99,20 +99,32 @@ export class ExpertInsurerController {
|
|||||||
|
|
||||||
@Put("branches/:branchId/status")
|
@Put("branches/:branchId/status")
|
||||||
@ApiParam({ name: "branchId" })
|
@ApiParam({ name: "branchId" })
|
||||||
@ApiQuery({ name: "isActive", type: Boolean })
|
@ApiBody({
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: { isActive: { type: "boolean" } },
|
||||||
|
required: ["isActive"],
|
||||||
|
},
|
||||||
|
})
|
||||||
async setBranchStatus(
|
async setBranchStatus(
|
||||||
@CurrentUser() insurer,
|
@CurrentUser() insurer,
|
||||||
@Param("branchId") branchId: string,
|
@Param("branchId") branchId: string,
|
||||||
@Query("isActive") isActive: string,
|
@Body("isActive") isActive: unknown,
|
||||||
) {
|
) {
|
||||||
if (!insurer) {
|
if (!insurer) {
|
||||||
throw new UnauthorizedException("Could not identify the current user.");
|
throw new UnauthorizedException("Could not identify the current user.");
|
||||||
}
|
}
|
||||||
const normalized = String(isActive).trim().toLowerCase();
|
// Accept native boolean (JSON body) or string coercion (legacy query/form usage)
|
||||||
|
let active: boolean;
|
||||||
|
if (typeof isActive === "boolean") {
|
||||||
|
active = isActive;
|
||||||
|
} else {
|
||||||
|
const normalized = String(isActive ?? "").trim().toLowerCase();
|
||||||
if (!["true", "false", "1", "0", "yes", "no"].includes(normalized)) {
|
if (!["true", "false", "1", "0", "yes", "no"].includes(normalized)) {
|
||||||
throw new BadRequestException("isActive must be true/false");
|
throw new BadRequestException("isActive must be a boolean");
|
||||||
|
}
|
||||||
|
active = ["true", "1", "yes"].includes(normalized);
|
||||||
}
|
}
|
||||||
const active = ["true", "1", "yes"].includes(normalized);
|
|
||||||
return this.expertInsurerService.setBranchActive(
|
return this.expertInsurerService.setBranchActive(
|
||||||
insurer.clientKey,
|
insurer.clientKey,
|
||||||
branchId,
|
branchId,
|
||||||
|
|||||||
@@ -263,8 +263,6 @@ export function buildClaimDetailsV2OwnerGuidance(
|
|||||||
shape.mixedFactorAndPrice &&
|
shape.mixedFactorAndPrice &&
|
||||||
!claim.evaluation?.ownerPricedPartsApproval?.signedAt
|
!claim.evaluation?.ownerPricedPartsApproval?.signedAt
|
||||||
) {
|
) {
|
||||||
const ow = objectionWindowForOwner(claim);
|
|
||||||
const allowObj = ow.pricingEligible;
|
|
||||||
return {
|
return {
|
||||||
phaseKey: "SIGN_PRICED_LINES",
|
phaseKey: "SIGN_PRICED_LINES",
|
||||||
headline: "Sign acceptance of priced lines",
|
headline: "Sign acceptance of priced lines",
|
||||||
@@ -278,13 +276,12 @@ export function buildClaimDetailsV2OwnerGuidance(
|
|||||||
"Multipart sign + agree + branchId",
|
"Multipart sign + agree + branchId",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
objectionAllowed: allowObj,
|
objectionAllowed,
|
||||||
objectionHint: objectionHintWhen(allowObj),
|
objectionHint,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** NEEDS_REVISION at INSURER_REVIEW without mixed gate — all-factor initial sign not used; fallback */
|
/** NEEDS_REVISION at INSURER_REVIEW without mixed gate — all-factor initial sign not used; fallback */
|
||||||
const allowObj = objectionWindowForOwner(claim).pricingEligible;
|
|
||||||
return {
|
return {
|
||||||
phaseKey: "INSURER_REVIEW_NEEDS_REVISION",
|
phaseKey: "INSURER_REVIEW_NEEDS_REVISION",
|
||||||
headline: "Insurer approval — action pending",
|
headline: "Insurer approval — action pending",
|
||||||
@@ -298,13 +295,12 @@ export function buildClaimDetailsV2OwnerGuidance(
|
|||||||
"Sign if prompted by app state",
|
"Sign if prompted by app state",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
objectionAllowed: allowObj,
|
objectionAllowed,
|
||||||
objectionHint: objectionHintWhen(allowObj),
|
objectionHint,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cs === ClaimStatus.APPROVED && !claim.evaluation?.ownerInsurerApproval?.signedAt) {
|
if (cs === ClaimStatus.APPROVED && !claim.evaluation?.ownerInsurerApproval?.signedAt) {
|
||||||
const allowObj = objectionWindowForOwner(claim).pricingEligible;
|
|
||||||
return {
|
return {
|
||||||
phaseKey: "FINAL_SIGN_OR_REJECT",
|
phaseKey: "FINAL_SIGN_OR_REJECT",
|
||||||
headline: "Accept or reject final pricing",
|
headline: "Accept or reject final pricing",
|
||||||
@@ -323,8 +319,8 @@ export function buildClaimDetailsV2OwnerGuidance(
|
|||||||
"Dispute priced lines before signing",
|
"Dispute priced lines before signing",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
objectionAllowed: allowObj,
|
objectionAllowed,
|
||||||
objectionHint: objectionHintWhen(allowObj),
|
objectionHint,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -367,8 +367,7 @@ export class InquiryRefreshService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
next.insurance.policyNumber =
|
next.insurance.policyNumber =
|
||||||
mapped.LastCompanyDocumentNumber ||
|
mapped.PrntPlcyCmpDocNo ||
|
||||||
mapped.insuranceNumber ||
|
|
||||||
next.insurance.policyNumber;
|
next.insurance.policyNumber;
|
||||||
next.insurance.company =
|
next.insurance.company =
|
||||||
mapped.companyPersianName || mapped.CompanyName || next.insurance.company;
|
mapped.companyPersianName || mapped.CompanyName || next.insurance.company;
|
||||||
|
|||||||
@@ -1323,7 +1323,7 @@ export class RequestManagementService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!party.insurance) party.insurance = {} as any;
|
if (!party.insurance) party.insurance = {} as any;
|
||||||
party.insurance.policyNumber = inquiryMapped?.insuranceNumber;
|
party.insurance.policyNumber = inquiryMapped?.PrntPlcyCmpDocNo;
|
||||||
party.insurance.company = clientName;
|
party.insurance.company = clientName;
|
||||||
party.insurance.financialCeiling = inquiryMapped?.FinancialCvrCptl;
|
party.insurance.financialCeiling = inquiryMapped?.FinancialCvrCptl;
|
||||||
party.insurance.startDate = inquiryMapped?.IssueDate;
|
party.insurance.startDate = inquiryMapped?.IssueDate;
|
||||||
|
|||||||
Reference in New Issue
Block a user