Add opening balance action summary to Excel export
This commit is contained in:
@@ -284,7 +284,7 @@ def page(
|
||||
|
||||
@router.get("/download/{run_id}")
|
||||
def download_report(request: Request, run_id: int, client_id: int | None = None):
|
||||
"""Download the complete opening-balance comparison as an Excel workbook."""
|
||||
"""Download the complete opening-balance review, including the web summary action reports."""
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user, denied = _require_partner(request, db, "accounting.tally.view")
|
||||
@@ -298,11 +298,103 @@ def download_report(request: Request, run_id: int, client_id: int | None = None)
|
||||
if not selected or (client_id and int(client_id) != int(run.client_id)):
|
||||
return _go(error="Opening balance comparison run is not visible.")
|
||||
|
||||
# Complete detailed reports.
|
||||
ledger_rows = ledger_items(db, run_id=run.id)
|
||||
stock_rows = stock_items(db, run_id=run.id)
|
||||
|
||||
# These are the same action-required populations shown on the web Summary tab.
|
||||
ledger_action_rows = ledger_items(db, run_id=run.id, status="difference")
|
||||
stock_action_rows = []
|
||||
for action_status in (
|
||||
"quantity_difference",
|
||||
"value_difference",
|
||||
"quantity_and_value_difference",
|
||||
"unit_difference",
|
||||
):
|
||||
stock_action_rows.extend(stock_items(db, run_id=run.id, status=action_status))
|
||||
|
||||
try:
|
||||
summary_counts = _summary_counts(json.loads(run.summary_json or "{}"))
|
||||
except Exception:
|
||||
summary_counts = _summary_counts({})
|
||||
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "Balance Sheet Ledgers"
|
||||
meta = wb.active
|
||||
meta.title = "Summary"
|
||||
meta.append(["Opening Balance Review"])
|
||||
meta.append(["Client", getattr(selected, "client_name", "") or getattr(selected, "name", "") or str(selected.id)])
|
||||
meta.append(["Run ID", run.id])
|
||||
meta.append(["Previous Tally Company", run.previous_company_name])
|
||||
meta.append(["Current Tally Company", run.current_company_name])
|
||||
meta.append(["Scope", "Balance Sheet ledgers and Stock Items only"])
|
||||
meta.append(["Balance Sheet Ledger Rows", len(ledger_rows)])
|
||||
meta.append(["Stock Item Rows", len(stock_rows)])
|
||||
meta.append(["Ledger Differences — Action Required", len(ledger_action_rows)])
|
||||
meta.append(["Stock Differences — Action Required", len(stock_action_rows)])
|
||||
meta.append([])
|
||||
meta.append(["Ledger Status", "Count"])
|
||||
for label, key in (
|
||||
("Matched", "matched"),
|
||||
("Difference", "difference"),
|
||||
("Missing in Current Year", "missing_in_current_year"),
|
||||
("New in Current Year", "new_in_current_year"),
|
||||
):
|
||||
meta.append([label, summary_counts["ledgers"].get(key, 0)])
|
||||
meta.append([])
|
||||
meta.append(["Stock Item Status", "Count"])
|
||||
for label, key in (
|
||||
("Matched", "matched"),
|
||||
("Quantity Difference", "quantity_difference"),
|
||||
("Value Difference", "value_difference"),
|
||||
("Quantity & Value Difference", "quantity_and_value_difference"),
|
||||
("Unit Difference", "unit_difference"),
|
||||
("Missing in Current Year", "missing_in_current_year"),
|
||||
("New in Current Year", "new_in_current_year"),
|
||||
):
|
||||
meta.append([label, summary_counts["stock_items"].get(key, 0)])
|
||||
meta.append([])
|
||||
meta.append(["Generated", datetime.now().strftime("%Y-%m-%d %H:%M:%S")])
|
||||
|
||||
# Mirror the web Summary -> Ledger Differences — Action Required table.
|
||||
law = wb.create_sheet("Ledger Action Summary")
|
||||
ledger_action_headers = [
|
||||
"Apply", "Previous Ledger", "Previous Group", "PY Closing",
|
||||
"Current Ledger", "Current Group", "CY Opening", "Difference",
|
||||
"Match", "Match Method", "Confidence %", "Correction Status", "Correction Note",
|
||||
]
|
||||
law.append(ledger_action_headers)
|
||||
for row in ledger_action_rows:
|
||||
law.append([
|
||||
"", row.previous_name or "", row.previous_group or "",
|
||||
float(row.previous_closing_balance or 0), row.current_name or "",
|
||||
row.current_group or "", float(row.current_opening_balance or 0),
|
||||
float(row.difference or 0), row.match_status or "", row.match_method or "",
|
||||
int(row.confidence or 0), row.correction_status or "", row.correction_note or "",
|
||||
])
|
||||
|
||||
# Mirror the web Summary -> Stock Differences — Action Required table.
|
||||
saw = wb.create_sheet("Stock Action Summary")
|
||||
stock_action_headers = [
|
||||
"Apply", "Previous Stock Item", "Previous Group", "HSN", "Unit",
|
||||
"PY Closing Qty", "PY Closing Value", "Current Stock Item", "Current Group",
|
||||
"Current HSN", "Current Unit", "CY Opening Qty", "CY Opening Value",
|
||||
"Qty Difference", "Value Difference", "Status", "Match Method",
|
||||
"Confidence %", "Correction Status", "Correction Note",
|
||||
]
|
||||
saw.append(stock_action_headers)
|
||||
for row in stock_action_rows:
|
||||
saw.append([
|
||||
"", row.previous_name or "", row.previous_group or "", row.previous_hsn or "",
|
||||
row.previous_unit or "", float(row.previous_closing_qty or 0),
|
||||
float(row.previous_closing_value or 0), row.current_name or "",
|
||||
row.current_group or "", row.current_hsn or "", row.current_unit or "",
|
||||
float(row.current_opening_qty or 0), float(row.current_opening_value or 0),
|
||||
float(row.quantity_difference or 0), float(row.value_difference or 0),
|
||||
row.match_status or "", row.match_method or "", int(row.confidence or 0),
|
||||
row.correction_status or "", row.correction_note or "",
|
||||
])
|
||||
|
||||
ws = wb.create_sheet("Balance Sheet Ledgers")
|
||||
headers = [
|
||||
"Previous Ledger", "Previous Group", "PY Closing", "Current Ledger",
|
||||
"Current Group", "CY Opening", "Difference", "Status",
|
||||
@@ -337,32 +429,27 @@ def download_report(request: Request, run_id: int, client_id: int | None = None)
|
||||
row.correction_status or "", row.correction_note or "",
|
||||
])
|
||||
|
||||
meta = wb.create_sheet("Summary", 0)
|
||||
meta.append(["Opening Balance Review"])
|
||||
meta.append(["Client", getattr(selected, "client_name", "") or getattr(selected, "name", "") or str(selected.id)])
|
||||
meta.append(["Run ID", run.id])
|
||||
meta.append(["Previous Tally Company", run.previous_company_name])
|
||||
meta.append(["Current Tally Company", run.current_company_name])
|
||||
meta.append(["Scope", "Balance Sheet ledgers and Stock Items only"])
|
||||
meta.append(["Balance Sheet Ledger Rows", len(ledger_rows)])
|
||||
meta.append(["Stock Item Rows", len(stock_rows)])
|
||||
meta.append(["Generated", datetime.now().strftime("%Y-%m-%d %H:%M:%S")])
|
||||
|
||||
header_fill = PatternFill("solid", fgColor="DCE6F1")
|
||||
for sheet in (ws, sws):
|
||||
action_fill = PatternFill("solid", fgColor="FCE4D6")
|
||||
for sheet in (law, saw, ws, sws):
|
||||
sheet.freeze_panes = "A2"
|
||||
sheet.auto_filter.ref = sheet.dimensions
|
||||
for cell in sheet[1]:
|
||||
cell.font = Font(bold=True)
|
||||
cell.fill = header_fill
|
||||
cell.fill = action_fill if sheet in (law, saw) else header_fill
|
||||
cell.alignment = Alignment(vertical="center", wrap_text=True)
|
||||
for col in sheet.columns:
|
||||
letter = col[0].column_letter
|
||||
width = min(38, max(10, max(len(str(c.value or "")) for c in col[:200]) + 2))
|
||||
width = min(42, max(10, max(len(str(c.value or "")) for c in col[:200]) + 2))
|
||||
sheet.column_dimensions[letter].width = width
|
||||
|
||||
meta["A1"].font = Font(bold=True, size=14)
|
||||
meta.column_dimensions["A"].width = 28
|
||||
meta.column_dimensions["A"].width = 38
|
||||
meta.column_dimensions["B"].width = 48
|
||||
for row_no in (12, 18):
|
||||
for cell in meta[row_no]:
|
||||
cell.font = Font(bold=True)
|
||||
cell.fill = header_fill
|
||||
|
||||
output = BytesIO()
|
||||
wb.save(output)
|
||||
|
||||
Reference in New Issue
Block a user