forked from Yara724/api
Merge pull request 'main' (#162) from s.hajizadeh/yara724api:main into main
Reviewed-on: Yara724/api#162
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
# External API Curl Guide
|
# External API Curl Guide
|
||||||
|
|
||||||
This file documents outbound HTTP calls made by the app or maintenance scripts.
|
This file documents outbound HTTP calls made by the app or maintenance scripts.
|
||||||
Use placeholder values for secrets, tokens, IDs, plate values, and payloads before running any curl.
|
Client credentials that are hardcoded in the codebase are filled in below. Keep
|
||||||
|
placeholders only for runtime data such as national codes, plate values, tokens
|
||||||
|
returned by login calls, and payload files.
|
||||||
|
|
||||||
## Common Notes
|
## Common Notes
|
||||||
|
|
||||||
@@ -32,29 +34,73 @@ Used by:
|
|||||||
2. Login with `appToken` to get `authenticationToken`.
|
2. Login with `appToken` to get `authenticationToken`.
|
||||||
3. Call lookup, policy inquiry, or submit endpoint with `authenticationToken`, `CorpId`, `ContractId`, and `Location`.
|
3. Call lookup, policy inquiry, or submit endpoint with `authenticationToken`, `CorpId`, `ContractId`, and `Location`.
|
||||||
|
|
||||||
|
### Auth Script
|
||||||
|
|
||||||
|
Use this when you only need fresh Fanavaran tokens and do not want to copy the
|
||||||
|
curl commands manually:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/fanavaran-auth.sh tejaratno
|
||||||
|
scripts/fanavaran-auth.sh parsian
|
||||||
|
```
|
||||||
|
|
||||||
|
The script stores raw responses and reusable variables under
|
||||||
|
`files/fanavaran-auth/<client>/`. For example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
source files/fanavaran-auth/tejaratno/tokens.env
|
||||||
|
curl -X GET "$FANAVARAN_BIME_URL/car/base-info/accident-causes" \
|
||||||
|
-H "authenticationToken: $AUTHENTICATION_TOKEN" \
|
||||||
|
-H "CorpId: $CORP_ID" \
|
||||||
|
-H "ContractId: $CONTRACT_ID" \
|
||||||
|
-H "Location: $LOCATION" \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
```
|
||||||
|
|
||||||
### Tenant Credentials
|
### Tenant Credentials
|
||||||
|
|
||||||
The app supports these Fanavaran client profiles:
|
The app supports these Fanavaran client profiles:
|
||||||
|
|
||||||
| Client | appname | secret | userName | password | CorpId | ContractId | Location |
|
| Client | appname | secret | userName | password | CorpId | ContractId | Location |
|
||||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||||
| tejaratno | from `src/core/config/fanavaran-client.config.ts` | hardcoded in source | hardcoded in source | hardcoded in source | `3539` | `263` | `100` |
|
| tejaratno | `fanhab` | `5Fa@N#A2B` | `fanhabUser` | `Fan#@2U$3er` | `3539` | `263` | `100` |
|
||||||
| parsian | from `src/core/config/fanavaran-client.config.ts` | hardcoded in source | hardcoded in source | hardcoded in source | `543` | `28` | `210050` |
|
| parsian | `ParsianService` | `P@r30@n$erv!ce` | `ParsianServiceUser` | `P@r30@n123` | `543` | `28` | `210050` |
|
||||||
|
|
||||||
Set them as shell variables before running:
|
Set the client variables before running. These values come from
|
||||||
|
`src/core/config/fanavaran-client.config.ts` and match
|
||||||
|
`src/claim-request-management/claim-request-management.service.ts`.
|
||||||
|
|
||||||
|
Tejaratno:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
APP_NAME="<appname>"
|
FANAVARAN_CLIENT="tejaratno"
|
||||||
APP_SECRET="<secret>"
|
APP_NAME='fanhab'
|
||||||
FANAVARAN_USERNAME="<userName>"
|
APP_SECRET='5Fa@N#A2B'
|
||||||
FANAVARAN_PASSWORD="<password>"
|
FANAVARAN_USERNAME='fanhabUser'
|
||||||
CORP_ID="<CorpId>"
|
FANAVARAN_PASSWORD='Fan#@2U$3er'
|
||||||
CONTRACT_ID="<ContractId>"
|
CORP_ID='3539'
|
||||||
LOCATION="<Location>"
|
CONTRACT_ID='263'
|
||||||
|
LOCATION='100'
|
||||||
|
```
|
||||||
|
|
||||||
|
Parsian:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
FANAVARAN_CLIENT="parsian"
|
||||||
|
APP_NAME='ParsianService'
|
||||||
|
APP_SECRET='P@r30@n$erv!ce'
|
||||||
|
FANAVARAN_USERNAME='ParsianServiceUser'
|
||||||
|
FANAVARAN_PASSWORD='P@r30@n123'
|
||||||
|
CORP_ID='543'
|
||||||
|
CONTRACT_ID='28'
|
||||||
|
LOCATION='210050'
|
||||||
```
|
```
|
||||||
|
|
||||||
### 1. Get App Token
|
### 1. Get App Token
|
||||||
|
|
||||||
|
The app sends an empty string body, deletes `Content-Type`, and keeps
|
||||||
|
`Content-Length: 0`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -i -X POST "$FANAVARAN_BASE_URL/EITAuthentication/GetAppToken" \
|
curl -i -X POST "$FANAVARAN_BASE_URL/EITAuthentication/GetAppToken" \
|
||||||
-H "appname: $APP_NAME" \
|
-H "appname: $APP_NAME" \
|
||||||
@@ -65,11 +111,21 @@ curl -i -X POST "$FANAVARAN_BASE_URL/EITAuthentication/GetAppToken" \
|
|||||||
The token is returned in a response header named `appToken` or `apptoken`.
|
The token is returned in a response header named `appToken` or `apptoken`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
APP_TOKEN="<response appToken header>"
|
curl -sS -D /tmp/fanavaran-app-token.headers -o /tmp/fanavaran-app-token.body \
|
||||||
|
-X POST "$FANAVARAN_BASE_URL/EITAuthentication/GetAppToken" \
|
||||||
|
-H "appname: $APP_NAME" \
|
||||||
|
-H "secret: $APP_SECRET" \
|
||||||
|
-H "Content-Length: 0"
|
||||||
|
APP_TOKEN="$(awk -F': ' 'tolower($1)=="apptoken" {gsub(/\r/,"",$2); print $2}' /tmp/fanavaran-app-token.headers)"
|
||||||
|
printf 'APP_TOKEN=%s\n' "$APP_TOKEN"
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Login
|
### 2. Login
|
||||||
|
|
||||||
|
Use the `APP_TOKEN` returned by the immediately previous GetAppToken request.
|
||||||
|
Do not reuse an old app token pasted from logs or another machine; the app does
|
||||||
|
not do that.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -i -X POST "$FANAVARAN_BASE_URL/EITAuthentication/Login" \
|
curl -i -X POST "$FANAVARAN_BASE_URL/EITAuthentication/Login" \
|
||||||
-H "appToken: $APP_TOKEN" \
|
-H "appToken: $APP_TOKEN" \
|
||||||
@@ -81,7 +137,95 @@ curl -i -X POST "$FANAVARAN_BASE_URL/EITAuthentication/Login" \
|
|||||||
The token is returned in a response header or body field named `authenticationToken`, `authenticationtoken`, or `authentication_token`.
|
The token is returned in a response header or body field named `authenticationToken`, `authenticationtoken`, or `authentication_token`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
AUTHENTICATION_TOKEN="<response authenticationToken>"
|
curl -sS -D /tmp/fanavaran-login.headers -o /tmp/fanavaran-login.body \
|
||||||
|
-X POST "$FANAVARAN_BASE_URL/EITAuthentication/Login" \
|
||||||
|
-H "appToken: $APP_TOKEN" \
|
||||||
|
-H "userName: $FANAVARAN_USERNAME" \
|
||||||
|
-H "password: $FANAVARAN_PASSWORD" \
|
||||||
|
-H "Content-Length: 0"
|
||||||
|
AUTHENTICATION_TOKEN="$(awk -F': ' 'tolower($1)=="authenticationtoken" {gsub(/\r/,"",$2); print $2}' /tmp/fanavaran-login.headers)"
|
||||||
|
if [ -z "$AUTHENTICATION_TOKEN" ]; then
|
||||||
|
AUTHENTICATION_TOKEN="$(node -e 'const fs=require("fs"); const body=fs.readFileSync("/tmp/fanavaran-login.body","utf8"); try { const json=JSON.parse(body); console.log(json.authenticationToken || json.authenticationtoken || json.authentication_token || ""); } catch { console.log(""); }')"
|
||||||
|
fi
|
||||||
|
printf 'AUTHENTICATION_TOKEN=%s\n' "$AUTHENTICATION_TOKEN"
|
||||||
|
```
|
||||||
|
|
||||||
|
If login returns `نام کاربر یا رمز عبور صحیح نیست` for `tejaratno`, first check
|
||||||
|
that `APP_TOKEN` was generated with `appname: fanhab` and `secret: 5Fa@N#A2B` in
|
||||||
|
the same sequence. The runtime code calls `GetAppToken` first, then passes that
|
||||||
|
fresh header value to `Login`; it does not use a static value such as
|
||||||
|
`182197f6-7b41-47b4-9b18-5bfcbc027f2e`.
|
||||||
|
|
||||||
|
### Ready-To-Run Auth Sequences
|
||||||
|
|
||||||
|
Tejaratno:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
FANAVARAN_BASE_URL="https://apimanager.iraneit.com/BimeApiManager/api"
|
||||||
|
FANAVARAN_BIME_URL="$FANAVARAN_BASE_URL/BimeApi/v2.0"
|
||||||
|
FANAVARAN_CLIENT="tejaratno"
|
||||||
|
APP_NAME='fanhab'
|
||||||
|
APP_SECRET='5Fa@N#A2B'
|
||||||
|
FANAVARAN_USERNAME='fanhabUser'
|
||||||
|
FANAVARAN_PASSWORD='Fan#@2U$3er'
|
||||||
|
CORP_ID='3539'
|
||||||
|
CONTRACT_ID='263'
|
||||||
|
LOCATION='100'
|
||||||
|
|
||||||
|
curl -sS -D /tmp/fanavaran-app-token.headers -o /tmp/fanavaran-app-token.body \
|
||||||
|
-X POST "$FANAVARAN_BASE_URL/EITAuthentication/GetAppToken" \
|
||||||
|
-H "appname: $APP_NAME" \
|
||||||
|
-H "secret: $APP_SECRET" \
|
||||||
|
-H "Content-Length: 0"
|
||||||
|
APP_TOKEN="$(awk -F': ' 'tolower($1)=="apptoken" {gsub(/\r/,"",$2); print $2}' /tmp/fanavaran-app-token.headers)"
|
||||||
|
|
||||||
|
curl -sS -D /tmp/fanavaran-login.headers -o /tmp/fanavaran-login.body \
|
||||||
|
-X POST "$FANAVARAN_BASE_URL/EITAuthentication/Login" \
|
||||||
|
-H "appToken: $APP_TOKEN" \
|
||||||
|
-H "userName: $FANAVARAN_USERNAME" \
|
||||||
|
-H "password: $FANAVARAN_PASSWORD" \
|
||||||
|
-H "Content-Length: 0"
|
||||||
|
AUTHENTICATION_TOKEN="$(awk -F': ' 'tolower($1)=="authenticationtoken" {gsub(/\r/,"",$2); print $2}' /tmp/fanavaran-login.headers)"
|
||||||
|
if [ -z "$AUTHENTICATION_TOKEN" ]; then
|
||||||
|
AUTHENTICATION_TOKEN="$(node -e 'const fs=require("fs"); const body=fs.readFileSync("/tmp/fanavaran-login.body","utf8"); try { const json=JSON.parse(body); console.log(json.authenticationToken || json.authenticationtoken || json.authentication_token || ""); } catch { console.log(""); }')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'APP_TOKEN=%s\nAUTHENTICATION_TOKEN=%s\n' "$APP_TOKEN" "$AUTHENTICATION_TOKEN"
|
||||||
|
```
|
||||||
|
|
||||||
|
Parsian:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
FANAVARAN_BASE_URL="https://apimanager.iraneit.com/BimeApiManager/api"
|
||||||
|
FANAVARAN_BIME_URL="$FANAVARAN_BASE_URL/BimeApi/v2.0"
|
||||||
|
FANAVARAN_CLIENT="parsian"
|
||||||
|
APP_NAME='ParsianService'
|
||||||
|
APP_SECRET='P@r30@n$erv!ce'
|
||||||
|
FANAVARAN_USERNAME='ParsianServiceUser'
|
||||||
|
FANAVARAN_PASSWORD='P@r30@n123'
|
||||||
|
CORP_ID='543'
|
||||||
|
CONTRACT_ID='28'
|
||||||
|
LOCATION='210050'
|
||||||
|
|
||||||
|
curl -sS -D /tmp/fanavaran-app-token.headers -o /tmp/fanavaran-app-token.body \
|
||||||
|
-X POST "$FANAVARAN_BASE_URL/EITAuthentication/GetAppToken" \
|
||||||
|
-H "appname: $APP_NAME" \
|
||||||
|
-H "secret: $APP_SECRET" \
|
||||||
|
-H "Content-Length: 0"
|
||||||
|
APP_TOKEN="$(awk -F': ' 'tolower($1)=="apptoken" {gsub(/\r/,"",$2); print $2}' /tmp/fanavaran-app-token.headers)"
|
||||||
|
|
||||||
|
curl -sS -D /tmp/fanavaran-login.headers -o /tmp/fanavaran-login.body \
|
||||||
|
-X POST "$FANAVARAN_BASE_URL/EITAuthentication/Login" \
|
||||||
|
-H "appToken: $APP_TOKEN" \
|
||||||
|
-H "userName: $FANAVARAN_USERNAME" \
|
||||||
|
-H "password: $FANAVARAN_PASSWORD" \
|
||||||
|
-H "Content-Length: 0"
|
||||||
|
AUTHENTICATION_TOKEN="$(awk -F': ' 'tolower($1)=="authenticationtoken" {gsub(/\r/,"",$2); print $2}' /tmp/fanavaran-login.headers)"
|
||||||
|
if [ -z "$AUTHENTICATION_TOKEN" ]; then
|
||||||
|
AUTHENTICATION_TOKEN="$(node -e 'const fs=require("fs"); const body=fs.readFileSync("/tmp/fanavaran-login.body","utf8"); try { const json=JSON.parse(body); console.log(json.authenticationToken || json.authenticationtoken || json.authentication_token || ""); } catch { console.log(""); }')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'APP_TOKEN=%s\nAUTHENTICATION_TOKEN=%s\n' "$APP_TOKEN" "$AUTHENTICATION_TOKEN"
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3A. Lookup Endpoints
|
### 3A. Lookup Endpoints
|
||||||
@@ -167,6 +311,8 @@ Default base URL:
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
TEJARAT_INQUIRY_BASE_URL="${TEJARAT_INQUIRY_BASE_URL:-http://82.99.202.245:3027}"
|
TEJARAT_INQUIRY_BASE_URL="${TEJARAT_INQUIRY_BASE_URL:-http://82.99.202.245:3027}"
|
||||||
|
TEJARAT_INQUIRY_EMAIL='xxx@example.com'
|
||||||
|
TEJARAT_INQUIRY_PASSWORD='123321'
|
||||||
```
|
```
|
||||||
|
|
||||||
Used by `src/sand-hub/sand-hub.service.ts` for third-party plate and car-body plate inquiries when ESG is not selected.
|
Used by `src/sand-hub/sand-hub.service.ts` for third-party plate and car-body plate inquiries when ESG is not selected.
|
||||||
@@ -311,8 +457,10 @@ Used by `src/sand-hub/sand-hub.service.ts` for legacy inquiry flows.
|
|||||||
Environment:
|
Environment:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
SANHUB_URL_LOGIN="<login URL>"
|
SANHUB_BASE_URL='http://82.99.202.245:3027'
|
||||||
SANHUB_BASE_URL="<base URL>"
|
SANHUB_URL_LOGIN='http://82.99.202.245:3027/user/login'
|
||||||
|
SANHUB_USERNAME='default@admin.com'
|
||||||
|
SANHUB_PASSWORD='123321'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Sequence
|
### Sequence
|
||||||
@@ -415,7 +563,7 @@ curl -X POST "$SANHUB_BASE_URL/sheba/sheba-tejaratno" \
|
|||||||
Used by `src/claim-request-management/claim-request-management.service.ts`.
|
Used by `src/claim-request-management/claim-request-management.service.ts`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
MAP_IR_API_KEY="<x-api-key>"
|
MAP_IR_API_KEY='eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImI5ZDZjMThkNDRjZjc2OWI2Yjk1ODcyMGFjYmEzMmRiN2NhZjg0Zjk4OTRlMjZiZDg0Yzg3YjVlMzhlMTAyZDlkMWYxOGM5NjNmOTk4YjY2In0.eyJhdWQiOiIyMTcxOCIsImp0aSI6ImI5ZDZjMThkNDRjZjc2OWI2Yjk1ODcyMGFjYmEzMmRiN2NhZjg0Zjk4OTRlMjZiZDg0Yzg3YjVlMzhlMTAyZDlkMWYxOGM5NjNmOTk4YjY2IiwiaWF0IjoxNjgwNjA4NTkxLCJuYmYiOjE2ODA2MDg1OTEsImV4cCI6MTY4MzIwMDU5MSwic3ViIjoiIiwic2NvcGVzIjpbImJhc2ljIl19.rTviLd8b5yTHUDa3ODZyva593eMnL0d3XPg3sKkZxMOf_jNIH6lFQyIfbId-wsd1EAdsOdsL3CME_Y8t332PWJbxMNgnEq4Rf2IkClkvkSx6Sb5_4bmlhBM75zw2SmccvgbFUn4xkTOw0FT4vABC2Y3-MKctjMpmO8QOrVULSKt4psrmQhr7hBu7YRDnAAEc6muZ1VpRvdB1kqNKddoSIrfDaq6aDRJ-BNbGRAaFFvP_kH4cgSCKV4dU0TknL3mRKUiVy6_TDkjtzAN8fE2wsdvNo2pGTJPzKFsR2ipgGNTvB__g3bOnVpKsgFXPBH0e_Qa7ff1tZ3VGWy3jRNh9Lg'
|
||||||
LAT="35.6892"
|
LAT="35.6892"
|
||||||
LON="51.3890"
|
LON="51.3890"
|
||||||
|
|
||||||
@@ -431,7 +579,7 @@ curl -X GET "https://map.ir/fast-reverse?lat=$LAT&lon=$LON" \
|
|||||||
Used by `src/sms-orchestration/provider/kavenegar.service.ts`.
|
Used by `src/sms-orchestration/provider/kavenegar.service.ts`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
SMS_API_KEY="<kavenegar API key>"
|
SMS_API_KEY='75776C717969412B4B52306A5956462F4A714E6F6C65544D6A2B654B7566786E'
|
||||||
KAVENEGAR_BASE_URL="https://api.kavenegar.com/v1/$SMS_API_KEY"
|
KAVENEGAR_BASE_URL="https://api.kavenegar.com/v1/$SMS_API_KEY"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -462,9 +610,9 @@ Used by `src/sms-orchestration/provider/parsian-sms.gateway.ts`.
|
|||||||
`PARSIAN_SMS_URL` is expected to already include the provider URL prefix and query key before receptor. The app appends `=<receptor>&Message=<encoded message>`.
|
`PARSIAN_SMS_URL` is expected to already include the provider URL prefix and query key before receptor. The app appends `=<receptor>&Message=<encoded message>`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
PARSIAN_SMS_URL="<provider URL prefix>"
|
PARSIAN_SMS_URL='https://apigateway.parsianinsurance.com/api/SendSMS?ReceiverNumbers'
|
||||||
PARSIAN_API_KEY="<package API key>"
|
PARSIAN_API_KEY='be988c9c-dbd6-494e-9c04-944ecc6426bf'
|
||||||
PARSIAN_BASIC_TOKEN="<basic token>"
|
PARSIAN_BASIC_TOKEN='UGFyc2lhbkFQSTpQYXJzaWFuQHBpMjI='
|
||||||
RECEPTOR="09120000000"
|
RECEPTOR="09120000000"
|
||||||
MESSAGE="Hello"
|
MESSAGE="Hello"
|
||||||
|
|
||||||
@@ -494,7 +642,9 @@ curl -X GET "${CW_URL}price?hamrah"
|
|||||||
3. `POST $AI_URL_V2/services/car-damage/detector?version=ai-v7`
|
3. `POST $AI_URL_V2/services/car-damage/detector?version=ai-v7`
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
AI_URL_V2="<AI service base URL>"
|
AI_URL_V2='https://ai-gw.ittalie.ir'
|
||||||
|
AI_USERNAME='yara@gmail.io'
|
||||||
|
AI_PASSWORD='123321'
|
||||||
|
|
||||||
curl -X POST "$AI_URL_V2/auth/login" \
|
curl -X POST "$AI_URL_V2/auth/login" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
|
|||||||
143
scripts/fanavaran-auth.sh
Executable file
143
scripts/fanavaran-auth.sh
Executable file
@@ -0,0 +1,143 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'USAGE'
|
||||||
|
Usage:
|
||||||
|
scripts/fanavaran-auth.sh <tejaratno|parsian>
|
||||||
|
|
||||||
|
Calls Fanavaran GetAppToken, then Login with the returned appToken.
|
||||||
|
Outputs the appToken and authenticationToken, and writes raw responses to:
|
||||||
|
files/fanavaran-auth/<client>/
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
FANAVARAN_BASE_URL can override the default API Manager base URL.
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
client="${1:-}"
|
||||||
|
if [[ -z "$client" || "$client" == "-h" || "$client" == "--help" ]]; then
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$client" in
|
||||||
|
tejaratno)
|
||||||
|
app_name='fanhab'
|
||||||
|
app_secret='5Fa@N#A2B'
|
||||||
|
fanavaran_username='fanhabUser'
|
||||||
|
fanavaran_password='Fan#@2U$3er'
|
||||||
|
corp_id='3539'
|
||||||
|
contract_id='263'
|
||||||
|
location='100'
|
||||||
|
;;
|
||||||
|
parsian)
|
||||||
|
app_name='ParsianService'
|
||||||
|
app_secret='P@r30@n$erv!ce'
|
||||||
|
fanavaran_username='ParsianServiceUser'
|
||||||
|
fanavaran_password='P@r30@n123'
|
||||||
|
corp_id='543'
|
||||||
|
contract_id='28'
|
||||||
|
location='210050'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Unknown Fanavaran client: %s\n\n' "$client" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
base_url="${FANAVARAN_BASE_URL:-https://apimanager.iraneit.com/BimeApiManager/api}"
|
||||||
|
auth_dir="files/fanavaran-auth/$client"
|
||||||
|
mkdir -p "$auth_dir"
|
||||||
|
|
||||||
|
app_token_headers="$auth_dir/get-app-token.headers"
|
||||||
|
app_token_body="$auth_dir/get-app-token.body.json"
|
||||||
|
login_headers="$auth_dir/login.headers"
|
||||||
|
login_body="$auth_dir/login.body.json"
|
||||||
|
tokens_file="$auth_dir/tokens.env"
|
||||||
|
|
||||||
|
extract_header() {
|
||||||
|
local header_name="$1"
|
||||||
|
local header_file="$2"
|
||||||
|
awk -F': ' -v wanted="$header_name" '
|
||||||
|
tolower($1) == tolower(wanted) {
|
||||||
|
gsub(/\r/, "", $2)
|
||||||
|
print $2
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
' "$header_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_authentication_token_from_body() {
|
||||||
|
local body_file="$1"
|
||||||
|
node -e '
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = process.argv[1];
|
||||||
|
const body = fs.existsSync(path) ? fs.readFileSync(path, "utf8") : "";
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(body || "{}");
|
||||||
|
console.log(json.authenticationToken || json.authenticationtoken || json.authentication_token || "");
|
||||||
|
} catch {
|
||||||
|
console.log("");
|
||||||
|
}
|
||||||
|
' "$body_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
printf 'Fanavaran client: %s\n' "$client"
|
||||||
|
printf 'Base URL: %s\n\n' "$base_url"
|
||||||
|
|
||||||
|
printf '1. Calling GetAppToken...\n'
|
||||||
|
curl -sS -D "$app_token_headers" -o "$app_token_body" \
|
||||||
|
-X POST "$base_url/EITAuthentication/GetAppToken" \
|
||||||
|
-H "appname: $app_name" \
|
||||||
|
-H "secret: $app_secret" \
|
||||||
|
-H "Content-Length: 0"
|
||||||
|
|
||||||
|
app_token="$(extract_header "apptoken" "$app_token_headers")"
|
||||||
|
if [[ -z "$app_token" ]]; then
|
||||||
|
printf 'Failed to extract appToken from %s\n' "$app_token_headers" >&2
|
||||||
|
printf 'Response body is saved at %s\n' "$app_token_body" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '2. Calling Login...\n'
|
||||||
|
curl -sS -D "$login_headers" -o "$login_body" \
|
||||||
|
-X POST "$base_url/EITAuthentication/Login" \
|
||||||
|
-H "appToken: $app_token" \
|
||||||
|
-H "userName: $fanavaran_username" \
|
||||||
|
-H "password: $fanavaran_password" \
|
||||||
|
-H "Content-Length: 0"
|
||||||
|
|
||||||
|
authentication_token="$(extract_header "authenticationtoken" "$login_headers")"
|
||||||
|
if [[ -z "$authentication_token" ]]; then
|
||||||
|
authentication_token="$(extract_authentication_token_from_body "$login_body")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$authentication_token" ]]; then
|
||||||
|
printf 'Failed to extract authenticationToken from login response.\n' >&2
|
||||||
|
printf 'Headers: %s\n' "$login_headers" >&2
|
||||||
|
printf 'Body: %s\n' "$login_body" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "$tokens_file" <<TOKENS
|
||||||
|
FANAVARAN_CLIENT='$client'
|
||||||
|
FANAVARAN_BASE_URL='$base_url'
|
||||||
|
FANAVARAN_BIME_URL='$base_url/BimeApi/v2.0'
|
||||||
|
APP_TOKEN='$app_token'
|
||||||
|
AUTHENTICATION_TOKEN='$authentication_token'
|
||||||
|
CORP_ID='$corp_id'
|
||||||
|
CONTRACT_ID='$contract_id'
|
||||||
|
LOCATION='$location'
|
||||||
|
TOKENS
|
||||||
|
|
||||||
|
printf '\nDone.\n'
|
||||||
|
printf 'APP_TOKEN=%s\n' "$app_token"
|
||||||
|
printf 'AUTHENTICATION_TOKEN=%s\n' "$authentication_token"
|
||||||
|
printf 'CORP_ID=%s\n' "$corp_id"
|
||||||
|
printf 'CONTRACT_ID=%s\n' "$contract_id"
|
||||||
|
printf 'LOCATION=%s\n' "$location"
|
||||||
|
printf '\nSaved token variables: %s\n' "$tokens_file"
|
||||||
|
printf 'Saved raw GetAppToken response: %s, %s\n' "$app_token_headers" "$app_token_body"
|
||||||
|
printf 'Saved raw Login response: %s, %s\n' "$login_headers" "$login_body"
|
||||||
@@ -176,6 +176,7 @@ import {
|
|||||||
FanavaranAuditStatus,
|
FanavaranAuditStatus,
|
||||||
FanavaranAuditStep,
|
FanavaranAuditStep,
|
||||||
} from "src/fanavaran/schema/fanavaran-audit-log.schema";
|
} from "src/fanavaran/schema/fanavaran-audit-log.schema";
|
||||||
|
import { selectLatestActiveFanavaranPolicy } from "./fanavaran-policy-selection";
|
||||||
|
|
||||||
export interface FanavaranAutoSubmitResult {
|
export interface FanavaranAutoSubmitResult {
|
||||||
attempted: boolean;
|
attempted: boolean;
|
||||||
@@ -3438,17 +3439,13 @@ export class ClaimRequestManagementService {
|
|||||||
|
|
||||||
this.applyFanavaranDefaultFields(result);
|
this.applyFanavaranDefaultFields(result);
|
||||||
|
|
||||||
try {
|
|
||||||
const policyId = await input.resolvePolicyId();
|
const policyId = await input.resolvePolicyId();
|
||||||
if (policyId !== undefined && policyId !== null) {
|
if (policyId === undefined || policyId === null) {
|
||||||
result.PolicyId = policyId;
|
throw new BadRequestException(
|
||||||
}
|
`${input.logPrefix} PolicyId is required for Fanavaran submit. Policy inquiry returned no valid policy; contact the administrator.`,
|
||||||
} catch (error) {
|
|
||||||
this.logger.error(
|
|
||||||
`${input.logPrefix} Failed to get PolicyId from external API:`,
|
|
||||||
error,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
result.PolicyId = policyId;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -3567,15 +3564,18 @@ export class ClaimRequestManagementService {
|
|||||||
blameRequest,
|
blameRequest,
|
||||||
claimRequestId,
|
claimRequestId,
|
||||||
);
|
);
|
||||||
if (policyId) {
|
if (!policyId) {
|
||||||
result.PolicyId = policyId;
|
throw new BadRequestException(
|
||||||
|
`[Fanavaran Submit] PolicyId is required for Fanavaran submit. Policy inquiry returned no valid policy; contact the administrator.`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
result.PolicyId = policyId;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
`[Fanavaran Submit] Failed to get PolicyId from external API:`,
|
`[Fanavaran Submit] Failed to get PolicyId from external API:`,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
// Continue without PolicyId if API call fails
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -3866,11 +3866,7 @@ export class ClaimRequestManagementService {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const policyCount = Array.isArray(response.data)
|
const policyCount = Array.isArray(response.data) ? response.data.length : 0;
|
||||||
? response.data.length
|
|
||||||
: 0;
|
|
||||||
const lastPolicy =
|
|
||||||
policyCount > 0 ? response.data[policyCount - 1] : null;
|
|
||||||
|
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`${logPrefix} Policy inquiry response status=${response.status} count=${policyCount}`,
|
`${logPrefix} Policy inquiry response status=${response.status} count=${policyCount}`,
|
||||||
@@ -3882,20 +3878,11 @@ export class ClaimRequestManagementService {
|
|||||||
2,
|
2,
|
||||||
)}`,
|
)}`,
|
||||||
);
|
);
|
||||||
if (lastPolicy && typeof lastPolicy === "object") {
|
const selectedPolicy = selectLatestActiveFanavaranPolicy(response.data);
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`${logPrefix} Policy inquiry last policy keys: ${Object.keys(
|
`${logPrefix} Selected latest active policy PolicyId=${selectedPolicy.policyId} EndDate=${selectedPolicy.endDate}`,
|
||||||
lastPolicy,
|
|
||||||
).join(", ")}`,
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(response.data) && response.data.length > 0) {
|
|
||||||
const policyId = lastPolicy?.PolicyId;
|
|
||||||
if (policyId !== undefined && policyId !== null) {
|
|
||||||
this.logger.log(
|
|
||||||
`${logPrefix} Successfully retrieved PolicyId from last policy entry: ${policyId}`,
|
|
||||||
);
|
|
||||||
if (auditSession) {
|
if (auditSession) {
|
||||||
await this.fanavaranAuditService.recordStep({
|
await this.fanavaranAuditService.recordStep({
|
||||||
session: auditSession,
|
session: auditSession,
|
||||||
@@ -3904,34 +3891,15 @@ export class ClaimRequestManagementService {
|
|||||||
requestUrl: policyInquiryUrl,
|
requestUrl: policyInquiryUrl,
|
||||||
httpStatus: response.status,
|
httpStatus: response.status,
|
||||||
responseMeta: {
|
responseMeta: {
|
||||||
policyId,
|
policyId: selectedPolicy.policyId,
|
||||||
policyCount: response.data.length,
|
policyEndDate: selectedPolicy.endDate,
|
||||||
|
policyEndDateGregorian: selectedPolicy.endDateGregorian,
|
||||||
|
policyCount,
|
||||||
},
|
},
|
||||||
durationMs: Date.now() - startedAt,
|
durationMs: Date.now() - startedAt,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return policyId;
|
return selectedPolicy.policyId;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.warn(`${logPrefix} No PolicyId found in API response`);
|
|
||||||
if (auditSession) {
|
|
||||||
await this.fanavaranAuditService.recordStep({
|
|
||||||
session: auditSession,
|
|
||||||
step: FanavaranAuditStep.POLICY_INQUIRY,
|
|
||||||
status: FanavaranAuditStatus.SUCCESS,
|
|
||||||
requestUrl: policyInquiryUrl,
|
|
||||||
httpStatus: response.status,
|
|
||||||
responseMeta: {
|
|
||||||
policyId: null,
|
|
||||||
policyCount: Array.isArray(response.data)
|
|
||||||
? response.data.length
|
|
||||||
: 0,
|
|
||||||
},
|
|
||||||
durationMs: Date.now() - startedAt,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
error instanceof Error ? error.message : "unknown policy inquiry error";
|
error instanceof Error ? error.message : "unknown policy inquiry error";
|
||||||
@@ -3948,8 +3916,11 @@ export class ClaimRequestManagementService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`${logPrefix} Policy inquiry failed; continuing with empty PolicyId: ${errorMessage}`,
|
`${logPrefix} Policy inquiry failed: ${errorMessage}`,
|
||||||
);
|
);
|
||||||
|
if (error instanceof BadRequestException) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4011,6 +3982,9 @@ export class ClaimRequestManagementService {
|
|||||||
`[Fanavaran Submit] Error getting PolicyId from external API:`,
|
`[Fanavaran Submit] Error getting PolicyId from external API:`,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
|
if (error instanceof BadRequestException) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { BadRequestException } from "@nestjs/common";
|
||||||
|
import { selectLatestActiveFanavaranPolicy } from "./fanavaran-policy-selection";
|
||||||
|
|
||||||
|
describe("selectLatestActiveFanavaranPolicy", () => {
|
||||||
|
const today = "2026-06-30";
|
||||||
|
|
||||||
|
it("selects the policy with the latest EndDate when newest is first", () => {
|
||||||
|
const selected = selectLatestActiveFanavaranPolicy(
|
||||||
|
[
|
||||||
|
{ PolicyId: 4826286, EndDate: "1405/09/23" },
|
||||||
|
{ PolicyId: 3719458, EndDate: "1404/09/06" },
|
||||||
|
{ PolicyId: 2800731, EndDate: "1403/09/05" },
|
||||||
|
],
|
||||||
|
today,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(selected.policyId).toBe(4826286);
|
||||||
|
expect(selected.endDate).toBe("1405/09/23");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("selects the policy with the latest EndDate when newest is last", () => {
|
||||||
|
const selected = selectLatestActiveFanavaranPolicy(
|
||||||
|
[
|
||||||
|
{ PolicyId: 2800731, EndDate: "1403/09/05" },
|
||||||
|
{ PolicyId: 3719458, EndDate: "1404/09/06" },
|
||||||
|
{ PolicyId: 4826286, EndDate: "1405/09/23" },
|
||||||
|
],
|
||||||
|
today,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(selected.policyId).toBe(4826286);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects when no policies are returned", () => {
|
||||||
|
expect(() => selectLatestActiveFanavaranPolicy([], today)).toThrow(
|
||||||
|
BadRequestException,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects when the latest policy is expired", () => {
|
||||||
|
expect(() =>
|
||||||
|
selectLatestActiveFanavaranPolicy(
|
||||||
|
[
|
||||||
|
{ PolicyId: 3719458, EndDate: "1404/09/06" },
|
||||||
|
{ PolicyId: 2800731, EndDate: "1403/09/05" },
|
||||||
|
],
|
||||||
|
today,
|
||||||
|
),
|
||||||
|
).toThrow(BadRequestException);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects when the latest policy has no valid PolicyId", () => {
|
||||||
|
expect(() =>
|
||||||
|
selectLatestActiveFanavaranPolicy(
|
||||||
|
[
|
||||||
|
{ PolicyId: 3719458, EndDate: "1404/09/06" },
|
||||||
|
{ PolicyId: null, EndDate: "1405/09/23" },
|
||||||
|
],
|
||||||
|
today,
|
||||||
|
),
|
||||||
|
).toThrow(BadRequestException);
|
||||||
|
});
|
||||||
|
});
|
||||||
95
src/claim-request-management/fanavaran-policy-selection.ts
Normal file
95
src/claim-request-management/fanavaran-policy-selection.ts
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import { BadRequestException } from "@nestjs/common";
|
||||||
|
import { jalaliToGregorianDate } from "src/helpers/date-jalali";
|
||||||
|
import { gregorianDateInIran } from "src/helpers/iran-datetime";
|
||||||
|
|
||||||
|
export type FanavaranPolicyInquiryRow = {
|
||||||
|
PolicyId?: unknown;
|
||||||
|
EndDate?: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SelectedFanavaranPolicy = {
|
||||||
|
policy: FanavaranPolicyInquiryRow;
|
||||||
|
policyId: number;
|
||||||
|
endDate: string;
|
||||||
|
endDateGregorian: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DatedFanavaranPolicy = {
|
||||||
|
policy: FanavaranPolicyInquiryRow;
|
||||||
|
endDate: string;
|
||||||
|
endDateGregorian: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const NO_POLICY_MESSAGE =
|
||||||
|
"No Fanavaran policies were found for the insurer national code. PolicyId is required; contact the administrator.";
|
||||||
|
|
||||||
|
const EXPIRED_POLICY_MESSAGE =
|
||||||
|
"The latest insurance policy is expired and cannot be sent to Fanavaran. Contact the administrator.";
|
||||||
|
|
||||||
|
const INVALID_POLICY_MESSAGE =
|
||||||
|
"Fanavaran policy inquiry returned policies without a valid PolicyId or EndDate. PolicyId is required; contact the administrator.";
|
||||||
|
|
||||||
|
function parsePolicyId(value: unknown): number | null {
|
||||||
|
if (value === null || value === undefined) return null;
|
||||||
|
if (typeof value === "string" && value.trim() === "") return null;
|
||||||
|
const id = Number(value);
|
||||||
|
return Number.isFinite(id) && id > 0 ? id : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeEndDate(value: unknown): {
|
||||||
|
endDate: string;
|
||||||
|
endDateGregorian: string;
|
||||||
|
} | null {
|
||||||
|
if (value === null || value === undefined) return null;
|
||||||
|
const endDate = String(value).trim();
|
||||||
|
if (!endDate) return null;
|
||||||
|
|
||||||
|
const endDateGregorian = jalaliToGregorianDate(endDate);
|
||||||
|
if (!endDateGregorian) return null;
|
||||||
|
|
||||||
|
return { endDate, endDateGregorian };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function selectLatestActiveFanavaranPolicy(
|
||||||
|
policies: unknown,
|
||||||
|
todayGregorian: string = gregorianDateInIran(new Date()),
|
||||||
|
): SelectedFanavaranPolicy {
|
||||||
|
if (!Array.isArray(policies) || policies.length === 0) {
|
||||||
|
throw new BadRequestException(NO_POLICY_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
const candidates = policies
|
||||||
|
.map((policy) => {
|
||||||
|
if (!policy || typeof policy !== "object") return null;
|
||||||
|
const row = policy as FanavaranPolicyInquiryRow;
|
||||||
|
const endDate = normalizeEndDate(row.EndDate);
|
||||||
|
if (!endDate) return null;
|
||||||
|
return {
|
||||||
|
policy: row,
|
||||||
|
endDate: endDate.endDate,
|
||||||
|
endDateGregorian: endDate.endDateGregorian,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter((policy): policy is DatedFanavaranPolicy => policy !== null);
|
||||||
|
|
||||||
|
if (candidates.length === 0) {
|
||||||
|
throw new BadRequestException(INVALID_POLICY_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
const latest = candidates.reduce((currentLatest, candidate) =>
|
||||||
|
candidate.endDateGregorian > currentLatest.endDateGregorian
|
||||||
|
? candidate
|
||||||
|
: currentLatest,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (latest.endDateGregorian < todayGregorian) {
|
||||||
|
throw new BadRequestException(EXPIRED_POLICY_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
const policyId = parsePolicyId(latest.policy.PolicyId);
|
||||||
|
if (policyId === null) {
|
||||||
|
throw new BadRequestException(INVALID_POLICY_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...latest, policyId };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user