#!/usr/bin/env bash # Verify Accounting module (Haben-inspired German accounting) set -u cd /home/z/my-project BASE=http://127.0.0.1:3000 SHOTS=/home/z/my-project/aos-shots mkdir -p "$SHOTS" echo "=== Start server ===" pkill -f "next dev" 2>/dev/null; pkill -f "tee dev.log" 2>/dev/null; sleep 2 bun run dev > dev.log 2>&1 & SRV=$! for i in $(seq 1 90); do curl -s -o /dev/null "$BASE/" 2>/dev/null && break; sleep 1; done echo " ready after ${i}s"; sleep 2 echo "=== API tests ===" echo -n " /api/aos/accounting -> "; curl -s -o /dev/null -w "HTTP %{http_code}\n" "$BASE/api/aos/accounting" curl -s "$BASE/api/aos/accounting" | python3 -c " import sys,json d=json.load(sys.stdin) v=d['vat'] print(f' VAT: current period {v[\"current\"][\"periodMonth\"]}/{v[\"current\"][\"periodYear\"]} status={v[\"current\"][\"status\"]} payable={v[\"current\"][\"payableCents\"]/100:.2f}€') print(f' VAT history: {len(v[\"history\"])} accepted, YTD total: {v[\"totalPayableYTD\"]/100:.2f}€') e=d['eur'] print(f' EÜR: profit {e[\"totalProfit\"]/100:.2f}€, income {e[\"totalIncome\"]/100:.2f}€, cost {e[\"totalCost\"]/100:.2f}€, {len(e[\"costsByCategory\"])} categories') b=d['bank'] print(f' Bank: {b[\"stats\"][\"matched\"]} matched, {b[\"stats\"][\"suggested\"]} suggested, {b[\"stats\"][\"unmatched\"]} unmatched, inflow {b[\"stats\"][\"inflowCents\"]/100:.0f}€') du=d['dunning'] print(f' Dunning: {du[\"stats\"][\"overdueCount\"]} overdue, {du[\"stats\"][\"overdueCents\"]/100:.2f}€, {du[\"stats\"][\"dunningSent\"]} runs') " 2>/dev/null echo "" echo "=== Test VAT submit to ELSTER ===" VAT_ID=$(curl -s "$BASE/api/aos/accounting" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['vat']['current']['id'])" 2>/dev/null) echo " current VAT id: $VAT_ID" if [ -n "$VAT_ID" ]; then RES=$(curl -s -X PATCH "$BASE/api/aos/accounting/vat/$VAT_ID/submit") echo " submit result: $(echo "$RES" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'status={d[\"vat\"][\"status\"]}, elsterRef={d[\"elsterRef\"]}')" 2>/dev/null)" fi echo "" echo "=== Test bank match ===" # find a suggested bank tx TX_ID=$(curl -s "$BASE/api/aos/accounting" | python3 -c " import sys,json d=json.load(sys.stdin) for t in d['bank']['transactions']: if t['matchedStatus']=='suggested': print(t['id']); break " 2>/dev/null) echo " suggested tx id: $TX_ID" # find an unpaid invoice to match against INV_ID=$(curl -s "$BASE/api/aos/finance" | python3 -c " import sys,json d=json.load(sys.stdin) for i in d['invoices']: if i['status'] in ('sent','overdue'): print(i['id']); break " 2>/dev/null) echo " invoice id to match: $INV_ID" if [ -n "$TX_ID" ] && [ -n "$INV_ID" ]; then RES=$(curl -s -X POST "$BASE/api/aos/accounting/bank/$TX_ID/match" -H 'content-type: application/json' -d "{\"invoiceId\":\"$INV_ID\"}") echo " match result: $(echo "$RES" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'tx status={d[\"transaction\"][\"matchedStatus\"]}, invoice={d[\"invoiceNumber\"]}')" 2>/dev/null)" fi echo "" echo "=== Browser: Accounting view ===" agent-browser open "$BASE/" >/dev/null 2>&1 agent-browser wait --load networkidle >/dev/null 2>&1 || true agent-browser wait 3000 >/dev/null 2>&1 agent-browser set viewport 1440 900 >/dev/null 2>&1 # navigate via snapshot ref (more reliable than find text) agent-browser snapshot -i >/tmp/s.txt 2>&1 ACCT=$(grep -i 'button "Buchhaltung"' /tmp/s.txt | grep -oE 'ref=e[0-9]+' | head -1) echo " Buchhaltung nav ref: $ACCT" [ -n "$ACCT" ] && agent-browser click "$ACCT" >/dev/null 2>&1 agent-browser wait 3000 >/dev/null 2>&1 H1=$(agent-browser get text h1 2>/dev/null | head -1) echo " Accounting H1: $H1" agent-browser screenshot --full "$SHOTS/v13-accounting-vat.png" >/dev/null 2>&1 && echo " VAT shot OK" echo "=== Switch to EÜR tab ===" agent-browser find role tab click --name "EÜR" >/dev/null 2>&1 || agent-browser find text "EÜR" click >/dev/null 2>&1 agent-browser wait 2000 >/dev/null 2>&1 agent-browser screenshot --full "$SHOTS/v13-accounting-eur.png" >/dev/null 2>&1 && echo " EÜR shot OK" echo "=== Switch to Bankabgleich tab ===" agent-browser find role tab click --name "Bankabgleich" >/dev/null 2>&1 || agent-browser find text "Bankabgleich" click >/dev/null 2>&1 agent-browser wait 2000 >/dev/null 2>&1 agent-browser screenshot --full "$SHOTS/v13-accounting-bank.png" >/dev/null 2>&1 && echo " Bank shot OK" echo "=== Switch to Mahnwesen tab ===" agent-browser find role tab click --name "Mahnwesen" >/dev/null 2>&1 || agent-browser find text "Mahnwesen" click >/dev/null 2>&1 agent-browser wait 2000 >/dev/null 2>&1 agent-browser screenshot --full "$SHOTS/v13-accounting-dunning.png" >/dev/null 2>&1 && echo " Dunning shot OK" echo "" echo "=== Errors ===" agent-browser errors 2>&1 | head -8 echo "--- console last 5 ---" agent-browser console 2>&1 | tail -5 echo "" agent-browser close >/dev/null 2>&1 kill $SRV 2>/dev/null echo "=== dev.log errors ===" grep -iE "error|⨯|500" dev.log | grep -v SIGTERM | tail -8 echo "=== DONE ===" ls -la "$SHOTS"/v13-* 2>/dev/null | tail -6