diff --git a/src/request-management/request-management.car-body-client.spec.ts b/src/request-management/request-management.car-body-client.spec.ts new file mode 100644 index 0000000..3075890 --- /dev/null +++ b/src/request-management/request-management.car-body-client.spec.ts @@ -0,0 +1,25 @@ +import { RequestManagementService } from "./request-management.service"; + +describe("RequestManagementService CAR_BODY insurer client", () => { + const previousClientId = process.env.CLIENT_ID; + + afterEach(() => { + if (previousClientId === undefined) delete process.env.CLIENT_ID; + else process.env.CLIENT_ID = previousClientId; + }); + + it("uses the deployment insurer when the processed body lookup has no company id", async () => { + process.env.CLIENT_ID = "8"; + const service = Object.create(RequestManagementService.prototype) as any; + service.clientService = { + findOne: jest.fn().mockResolvedValue({ _id: "body-client-8" }), + }; + + await expect( + service.resolveCarBodyPolicyClientId({ companyId: null }), + ).resolves.toBe("body-client-8"); + expect(service.clientService.findOne).toHaveBeenCalledWith({ + clientCode: 8, + }); + }); +}); diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index a877168..072f750 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -168,6 +168,43 @@ export class RequestManagementService { ); } + /** + * CAR_BODY ownership is the deployment insurer, not the insurer returned by + * the preceding third-party lookup. Processed Parsian responses have no + * company id, so resolve the configured client from CLIENT_ID explicitly. + */ + private async resolveCarBodyPolicyClientId( + mapped: Record, + ): Promise { + const configuredCode = Number(process.env.CLIENT_ID); + if (!Number.isFinite(configuredCode)) { + throw new InternalServerErrorException( + "CLIENT_ID must be configured to save CAR_BODY policy ownership.", + ); + } + + let client: any = await this.clientService.findOne({ + clientCode: configuredCode, + }); + if (!client) { + const companyName = mapped.CompanyName ?? mapped.companyPersianName; + if (typeof companyName === "string" && companyName.trim()) { + client = await this.clientService.findOrCreateClientByCompanyCode( + configuredCode, + companyName, + ); + } + } + + const clientId = (client as any)?._id ?? (client as any)?._doc?._id; + if (!clientId) { + throw new InternalServerErrorException( + "Configured CAR_BODY insurer client could not be resolved.", + ); + } + return clientId; + } + private stepKeyToPartyRole(stepKey: WorkflowStep): PartyRole { if (String(stepKey).startsWith("FIRST_")) return PartyRole.FIRST; if (String(stepKey).startsWith("SECOND_")) return PartyRole.SECOND; @@ -1624,30 +1661,7 @@ export class RequestManagementService { hasEndorsement: m.hasEndorsement ?? null, }; - // ← THE FIX: overwrite clientId with car-body insurer's clientId - // For CAR_BODY files the relevant insurer is the one covering the car body, - // not the third-party liability insurer resolved earlier in this function. - const carBodyCompanyCode = m.companyId ?? m.CompanyCode; - const carBodyCompanyName = m.CompanyName ?? m.companyPersianName; - - if (carBodyCompanyCode && carBodyCompanyName) { - const carBodyClient = - await this.clientService.findOrCreateClientByCompanyCode( - carBodyCompanyCode, - carBodyCompanyName, - ); - - const carBodyClientId = - (carBodyClient as any)?._id ?? (carBodyClient as any)?._doc?._id; - - if (carBodyClientId) { - // Overwrite the third-party clientId set earlier in this function - party.person.clientId = carBodyClientId; - this.logger.log( - `[CAR_BODY] Overriding party clientId with car-body insurer clientId=${carBodyClientId} companyCode=${carBodyCompanyCode} for request=${req._id}`, - ); - } - } + party.person.clientId = await this.resolveCarBodyPolicyClientId(m); } // Advance workflow @@ -2021,18 +2035,7 @@ export class RequestManagementService { lossDocuments: m.lossDocuments ?? [], }; - const carBodyCompanyCode = m.companyId ?? m.CompanyCode; - const carBodyCompanyName = m.CompanyName ?? m.companyPersianName; - if (carBodyCompanyCode && carBodyCompanyName) { - const carBodyClient = - await this.clientService.findOrCreateClientByCompanyCode( - carBodyCompanyCode, - carBodyCompanyName, - ); - const carBodyClientId = - (carBodyClient as any)?._id ?? (carBodyClient as any)?._doc?._id; - if (carBodyClientId) party.person.clientId = carBodyClientId; - } + party.person.clientId = await this.resolveCarBodyPolicyClientId(m); } catch (err: any) { this.logger.error( `[CAR_BODY] VIN inquiry failed for request=${req._id}: ${err?.message || err}`, @@ -3164,6 +3167,8 @@ export class RequestManagementService { setFields[ "firstPartyDetails.firstPartyCarBodyInsuranceDetail.source" ] = carBodyInquiry.source; + setFields[`${partyDetails}.${partyType}Client.clientId`] = + await this.resolveCarBodyPolicyClientId(carBodyInfo); } // Build final update payload with proper MongoDB operators @@ -6410,17 +6415,6 @@ export class RequestManagementService { ); } - // Gate stale CAR_BODY submissions using the resolved client's window - // (V2 expert-initiated path always supplies accidentDate/accidentTime - // via formData.expertDescription). - if (formData?.expertDescription?.accidentDate) { - await this.assertCarBodyAccidentWithinWindow({ - clientId: (client as any)?._id, - accidentDate: formData.expertDescription.accidentDate, - accidentTime: formData.expertDescription.accidentTime, - }); - } - const carBodyInquiry = await this.sandHubService.getCarBodyInquiry({ nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, plate: firstPartyPlate.plate, @@ -6437,6 +6431,19 @@ export class RequestManagementService { mapped: carBodyInfo, }, ); + const carBodyClientId = await this.resolveCarBodyPolicyClientId( + carBodyInfo, + ); + + // Gate stale CAR_BODY submissions against the body-policy insurer, not + // the unrelated third-party insurer resolved above. + if (formData?.expertDescription?.accidentDate) { + await this.assertCarBodyAccidentWithinWindow({ + clientId: carBodyClientId, + accidentDate: formData.expertDescription.accidentDate, + accidentTime: formData.expertDescription.accidentTime, + }); + } const firstParty: any = { role: PartyRole.FIRST, @@ -6445,7 +6452,7 @@ export class RequestManagementService { phoneNumber: normalizeIranMobile(formData.firstPartyPhoneNumber) ?? formData.firstPartyPhoneNumber, - clientId: (client as any)?._id ?? (client as any)?._doc?._id, + clientId: carBodyClientId, nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, nationalCodeOfDriver: firstPartyPlate.nationalCodeOfDriver, insurerLicense: firstPartyPlate.insurerLicense, @@ -7725,6 +7732,8 @@ export class RequestManagementService { raw: carBodyInquiry.raw, source: carBodyInquiry.source, }; + firstPartyDetails.firstPartyClient.clientId = + await this.resolveCarBodyPolicyClientId(carBodyInfo); // Update the firstPartyDetails in the payload with all plate data updatePayload.$set.firstPartyDetails = firstPartyDetails; @@ -8988,21 +8997,9 @@ export class RequestManagementService { lossDocuments: m.lossDocuments ?? [], hasEndorsement: m.hasEndorsement ?? null, }; - const cbCompanyCode = m.companyId ?? m.CompanyCode; - const cbCompanyName = m.CompanyName ?? m.companyPersianName; - if (cbCompanyCode && cbCompanyName) { - const cbClient = - await this.clientService.findOrCreateClientByCompanyCode( - Number(cbCompanyCode), - String(cbCompanyName), - ); - const cbClientId = - (cbClient as any)?._id ?? (cbClient as any)?._doc?._id; - if (cbClientId) { - party.person.clientId = cbClientId; - clientId = String(cbClientId); - } - } + const carBodyClientId = await this.resolveCarBodyPolicyClientId(m); + party.person.clientId = carBodyClientId; + clientId = String(carBodyClientId); } catch (err: any) { this.logger.error( `[V3] car body inquiry failed for request=${req._id}: ${err?.message || err}`, @@ -9838,21 +9835,9 @@ export class RequestManagementService { lossDocuments: m.lossDocuments ?? [], hasEndorsement: m.hasEndorsement ?? null, }; - const cbCompanyCode = m.companyId ?? m.CompanyCode; - const cbCompanyName = m.CompanyName ?? m.companyPersianName; - if (cbCompanyCode && cbCompanyName) { - const cbClient = - await this.clientService.findOrCreateClientByCompanyCode( - Number(cbCompanyCode), - String(cbCompanyName), - ); - const cbClientId = - (cbClient as any)?._id ?? (cbClient as any)?._doc?._id; - if (cbClientId) { - party.person.clientId = cbClientId; - clientId = String(cbClientId); - } - } + const carBodyClientId = await this.resolveCarBodyPolicyClientId(m); + party.person.clientId = carBodyClientId; + clientId = String(carBodyClientId); } catch (err: any) { this.logger.error( `[V3-VIN] car body inquiry failed for request=${req._id}: ${err?.message || err}`,