انتقل إلى المحتوى الرئيسي

كيفية إنشاء قالب ميزانية عمومية مخصص في Odoo (2026)

أنشئ ميزانية عمومية مخصصة لـ Odoo 19: مجموعات الحسابات، والإجماليات الهرمية، والأعمدة المقارنة، وتوحيد الشركات المتعددة. تعتمد على XML، وجاهزة للتدقيق.

E
ECOSIRE Research and Development Team
|4 مايو 20268 دقائق قراءة1.5k كلمات|

هذه المقالة متاحة حاليًا باللغة الإنجليزية فقط. الترجمة قريبا.

By the end of this recipe, your Odoo 19 instance will produce a fully customized balance sheet matching your country's statutory format (US GAAP, IFRS, UK FRS 102, India Schedule III) with hierarchical totals, comparative period columns, and multi-currency consolidation.

By the end of this recipe, your Odoo 19 instance will produce a fully customized balance sheet matching your country's statutory format (US GAAP, IFRS, UK FRS 102, India Schedule III) with hierarchical totals, comparative period columns, and multi-currency consolidation. Skill required: developer-accountant hybrid comfortable with XML and Odoo's report engine. Time required: 3 hours setup, 30 minutes per quarterly comparison. ECOSIRE has built statutory balance sheets for clients in 15+ jurisdictions, and the recipe below is the playbook.

The trap most teams fall into: trying to use Odoo's stock balance sheet for statutory filing. The default ships with an IFRS-leaning structure that's wrong for US GAAP (where Inventory comes after Receivables, not before) and very wrong for India Schedule III (which requires Equity at the top, not Assets). The recipe below builds a fully custom report that matches whatever standard your auditor expects.

What you will need

  • Odoo version: 17, 18, or 19 with account_reports (Enterprise) or account_financial_report (OCA Community).
  • Skill: comfortable with XML, basic accounting (knowing what goes on a balance sheet).
  • Existing chart of accounts with account codes following a logical hierarchy (e.g., 1xxx = Assets, 2xxx = Liabilities, 3xxx = Equity).
  • Time: 3 hours.

Step-by-step

1. Define the report structure

Sketch your target layout on paper first:

ASSETS
  Current Assets
    Cash and Cash Equivalents
    Marketable Securities
    Accounts Receivable, net
    Inventory
    Prepaid Expenses
    Total Current Assets
  Non-Current Assets
    Property, Plant and Equipment, net
    Goodwill
    Intangible Assets
    Investments
    Total Non-Current Assets
TOTAL ASSETS

LIABILITIES AND EQUITY
  Current Liabilities
    Accounts Payable
    Accrued Liabilities
    Short-term Debt
    Current Portion of Long-term Debt
    Total Current Liabilities
  Non-Current Liabilities
    Long-term Debt
    Deferred Tax Liability
    Total Non-Current Liabilities
  Equity
    Common Stock
    Retained Earnings
    Other Comprehensive Income
    Total Equity
TOTAL LIABILITIES AND EQUITY

Map each leaf node to a range of account codes.

2. Create a custom report XML

In your custom module, create report/balance_sheet_us_gaap.xml:

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <record id="balance_sheet_us_gaap" model="account.report">
        <field name="name">Balance Sheet (US GAAP)</field>
        <field name="filter_period_comparison">1</field>
        <field name="filter_growth_comparison">1</field>
        <field name="filter_journals">1</field>
        <field name="filter_unfold_all">1</field>
        <field name="filter_hierarchy">1</field>
        <field name="root_report_id" ref="account_reports.balance_sheet"/>
        <field name="column_ids" eval="[(0,0,{'name': 'Balance', 'expression_label': 'balance'})]"/>
    </record>

    <!-- ASSETS -->
    <record id="bs_assets" model="account.report.line">
        <field name="report_id" ref="balance_sheet_us_gaap"/>
        <field name="name">ASSETS</field>
        <field name="sequence">10</field>
        <field name="hierarchy_level">0</field>
    </record>

    <record id="bs_current_assets" model="account.report.line">
        <field name="report_id" ref="balance_sheet_us_gaap"/>
        <field name="parent_id" ref="bs_assets"/>
        <field name="name">Current Assets</field>
        <field name="sequence">20</field>
        <field name="hierarchy_level">1</field>
    </record>

    <record id="bs_cash" model="account.report.line">
        <field name="report_id" ref="balance_sheet_us_gaap"/>
        <field name="parent_id" ref="bs_current_assets"/>
        <field name="name">Cash and Cash Equivalents</field>
        <field name="sequence">30</field>
        <field name="hierarchy_level">2</field>
        <field name="expression_ids" eval="[(0,0,{
            'label': 'balance',
            'engine': 'domain',
            'formula': [('account_id.account_type','=','asset_cash')],
            'subformula': 'sum',
        })]"/>
    </record>

    <record id="bs_ar" model="account.report.line">
        <field name="report_id" ref="balance_sheet_us_gaap"/>
        <field name="parent_id" ref="bs_current_assets"/>
        <field name="name">Accounts Receivable, net</field>
        <field name="sequence">40</field>
        <field name="hierarchy_level">2</field>
        <field name="expression_ids" eval="[(0,0,{
            'label': 'balance',
            'engine': 'domain',
            'formula': [('account_id.account_type','=','asset_receivable')],
            'subformula': 'sum',
        })]"/>
    </record>

    <!-- ... continue for inventory, PPE, payables, debt, equity ... -->

    <record id="bs_total_assets" model="account.report.line">
        <field name="report_id" ref="balance_sheet_us_gaap"/>
        <field name="parent_id" ref="bs_assets"/>
        <field name="name">TOTAL ASSETS</field>
        <field name="sequence">200</field>
        <field name="hierarchy_level">1</field>
        <field name="expression_ids" eval="[(0,0,{
            'label': 'balance',
            'engine': 'aggregation',
            'formula': 'bs_current_assets.balance + bs_noncurrent_assets.balance',
        })]"/>
    </record>
</odoo>

The key XML constructs: engine='domain' for direct account-domain lookups, engine='aggregation' for sums of other lines.

3. Add the Equity computation with retained earnings

Retained earnings is the accumulated net income from prior periods plus current year-to-date income. Compute it explicitly:

<record id="bs_retained_earnings" model="account.report.line">
    <field name="report_id" ref="balance_sheet_us_gaap"/>
    <field name="parent_id" ref="bs_equity"/>
    <field name="name">Retained Earnings</field>
    <field name="sequence">370</field>
    <field name="hierarchy_level">2</field>
    <field name="expression_ids" eval="[
        (0,0,{
            'label': 'balance',
            'engine': 'domain',
            'formula': [('account_id.account_type','in',['equity','equity_unaffected'])],
            'subformula': 'sum',
        })
    ]"/>
</record>

The trick: Odoo automatically includes the current period's net income in equity_unaffected if you have closed prior periods. Confirm by checking Settings > Companies > Accounting > "Lock Date for Non-Advisers".

Verification: TOTAL ASSETS = TOTAL LIABILITIES + EQUITY exactly, to the cent.

4. Add comparison columns

In the main report record, add columns for prior period and prior year:

<field name="column_ids" eval="[
    (0,0,{'name': 'Current Period', 'expression_label': 'balance'}),
    (0,0,{'name': 'Prior Period', 'expression_label': 'balance', 'date_scope': 'previous_period'}),
    (0,0,{'name': 'Prior Year', 'expression_label': 'balance', 'date_scope': 'previous_year'}),
]"/>

Verification: the report renders three columns side-by-side.

5. Configure multi-company consolidation

For a group with subsidiaries, add a column per company plus a consolidation total:

<field name="column_ids" eval="[
    (0,0,{'name': 'Parent Co.', 'expression_label': 'balance', 'company_id_filter': company_parent}),
    (0,0,{'name': 'Sub Co. A', 'expression_label': 'balance', 'company_id_filter': company_a}),
    (0,0,{'name': 'Sub Co. B', 'expression_label': 'balance', 'company_id_filter': company_b}),
    (0,0,{'name': 'Eliminations', 'expression_label': 'balance', 'company_id_filter': elim_company}),
    (0,0,{'name': 'Consolidated', 'expression_label': 'balance', 'aggregate': 'sum'}),
]"/>

For complex inter-company eliminations, use the Enterprise Consolidation module instead of doing it in the report.

Verification: parent + subs + elims = consolidated total.

6. Add country-specific overrides

For India Schedule III, the order is reversed (Equity & Liabilities first). Inherit the report:

<record id="balance_sheet_india_sch3" model="account.report">
    <field name="name">Balance Sheet (India Schedule III)</field>
    <field name="root_report_id" ref="balance_sheet_us_gaap"/>
    <!-- override the structure -->
</record>

<record id="bs_india_equity_liab" model="account.report.line">
    <field name="report_id" ref="balance_sheet_india_sch3"/>
    <field name="name">EQUITY AND LIABILITIES</field>
    <field name="sequence">5</field>
    <!-- Schedule III mandates this header first -->
</record>

Verification: India statutory filing accepts the PDF without comment.

7. Lock fiscal periods

Before issuing the report to auditors, lock the period: Settings > Accounting > Lock Date. This prevents anyone from posting to the closed period. Verification: trying to post a JE to the locked period raises a clear error.

8. Schedule monthly export

Use the same cron pattern as the cash flow recipe to email the PDF to your CFO and auditor on the 5th of every month. Include a one-page commentary section auto-generated from the growth_comparison percentages.

Verification: the email arrives with PDF attached.

Common mistakes

  • Computing Total Equity manually. Always derive it from account types so the BS balances automatically.
  • Hardcoding account codes in domain filters. Use account_type instead — survives chart-of-accounts restructures.
  • Forgetting to handle minority interest. For consolidated reports with non-100%-owned subsidiaries, add a Minority Interest line in equity.
  • Not testing fiscal year transitions. Run the report on December 31 and January 1 — make sure beginning equity carries cleanly.
  • Ignoring forex revaluation. Foreign-subsidiary balances must be translated; assets+liabilities at period-end rate, equity at historical rate, with CTA balancing the difference.

Going further

Branch-level balance sheet: filter by analytic_account_id for branch-specific BS within a single legal entity. Useful for franchise operators or retail chains where each store needs its own BS for performance reviews. Add a branch dimension column and produce an internal P&L per branch alongside.

Comparative consolidation: side-by-side Q1/Q2/Q3/Q4 + YTD columns for board packs. The Financial Reports engine supports up to 16 comparison columns natively. For full-year quarterly view: Q1, Q2, Q3, Q4, YTD, with Q-over-Q variance percentage as additional column.

Drill-down to JE: every line on Odoo's BS is clickable to the underlying journal entries. Useful during audit walkthroughs — auditor clicks Total Receivables, sees the constituent invoices, ages them, samples a few for confirmations. Make sure your team knows how to use this; saves days of audit prep.

Live KPI tile: pair this with how to build an Odoo dashboard tile to surface "Total Assets" on the executive dashboard. Add side-by-side ratios: current ratio (CA/CL), quick ratio ((CA-Inv)/CL), debt-to-equity (Total Debt / Total Equity), interest coverage. Each ratio is a single DAX measure once the BS lines exist.

Footnotes section: regulated jurisdictions require footnotes (commitments, contingencies, related-party transactions). Build a separate "Footnotes" tab on the report with customizable narrative blocks pulled from account.note records.

Period locking with audit log: pair statutory reports with formal period locking and an audit log of who locked what when. Settings > Accounting > "Lock Date for All Users" prevents back-posting. Combine with mail.activity so the close team gets a checklist of pre-lock validations.

XBRL export: jurisdictions like UK/Ireland require XBRL filing. Add an export option that maps your BS lines to the appropriate XBRL taxonomy. Saves the £500-£2000 per year that companies pay for separate XBRL tools.

Restatement handling: when prior periods need adjustment (post-audit), Odoo Enterprise has a "Period Adjustment" wizard that creates the restating entries with a clear audit trail. Your custom BS report should respect the period lock and show before/after restatement columns when present.

For statutory reporting setups across multiple jurisdictions including IFRS-to-GAAP reconciliations, ECOSIRE accounting services deliver fully audited templates. Pair this with how to build a cash flow statement.

Frequently Asked Questions

Why does my BS not balance by a few cents?

Almost always rounding. Use the "Round Globally" tax method on company config. Otherwise per-line rounding accumulates pennies of difference.

Can I add custom KPIs at the bottom?

Yes — add report lines after Total Equity using engine='aggregation' with formulas like bs_current_assets.balance / bs_current_liabilities.balance for current ratio.

How do I handle foreign-currency transactions in BS?

Tag the relevant accounts with currency_id set to the foreign currency. The BS report shows balances in company currency by default; foreign-currency-balance can be added as a separate column.

What about India Companies Act 2013 schedule changes?

Schedule III amendments require disclosing aging buckets for receivables and trade payables. Add aging-bucket lines that filter account_move_line.date_maturity.

For multi-jurisdiction statutory reporting including audit-firm-specific formats, ECOSIRE accounting services handle the configuration. Or read how to build an AR/AP aging report for the working-capital deep-dive.

الوسوم:odootutorialguide
مشاركة:
E

بقلم

ECOSIRE Team

Technical Writing

The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.

ECOSIRE

قم بتحويل أعمالك باستخدام Odoo ERP

تنفيذ وتخصيص ودعم خبير Odoo لتبسيط عملياتك.