Finance-Accounts/ar-aging-app/backend/tests/test_summary_export.py

140 lines
5.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""Summary (Finance pack) workbook: structure + that the key figures land in the right cells."""
from __future__ import annotations
import openpyxl
from app.core.summary_export import export_summary_workbook
PERIODS = ["0110 Jan 2026", "1120 Jan 2026"]
SUMMARY = {
"available": True, "marketplace": "USA", "currency": "USD",
"reporting_month": "2026-01", "month_end": "2026-01-31",
"period_labels": PERIODS,
"opening_balance": 10_868_838.70,
"components": [
{"key": "product_sales", "label": "Order / product sales", "group": "revenue",
"values": [100.0, 200.0], "total": 300.0},
{"key": "refunds", "label": "Refunds", "group": "revenue",
"values": [-10.0, -20.0], "total": -30.0},
{"key": "fba_fees", "label": "FBA fees", "group": "fee",
"values": [-5.0, -15.0], "total": -20.0},
{"key": "transfers", "label": "Transfer / disbursements", "group": "payout",
"values": [-50.0, -60.0], "total": -110.0},
],
"gross_revenue": 300.0,
"net_revenue": 19_038_659.52,
"disbursements": -18_797_065.22,
"in_transit_payouts": -9_555_841.69,
"closing_receivable": 11_110_433.00,
"finance_closing": 11_110_433.00,
"difference": 0.0,
"status": "matched",
"verified_by": "A. Controller",
"verified_at": "2026-02-02T10:00:00",
"ledger": [
{"period": "Opening", "description": "Previous month closing balance",
"debit": None, "credit": None, "balance": 10_868_838.70},
{"period": PERIODS[0], "description": "Net revenue (accrued)",
"debit": 4_421_131.76, "credit": None, "balance": 15_289_970.46},
{"period": "Settlement", "description": "Amazon payout received",
"debit": None, "credit": 18_797_065.22, "balance": 11_110_433.00},
{"period": "Closing", "description": "Month-end receivable",
"debit": None, "credit": None, "balance": 11_110_433.00},
],
}
CONTROL = {
"available": True, "tolerance": 1.0,
"rows": [
{"key": "gross_sales", "label": "Gross Sales", "critical": False,
"dashboard": 47_117_934.96, "finance": 47_117_934.96, "difference": 0.0, "status": "matched"},
{"key": "closing_receivable", "label": "Closing Receivable", "critical": True,
"dashboard": 11_110_433.0, "finance": 11_110_433.0, "difference": 0.0, "status": "matched"},
],
"verified_by": "A. Controller", "verified_at": "2026-02-02T10:00:00", "comment": "Tied to control sheet.",
}
JOURNAL = {
"periods": [{"label": p} for p in PERIODS],
"lines": [{"key": "Sales", "gl_account": "Sales:All Platforms Sales:Amazon USA",
"values": [1.0, 2.0], "total": 3.0}],
"receivable": {"key": "Receivable", "gl_account": "Accounts Receivable:Amazon USA",
"values": [4.0, 5.0], "total": 9.0},
}
def _build(tmp_path, controls=None):
out = str(tmp_path / "summary.xlsx")
export_summary_workbook(out, SUMMARY, CONTROL, JOURNAL,
{"session_name": "Jan close", "entry_no": "22283",
"files": [{"filename": "a.xlsx", "rows": 10, "dates": "..", "sha256": "abc"}]},
controls=controls)
return openpyxl.load_workbook(out)
def _cells(ws):
return [[ws.cell(row=r, column=c).value for c in range(1, ws.max_column + 1)]
for r in range(1, ws.max_row + 1)]
def test_sheets_present(tmp_path):
wb = _build(tmp_path)
assert wb.sheetnames == ["Finance Summary", "AR Ledger", "Reconciliation Control",
"Category Totals", "Month-End Controls", "Audit Trail"]
def test_month_end_controls_sheet_carries_the_evidence(tmp_path):
"""The workbook must stand alone as audit evidence — which controls ran, and their result."""
wb = _build(tmp_path, controls={
"controls": [
{"key": "C2", "label": "Column completeness", "status": "pass",
"severity": "error", "detail": "GL lines reconcile to the source `total` column.",
"evidence": []},
{"key": "C5", "label": "FX rates confirmed", "status": "fail", "severity": "error",
"detail": "1 marketplace has no FX rate confirmed for 2026-01.",
"evidence": ["Germany: rate 1.185665 (EUR) is a seeded default"]},
],
})
flat = [v for row in _cells(wb["Month-End Controls"]) for v in row]
assert "C2" in flat and "C5" in flat
assert "PASS" in flat and "FAIL" in flat
assert any(isinstance(v, str) and "seeded default" in v for v in flat)
def test_month_end_controls_sheet_when_none_recorded(tmp_path):
flat = [v for row in _cells(_build(tmp_path)["Month-End Controls"]) for v in row]
assert any(isinstance(v, str) and "No controls recorded" in v for v in flat)
def test_finance_summary_key_figures(tmp_path):
wb = _build(tmp_path)
flat = [v for row in _cells(wb["Finance Summary"]) for v in row]
# closing calculation + variance land in the sheet
assert 11_110_433.00 in flat
assert 19_038_659.52 in flat
assert 10_868_838.70 in flat
assert -18_797_065.22 in flat
assert "MATCHED" in flat
# revenue/fee component labels rendered
assert "Order / product sales" in flat and "FBA fees" in flat
def test_ledger_and_control_sheets(tmp_path):
wb = _build(tmp_path)
ledger = [v for row in _cells(wb["AR Ledger"]) for v in row]
assert "Opening" in ledger and "Closing" in ledger
assert 11_110_433.00 in ledger and 18_797_065.22 in ledger
ctrl = [v for row in _cells(wb["Reconciliation Control"]) for v in row]
assert "Closing Receivable" in ctrl and "MATCHED" in ctrl
assert "A. Controller" in ctrl
def test_category_totals_and_audit(tmp_path):
wb = _build(tmp_path)
cats = [v for row in _cells(wb["Category Totals"]) for v in row]
assert "Sales" in cats and "Receivable" in cats
audit = [v for row in _cells(wb["Audit Trail"]) for v in row]
assert "22283" in audit and "Jan close" in audit