package models
import (
"fmt"
"strings"
"odoo-go/pkg/orm"
)
// RenderReportHTML generates an HTML table for a report type.
// Mirrors: odoo/addons/account_reports/models/account_report.py _get_html()
//
// Supports: trial_balance, balance_sheet, profit_loss, aged_receivable,
// aged_payable, general_ledger.
func RenderReportHTML(env *orm.Environment, reportType string) (string, error) {
var data interface{}
var err error
switch reportType {
case "trial_balance":
data, err = generateTrialBalance(env)
case "balance_sheet":
data, err = generateBalanceSheet(env)
case "profit_loss":
data, err = generateProfitLoss(env)
case "aged_receivable":
data, err = generateAgedReport(env, "asset_receivable")
case "aged_payable":
data, err = generateAgedReport(env, "liability_payable")
case "general_ledger":
data, err = generateGeneralLedger(env)
default:
return "", fmt.Errorf("unknown report: %s", reportType)
}
if err != nil {
return "", err
}
result, ok := data.(map[string]interface{})
if !ok {
return "", fmt.Errorf("invalid report data")
}
lines, _ := result["lines"].([]map[string]interface{})
var b strings.Builder
b.WriteString(`
`)
// Build table based on report type
switch reportType {
case "trial_balance":
b.WriteString("Trial Balance
")
b.WriteString(`| Code | Account | Debit | Credit | Balance |
`)
for _, l := range lines {
b.WriteString(fmt.Sprintf("| %v | %v | %.2f | %.2f | %.2f |
",
l["code"], l["name"], toF(l["debit"]), toF(l["credit"]), toF(l["balance"])))
}
b.WriteString("
")
case "balance_sheet":
b.WriteString("Balance Sheet
")
b.WriteString(`| Section | Code | Account | Balance |
`)
for _, l := range lines {
b.WriteString(fmt.Sprintf("| %v | %v | %v | %.2f |
",
l["section"], l["code"], l["name"], toF(l["balance"])))
}
b.WriteString("
")
case "profit_loss":
b.WriteString("Profit & Loss
")
b.WriteString(`| Section | Code | Account | Amount |
`)
for _, l := range lines {
b.WriteString(fmt.Sprintf("| %v | %v | %v | %.2f |
",
l["section"], l["code"], l["name"], toF(l["balance"])))
}
b.WriteString("
")
case "aged_receivable", "aged_payable":
title := "Aged Receivable"
if reportType == "aged_payable" {
title = "Aged Payable"
}
b.WriteString(fmt.Sprintf("%s
", title))
b.WriteString(`| Partner | Current | 1-30 | 31-60 | 61-90+ | Total |
`)
for _, l := range lines {
b.WriteString(fmt.Sprintf("| %v | %.2f | %.2f | %.2f | %.2f | %.2f |
",
l["partner"], toF(l["current"]), toF(l["1-30"]), toF(l["31-60"]), toF(l["61-90+"]), toF(l["total"])))
}
b.WriteString("
")
case "general_ledger":
b.WriteString("General Ledger
")
b.WriteString(`| Account | Move | Date | Label | Debit | Credit |
`)
for _, l := range lines {
b.WriteString(fmt.Sprintf("| %v %v | %v | %v | %v | %.2f | %.2f |
",
l["account_code"], l["account_name"], l["move"], l["date"], l["label"],
toF(l["debit"]), toF(l["credit"])))
}
b.WriteString("
")
}
b.WriteString("")
return b.String(), nil
}
// toF converts various numeric types to float64 for formatting.
func toF(v interface{}) float64 {
switch n := v.(type) {
case float64:
return n
case int64:
return float64(n)
case int:
return float64(n)
case int32:
return float64(n)
}
return 0
}