Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
- Config, docs, scripts, and backup manifests - Submodule refs unchanged (m = modified content in submodules) Made-with: Cursor
135 lines
5.1 KiB
Bash
135 lines
5.1 KiB
Bash
#!/usr/bin/env bash
|
|
# Create FX and GRU (M00) GL accounts from CHART_OF_ACCOUNTS.md in OMNL Fineract.
|
|
# Idempotent: skips if glCode exists. Creates parents before children. Run from repo root.
|
|
# Requires: curl, jq.
|
|
# See: docs/04-configuration/mifos-omnl-central-bank/CHART_OF_ACCOUNTS.md, OMNL_GL_ACCOUNTS_FX_GRU.md
|
|
|
|
set -euo pipefail
|
|
REPO_ROOT="${REPO_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
|
|
# usage: 1=DETAIL, 2=HEADER
|
|
USAGE_DETAIL=1
|
|
USAGE_HEADER=2
|
|
|
|
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 -w "\n%{http_code}" -H "Fineract-Platform-TenantId: ${TENANT}" -H "Content-Type: application/json" -u "${USER}:${PASS}")
|
|
|
|
# Build glCode -> id map from existing GL accounts
|
|
get_gl_map() {
|
|
local json
|
|
json=$(curl "${CURL_OPTS[@]}" "${BASE_URL}/glaccounts" 2>/dev/null | sed '$d')
|
|
echo "$json" | jq -r '.[] | "\(.glCode)|\(.id)"' 2>/dev/null || true
|
|
}
|
|
|
|
# Create one GL account; optional parent glCode; usage 1=DETAIL 2=HEADER
|
|
create_gl() {
|
|
local gl_code="$1" name="$2" type_id="$3" usage_id="$4" parent_gl="$5" desc="$6"
|
|
local body parent_id
|
|
|
|
if [ -n "${GL_ID_MAP[$gl_code]:-}" ]; then
|
|
echo " [skip] $gl_code — $name (exists)"
|
|
return 0
|
|
fi
|
|
|
|
parent_id=""
|
|
if [ -n "$parent_gl" ] && [ -n "${GL_ID_MAP[$parent_gl]:-}" ]; then
|
|
parent_id="${GL_ID_MAP[$parent_gl]}"
|
|
fi
|
|
|
|
if [ -n "$parent_id" ]; then
|
|
body=$(jq -n \
|
|
--arg code "$gl_code" \
|
|
--arg name "$name" \
|
|
--argjson type "$type_id" \
|
|
--argjson usage "$usage_id" \
|
|
--argjson parentId "$parent_id" \
|
|
--arg desc "$desc" \
|
|
'{ glCode: $code, name: $name, type: $type, usage: $usage, parentId: $parentId, manualEntriesAllowed: true, description: $desc }')
|
|
else
|
|
body=$(jq -n \
|
|
--arg code "$gl_code" \
|
|
--arg name "$name" \
|
|
--argjson type "$type_id" \
|
|
--argjson usage "$usage_id" \
|
|
--arg desc "$desc" \
|
|
'{ glCode: $code, name: $name, type: $type, usage: $usage, manualEntriesAllowed: true, description: $desc }')
|
|
fi
|
|
|
|
local out
|
|
out=$(curl "${CURL_OPTS[@]}" -X POST -d "$body" "${BASE_URL}/glaccounts" 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
|
|
local new_id
|
|
new_id=$(echo "$resp" | jq -r '.resourceId // empty')
|
|
if [ -n "$new_id" ]; then
|
|
GL_ID_MAP[$gl_code]=$new_id
|
|
fi
|
|
echo " [created] $gl_code — $name"
|
|
else
|
|
echo " [fail] $gl_code — $name HTTP $code: $resp" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Load initial map
|
|
declare -A GL_ID_MAP
|
|
while IFS='|' read -r code id; do
|
|
[ -n "$code" ] && [ -n "$id" ] && GL_ID_MAP[$code]=$id
|
|
done < <(get_gl_map)
|
|
|
|
echo "=== OMNL Fineract — Create FX and GRU (M00) GL accounts ==="
|
|
echo "Base URL: $BASE_URL"
|
|
echo ""
|
|
|
|
# Type: 1=ASSET, 2=LIABILITY, 4=INCOME, 5=EXPENSE
|
|
# Order: parents before children
|
|
|
|
echo "--- Assets (FX reserves & settlement) ---"
|
|
create_gl "10000" "Assets (header)" 1 $USAGE_HEADER "" "Total assets"
|
|
create_gl "12000" "Foreign currency reserves (header)" 1 $USAGE_HEADER "10000" "FX reserves header"
|
|
create_gl "12010" "FX reserves — USD" 1 $USAGE_DETAIL "12000" "Foreign currency reserves — USD"
|
|
create_gl "12020" "FX reserves — EUR" 1 $USAGE_DETAIL "12000" "Foreign currency reserves — EUR"
|
|
create_gl "12090" "FX reserves — other" 1 $USAGE_DETAIL "12000" "Other ISO-4217 and special units"
|
|
create_gl "13000" "FX settlement balances (header)" 1 $USAGE_HEADER "10000" "FX settlement header"
|
|
create_gl "13010" "FX settlement — nostro" 1 $USAGE_DETAIL "13000" "Settlement balances with counterparties"
|
|
|
|
echo "--- Liabilities (GRU / M00) ---"
|
|
create_gl "20000" "Liabilities (header)" 2 $USAGE_HEADER "" "Total liabilities"
|
|
create_gl "21000" "M00 — Base reserve (header)" 2 $USAGE_HEADER "20000" "Central bank reserve unit; GRU-denominated; non-circulating except authorized issuance"
|
|
create_gl "21010" "M00 — Bank reserves (control)" 2 $USAGE_DETAIL "21000" "Control account for M00"
|
|
|
|
echo "--- Income (FX gains) ---"
|
|
create_gl "40000" "Income (header)" 4 $USAGE_HEADER "" "Total income"
|
|
create_gl "42000" "FX gains (realized)" 4 $USAGE_DETAIL "40000" "Realized foreign exchange gains"
|
|
create_gl "42100" "Unrealized FX gain (P&L)" 4 $USAGE_DETAIL "40000" "Unrealized FX gain (revaluation)"
|
|
|
|
echo "--- Expenses (FX losses) ---"
|
|
create_gl "50000" "Expenses (header)" 5 $USAGE_HEADER "" "Total expenses"
|
|
create_gl "51000" "FX losses (realized)" 5 $USAGE_DETAIL "50000" "Realized foreign exchange losses"
|
|
create_gl "52100" "Unrealized FX loss (P&L)" 5 $USAGE_DETAIL "50000" "Unrealized FX loss (revaluation)"
|
|
|
|
echo ""
|
|
echo "Done. See CHART_OF_ACCOUNTS.md and FX_AND_VALUATION.md for usage."
|