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(``) for _, l := range lines { b.WriteString(fmt.Sprintf("", l["code"], l["name"], toF(l["debit"]), toF(l["credit"]), toF(l["balance"]))) } b.WriteString("
CodeAccountDebitCreditBalance
%v%v%.2f%.2f%.2f
") case "balance_sheet": b.WriteString("

Balance Sheet

") b.WriteString(``) for _, l := range lines { b.WriteString(fmt.Sprintf("", l["section"], l["code"], l["name"], toF(l["balance"]))) } b.WriteString("
SectionCodeAccountBalance
%v%v%v%.2f
") case "profit_loss": b.WriteString("

Profit & Loss

") b.WriteString(``) for _, l := range lines { b.WriteString(fmt.Sprintf("", l["section"], l["code"], l["name"], toF(l["balance"]))) } b.WriteString("
SectionCodeAccountAmount
%v%v%v%.2f
") case "aged_receivable", "aged_payable": title := "Aged Receivable" if reportType == "aged_payable" { title = "Aged Payable" } b.WriteString(fmt.Sprintf("

%s

", title)) b.WriteString(``) for _, l := range lines { b.WriteString(fmt.Sprintf("", l["partner"], toF(l["current"]), toF(l["1-30"]), toF(l["31-60"]), toF(l["61-90+"]), toF(l["total"]))) } b.WriteString("
PartnerCurrent1-3031-6061-90+Total
%v%.2f%.2f%.2f%.2f%.2f
") case "general_ledger": b.WriteString("

General Ledger

") b.WriteString(``) for _, l := range lines { b.WriteString(fmt.Sprintf("", l["account_code"], l["account_name"], l["move"], l["date"], l["label"], toF(l["debit"]), toF(l["credit"]))) } b.WriteString("
AccountMoveDateLabelDebitCredit
%v %v%v%v%v%.2f%.2f
") } 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 }