#!/usr/bin/env bash # OMNL Fineract — Create one Office for Samama Group LLC (Azerbaijan) and optionally run 5B USD M1 transfer. # Uses Fineract POST /offices (name, parentId, openingDate, externalId). See docs/04-configuration/mifos-omnl-central-bank/SAMAMA_OFFICE_AND_5B_M1_TRANSFER.md. # Usage: run from repo root. Set DRY_RUN=1 to print only. Set SKIP_TRANSFER=1 to create office only. # OPENING_DATE=2024-01-10 (default) # Requires: curl, jq. set -euo pipefail REPO_ROOT="${REPO_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}" DRY_RUN="${DRY_RUN:-0}" SKIP_TRANSFER="${SKIP_TRANSFER:-0}" OPENING_DATE="${OPENING_DATE:-2024-01-10}" SAMAMA_EXTERNAL_ID="${SAMAMA_EXTERNAL_ID:-SAMAMA-AZ-1703722701}" SAMAMA_OFFICE_NAME="${SAMAMA_OFFICE_NAME:-Samama Group LLC - Azerbaijan}" 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. 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 existing office by externalId offices_json=$(curl "${CURL_OPTS[@]}" "${BASE_URL}/offices" 2>/dev/null) existing_id=$(echo "$offices_json" | jq -r --arg e "$SAMAMA_EXTERNAL_ID" '.[] | select(.externalId == $e) | .id' 2>/dev/null | head -1) if [ -n "$existing_id" ] && [ "$existing_id" != "null" ]; then echo "Samama office already exists: officeId=$existing_id (externalId=$SAMAMA_EXTERNAL_ID)" >&2 SAMAMA_OFFICE_ID="$existing_id" else payload=$(jq -n \ --arg name "$SAMAMA_OFFICE_NAME" \ --arg openingDate "$OPENING_DATE" \ --arg externalId "$SAMAMA_EXTERNAL_ID" \ '{ name: $name, parentId: 1, openingDate: $openingDate, externalId: $externalId, dateFormat: "yyyy-MM-dd", locale: "en" }') if [ "$DRY_RUN" = "1" ]; then echo "DRY_RUN: would POST /offices with name=$SAMAMA_OFFICE_NAME externalId=$SAMAMA_EXTERNAL_ID openingDate=$OPENING_DATE" >&2 echo "Payload: $payload" >&2 exit 0 fi res=$(curl "${CURL_OPTS[@]}" -X POST -d "$payload" "${BASE_URL}/offices" 2>/dev/null) || true if echo "$res" | jq -e '.resourceId // .officeId' >/dev/null 2>&1; then SAMAMA_OFFICE_ID=$(echo "$res" | jq -r '.resourceId // .officeId') echo "Created Samama office: officeId=$SAMAMA_OFFICE_ID" >&2 else echo "Failed to create office: $res" >&2 exit 1 fi fi if [ "$SKIP_TRANSFER" = "1" ]; then echo "SKIP_TRANSFER=1: not posting 5B M1. Run with JOURNAL_MATRIX=.../omnl-journal-matrix-samama-5b.json and set OFFICE_ID_SAMAMA=$SAMAMA_OFFICE_ID, or run this script without SKIP_TRANSFER." >&2 echo "OFFICE_ID_SAMAMA=$SAMAMA_OFFICE_ID" exit 0 fi # Post 5B M1 transfer: HO leg (officeId=1) + Office leg (officeId=SAMAMA_OFFICE_ID) # GL: 2100 (M1), 2410 (Due To), 1410 (Due From). Same pattern as T-004 (TAJ). CURL_OPTS_HTTP=(-s -S -w "\n%{http_code}" -H "Fineract-Platform-TenantId: ${TENANT}" -H "Content-Type: application/json" -u "${USER}:${PASS}") GL_ACCOUNTS=$(curl "${CURL_OPTS_HTTP[@]}" "${BASE_URL}/glaccounts" 2>/dev/null | sed '$d') get_gl_id() { local code="$1" echo "$GL_ACCOUNTS" | jq -r --arg c "$code" '.[] | select(.glCode == $c) | .id // empty' 2>/dev/null || true } ID_2100=$(get_gl_id "2100") ID_2410=$(get_gl_id "2410") ID_1410=$(get_gl_id "1410") TRANSACTION_DATE="${TRANSACTION_DATE:-$(date +%Y-%m-%d)}" if [ -z "$ID_2100" ] || [ -z "$ID_2410" ] || [ -z "$ID_1410" ]; then echo "Missing GL accounts (2100, 2410, 1410). Create them first (see omnl-gl-accounts-create.sh and Phase C interoffice docs)." >&2 exit 1 fi post_entry() { local office_id="$1" local debit_id="$2" local credit_id="$3" local amount="$4" local comments="$5" local body local ref="${6:-}" [ -z "$ref" ] && ref="OMNL-JE-${office_id}-${TRANSACTION_DATE//-/}-0" body=$(jq -n \ --argjson officeId "$office_id" \ --arg transactionDate "$TRANSACTION_DATE" \ --arg comments "$comments" \ --arg referenceNumber "$ref" \ --arg dateFormat "yyyy-MM-dd" \ --arg locale "en" \ --arg currencyCode "USD" \ --argjson debitId "$debit_id" \ --argjson creditId "$credit_id" \ --argjson amount "$amount" \ '{ officeId: $officeId, transactionDate: $transactionDate, dateFormat: $dateFormat, locale: $locale, currencyCode: $currencyCode, comments: $comments, referenceNumber: $referenceNumber, credits: [ { glAccountId: $creditId, amount: $amount } ], debits: [ { glAccountId: $debitId, amount: $amount } ] }' 2>/dev/null) if [ "$DRY_RUN" = "1" ]; then echo "DRY_RUN: $comments (officeId=$office_id amount=$amount)" >&2 return 0 fi local out out=$(curl "${CURL_OPTS_HTTP[@]}" -X POST -d "$body" "${BASE_URL}/journalentries" 2>/dev/null) local code code=$(echo "$out" | tail -n1) local resp resp=$(echo "$out" | sed '$d') if [ "$code" = "200" ] || [ "${code:0:1}" = "2" ]; then echo "OK $comments (HTTP $code)" >&2 else echo "FAIL $comments HTTP $code: $resp" >&2 return 1 fi } AMOUNT_5B=5000000000 DATE_REF="${TRANSACTION_DATE//-/}" post_entry 1 "$ID_2100" "$ID_2410" "$AMOUNT_5B" "T-Samama-HO — Due To Samama Group LLC — M1 5B" "SAMAMA-20-${DATE_REF}-HO" post_entry "$SAMAMA_OFFICE_ID" "$ID_1410" "$ID_2100" "$AMOUNT_5B" "T-Samama-OF — Due From HO — Samama Group LLC M1 5B" "SAMAMA-20-${DATE_REF}-OF" echo "Done: Samama officeId=$SAMAMA_OFFICE_ID; 5B USD M1 transfer posted." >&2 echo "OFFICE_ID_SAMAMA=$SAMAMA_OFFICE_ID"