#!/usr/bin/env bash # OMNL Fineract — Apply entity master data (name, LEI, address, contacts) to clients. # Reads OMNL_ENTITY_MASTER_DATA.json; maps by accountNo to clientId; updates names, identifiers (LEI), addresses, contacts. # Usage: run from repo root; sources omnl-fineract/.env or .env. # ENTITY_DATA= JSON entity data (default: docs/04-configuration/mifos-omnl-central-bank/OMNL_ENTITY_MASTER_DATA.json) # DRY_RUN=1 print only, do not PUT/POST. # Requires: curl, jq. set -euo pipefail REPO_ROOT="${REPO_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}" DRY_RUN="${DRY_RUN:-0}" ENTITY_DATA="${ENTITY_DATA:-${REPO_ROOT}/docs/04-configuration/mifos-omnl-central-bank/OMNL_ENTITY_MASTER_DATA.json}" if [ ! -f "$ENTITY_DATA" ]; then echo "Entity data file not found: $ENTITY_DATA" >&2 exit 1 fi if [ -f "${REPO_ROOT}/omnl-fineract/.env" ]; then set +u source "${REPO_ROOT}/omnl-fineract/.env" 2>/dev/null || true set -u elif [ -f "${REPO_ROOT}/.env" ]; then set +u source "${REPO_ROOT}/.env" 2>/dev/null || true set -u fi BASE_URL="${OMNL_FINERACT_BASE_URL:-}" TENANT="${OMNL_FINERACT_TENANT:-omnl}" USER="${OMNL_FINERACT_USER:-app.omnl}" PASS="${OMNL_FINERACT_PASSWORD:-}" if [ -z "$BASE_URL" ] || [ -z "$PASS" ]; then echo "Set OMNL_FINERACT_BASE_URL and OMNL_FINERACT_PASSWORD (e.g. in omnl-fineract/.env)" >&2 exit 1 fi CURL_OPTS=(-s -S -H "Fineract-Platform-TenantId: ${TENANT}" -H "Content-Type: application/json" -u "${USER}:${PASS}") # Resolve clientId by accountNo (000000001 -> id) get_client_id_by_account() { local account_no="$1" local clients_json="$2" if echo "$clients_json" | jq -e '.pageItems' >/dev/null 2>&1; then echo "$clients_json" | jq -r --arg an "$account_no" '.pageItems[] | select(.accountNo == $an) | .id' else echo "$clients_json" | jq -r --arg an "$account_no" '.[] | select(.accountNo == $an) | .id' fi } # Resolve clientId by externalId (e.g. OMNL-9) when accountNo not found get_client_id_by_external_id() { local ext_id="$1" local clients_json="$2" if echo "$clients_json" | jq -e '.pageItems' >/dev/null 2>&1; then echo "$clients_json" | jq -r --arg e "$ext_id" '.pageItems[] | select(.externalId == $e) | .id' else echo "$clients_json" | jq -r --arg e "$ext_id" '.[] | select(.externalId == $e) | .id' fi } # Resolve LEI document type ID from identifiers template (first type whose name contains LEI, or first type) get_lei_document_type_id() { local client_id="$1" local template template=$(curl "${CURL_OPTS[@]}" "${BASE_URL}/clients/${client_id}/identifiers/template" 2>/dev/null) || true if [ -z "$template" ]; then echo "" return fi local id id=$(echo "$template" | jq -r '(.allowedDocumentTypes // [])[] | select(.name | ascii_upcase | test("LEI")) | .id' 2>/dev/null | head -1) if [ -z "$id" ] || [ "$id" = "null" ]; then id=$(echo "$template" | jq -r '(.allowedDocumentTypes // [])[0].id // empty' 2>/dev/null) fi echo "$id" } clients_json=$(curl "${CURL_OPTS[@]}" "${BASE_URL}/clients") if ! echo "$clients_json" | jq -e '.pageItems // .' >/dev/null 2>&1; then echo "Unexpected clients response." >&2 exit 1 fi entity_count=$(jq -r '.entities | length' "$ENTITY_DATA") updated_names=0 updated_lei=0 updated_address=0 updated_contact=0 for i in $(seq 0 $((entity_count - 1))); do entity=$(jq -c ".entities[$i]" "$ENTITY_DATA") client_num=$(echo "$entity" | jq -r '.clientNumber') account_no=$(echo "$entity" | jq -r '.accountNo') entity_name=$(echo "$entity" | jq -r '.entityName') lei=$(echo "$entity" | jq -r '.lei // ""') mobile=$(echo "$entity" | jq -r '.contact.mobileNo // ""') email=$(echo "$entity" | jq -r '.contact.emailAddress // ""') client_id=$(get_client_id_by_account "$account_no" "$clients_json") if [ -z "$client_id" ] || [ "$client_id" = "null" ]; then client_id=$(get_client_id_by_external_id "OMNL-${client_num}" "$clients_json") fi if [ -z "$client_id" ] || [ "$client_id" = "null" ]; then echo "Skip: no client with accountNo=$account_no or externalId=OMNL-$client_num" >&2 continue fi echo "=== Client $client_num (id=$client_id) $entity_name ===" >&2 # 1. Name (lastname non-blank required by tenant validation) payload_name=$(jq -n --arg f "$entity_name" --arg l "." '{ firstname: $f, lastname: $l }') if [ "$DRY_RUN" = "1" ]; then echo " [DRY RUN] PUT clients/${client_id} name=$entity_name" >&2 else res=$(curl "${CURL_OPTS[@]}" -X PUT -d "$payload_name" "${BASE_URL}/clients/${client_id}" 2>/dev/null) || true if echo "$res" | jq -e '.resourceId // .clientId' >/dev/null 2>&1; then ((updated_names++)) || true fi fi # 2. LEI identifier (if lei non-empty) if [ -n "$lei" ] && [ "$lei" != "null" ]; then lei_type_id=$(get_lei_document_type_id "$client_id") if [ -n "$lei_type_id" ] && [ "$lei_type_id" != "null" ]; then payload_lei=$(jq -n --arg key "$lei" --argjson typeId "$lei_type_id" '{ documentKey: $key, documentTypeId: $typeId, description: "LEI", status: "Active" }') if [ "$DRY_RUN" = "1" ]; then echo " [DRY RUN] POST clients/${client_id}/identifiers LEI=$lei" >&2 else res=$(curl "${CURL_OPTS[@]}" -X POST -d "$payload_lei" "${BASE_URL}/clients/${client_id}/identifiers" 2>/dev/null) || true if echo "$res" | jq -e '.resourceId // .clientId' >/dev/null 2>&1; then ((updated_lei++)) || true fi fi else echo " Skip LEI: no LEI document type in tenant (add via Admin or codes)" >&2 fi fi # 3. Address (if any address field set and countryId present) country_id=$(echo "$entity" | jq -r '.address.countryId // empty') street=$(echo "$entity" | jq -r '.address.street // ""') line1=$(echo "$entity" | jq -r '.address.addressLine1 // ""') city=$(echo "$entity" | jq -r '.address.city // ""') if [ -n "$country_id" ] && [ "$country_id" != "null" ] && { [ -n "$street" ] || [ -n "$line1" ] || [ -n "$city" ]; }; then payload_addr=$(echo "$entity" | jq -c ' .address | { street: (.street // ""), addressLine1: (.addressLine1 // ""), addressLine2: (.addressLine2 // ""), addressLine3: (.addressLine3 // ""), city: (.city // ""), postalCode: (if .postalCode != null and .postalCode != "" then .postalCode else "" end), countryId: .countryId, isActive: true } + (if .stateProvinceId != null and .stateProvinceId != "" then { stateProvinceId: .stateProvinceId } else {} end) ') if [ "$DRY_RUN" = "1" ]; then echo " [DRY RUN] POST client/${client_id}/addresses" >&2 else res=$(curl "${CURL_OPTS[@]}" -X POST -d "$payload_addr" "${BASE_URL}/client/${client_id}/addresses" 2>/dev/null) || true if echo "$res" | jq -e '.resourceId // .addressId' >/dev/null 2>&1; then ((updated_address++)) || true fi fi fi # 4. Contact (mobileNo, emailAddress) via PUT client if [ -n "$mobile" ] || [ -n "$email" ]; then payload_contact=$(jq -n --arg m "$mobile" --arg e "$email" '{ mobileNo: $m, emailAddress: $e }') if [ "$DRY_RUN" = "1" ]; then echo " [DRY RUN] PUT clients/${client_id} contact mobile=$mobile email=$email" >&2 else res=$(curl "${CURL_OPTS[@]}" -X PUT -d "$payload_contact" "${BASE_URL}/clients/${client_id}" 2>/dev/null) || true if echo "$res" | jq -e '.resourceId // .clientId' >/dev/null 2>&1; then ((updated_contact++)) || true fi fi fi done echo "Done: names=$updated_names, LEI=$updated_lei, addresses=$updated_address, contacts=$updated_contact" >&2