diff --git a/src/helpers/date-jalali.ts b/src/helpers/date-jalali.ts index 9fc6f66..ad64f2e 100644 --- a/src/helpers/date-jalali.ts +++ b/src/helpers/date-jalali.ts @@ -1,3 +1,5 @@ +import * as jMoment from "jalali-moment"; + /** * Converts an ISO date string or Date to Jalali (Persian) date and time. * @param input - ISO date string (e.g. 2026-02-08T13:51:20.747+00:00) or Date @@ -12,6 +14,66 @@ export function toJalaliDateAndTime( return [dateStr, timeStr]; } +/** + * Converts a Jalali (Persian) date in any of the common shapes used across + * this codebase to a Gregorian `YYYY-MM-DD` string. + * + * Accepted input shapes: + * - number `13770624` (packed `YYYYMMDD`) + * - string `"13770624"` / `"1377-06-24"` / `"1377/06/24"` / `"1377/6/24"` + * - already-Gregorian `YYYY-MM-DD` strings are returned untouched as long as + * they parse (we treat them as Gregorian only when the year is clearly + * Gregorian, i.e. >= 1900). Otherwise the year is treated as Jalali. + * + * Returns `null` when the input cannot be parsed into a valid Jalali date. + */ +export function jalaliToGregorianDate( + input: string | number | null | undefined, +): string | null { + if (input === null || input === undefined) return null; + + const raw = + typeof input === "number" ? String(input) : String(input).trim(); + if (!raw) return null; + + let year = 0; + let month = 0; + let day = 0; + + const separated = raw.match(/^(\d{4})[\-/](\d{1,2})[\-/](\d{1,2})$/); + if (separated) { + year = parseInt(separated[1], 10); + month = parseInt(separated[2], 10); + day = parseInt(separated[3], 10); + } else { + const digits = raw.replace(/\D/g, ""); + if (digits.length === 8) { + year = parseInt(digits.slice(0, 4), 10); + month = parseInt(digits.slice(4, 6), 10); + day = parseInt(digits.slice(6, 8), 10); + } else { + return null; + } + } + + if (!year || !month || !day) return null; + + // If the year already looks Gregorian (>= 1900), assume the caller already + // sent a Gregorian date and just normalise the formatting. + if (year >= 1900) { + const mm = String(month).padStart(2, "0"); + const dd = String(day).padStart(2, "0"); + const m = jMoment(`${year}-${mm}-${dd}`, "YYYY-MM-DD"); + return m.isValid() ? m.format("YYYY-MM-DD") : null; + } + + const mm = String(month).padStart(2, "0"); + const dd = String(day).padStart(2, "0"); + const jm = jMoment(`${year}-${mm}-${dd}`, "jYYYY-jMM-jDD"); + if (!jm.isValid()) return null; + return jm.format("YYYY-MM-DD"); +} + /** * Converts a Date to Jalali date string (e.g. 1404/11/24). */ diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index 3b3df8b..7100100 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -870,15 +870,24 @@ export class RequestManagementService { } // ---- External inquiry 2: personal identity check (insurer/driver nationalCode + birthDate) ---- + // The form sends the birthday as a Jalali date in any of these shapes: + // - number 13770624 (packed YYYYMMDD) + // - string "1377-06-24" / "1377/06/24" / "13770624" + // We forward it as-is; sandHubService.getPersonalInquiry() handles the + // Jalali → Gregorian conversion required by the external API. const personalNationalCode = body.nationalCodeOfInsurer || body.nationalCodeOfDriver; - const birthDateRaw = - body.insurerBirthday ?? body.driverBirthday ?? null; - const birthDateDigits = String(birthDateRaw ?? "") - .replace(/\D/g, "") - .trim(); - const personalBirthDate = Number(birthDateDigits); - if (!personalNationalCode || !Number.isFinite(personalBirthDate) || personalBirthDate <= 0) { + const personalBirthDate: number | string | null = + (body.insurerBirthday ?? body.driverBirthday ?? null) as + | number + | string + | null; + if ( + !personalNationalCode || + personalBirthDate === null || + personalBirthDate === undefined || + String(personalBirthDate).trim() === "" + ) { throw new BadRequestException( "Valid nationalCode and birthDate are required for personal inquiry.", ); diff --git a/src/sand-hub/sand-hub.service.ts b/src/sand-hub/sand-hub.service.ts index 6505ac6..8149206 100644 --- a/src/sand-hub/sand-hub.service.ts +++ b/src/sand-hub/sand-hub.service.ts @@ -13,6 +13,7 @@ import axios from "axios"; import { SandHubDbService } from "src/sand-hub/entity/db-service/sand-hub.db.service"; import { SandHubModel } from "src/sand-hub/entity/schema/sand-hub.schema"; import { SandHubDetailDto } from "./dto/sand-hub.dto"; +import { jalaliToGregorianDate } from "src/helpers/date-jalali"; @Injectable() export class SandHubService { @@ -473,13 +474,29 @@ export class SandHubService { } } - async getPersonalInquiry(nationalCode: string, birthDate: number) { + /** + * Personal identity check against the Tejarat hub. The upstream gateway only + * accepts a Gregorian birthdate in `YYYY-MM-DD` form, but every caller in + * this codebase has the value as a Jalali date (number `13770624` or string + * `"1377-06-24"`/`"1377/06/24"`). We convert here so callers don't have to. + */ + async getPersonalInquiry( + nationalCode: string, + birthDate: number | string, + ) { try { - const requestUrl = `${process.env.SANDHUB_BASE_URL}/personal-inquiry/asia`; + const requestUrl = `${process.env.SANDHUB_BASE_URL}/personal-inquiry/tejarat-no`; + + const gregorianBirthdate = jalaliToGregorianDate(birthDate); + if (!gregorianBirthdate) { + throw new BadRequestException( + `Invalid birth date for personal inquiry: ${birthDate}. Expected a Jalali date (e.g. 13770624 or "1377-06-24").`, + ); + } + const requestPayload = { - nin: nationalCode, - birthDate: birthDate, - persianBirthDate: "", + nationalCode, + birthdate: gregorianBirthdate, }; const response = await this.makeSandHubRequest( @@ -494,6 +511,12 @@ export class SandHubService { } return response.data; } catch (err) { + if ( + err instanceof BadRequestException || + err instanceof NotFoundException + ) { + throw err; + } throw new Error(`Error in finding personal inquiry: ${err}`); } }