会计本地化

警告

本教程需要了解如何在Odoo中构建模块的知识(请参阅 开始)。

安装过程

在安装 account 模块时,与公司国家代码对应的本地化模块会自动安装。如果没有设置国家代码或找不到本地化模块,则默认安装 l10n_generic_coa (US) 本地化模块。详细信息请查看 post init hook

例如, l10n_ch <https://github.com/odoo/odoo/blob/16.0/addons/l10n_ch> _ 将会被安装,如果公司的国家是 Switzerland

构建本地化模块

一个基本的 l10n_XX 模块的结构可以用下面的 __manifest__.py 文件来描述:

{
    "name": "COUNTRY - Accounting",
    "version": "1.0.0",
    "category": "Accounting/Localizations/Account Charts",
    "license": "LGPL-3",
    "depends": [
        "account",
        # "l10n_multilang",
    ],
    "data": [
        # Chart of Accounts
        "data/account_chart_template_data.xml",
        "data/account_account_tag_data.xml",
        "data/account.account.template.csv",
        "data/account.group.template.csv",

        # Taxes
        "data/account_tax_group_data.xml",
        "data/account_tax_report_data.xml",
        "data/account_tax_template_data.xml",
        "data/account_fiscal_position_template_data.xml",
        "data/account_account_template_post_data.xml",

        "data/account_chart_post_data.xml",
        "data/account_chart_template_try_loading.xml",

        # Views and others
        "views/xxxmodel_views.xml"
    ],
    "demo": [
        "demo/demo_company.xml",
    ]
}

在第一个文件 data/account_chart_template_data.xml 中,我们设置了会计科目表的名称以及一些基本字段。

Example

addons/l10n_ch/data/l10n_ch_chart_data.xml

        <record id="l10nch_chart_template" model="account.chart.template">
            <field name="name">Plan comptable 2015 (Suisse)</field>
            <field name="code_digits">4</field>
            <field name="bank_account_code_prefix">102</field>
            <field name="cash_account_code_prefix">100</field>
            <field name="transfer_account_code_prefix">1090</field>
            <field name="currency_id" ref="base.CHF"/>
            <field name="country_id" ref="base.ch"/>
            <field name="spoken_languages" eval="'it_IT;de_DE;de_CH;fr_FR;fr_CH'"/>
        </record>

注解

推荐的 xmlid 记录是 chart_template。如果您需要多个会计科目表,您可以添加一些后缀,例如 chart_template_XXX

科目表

账户标签

标签是一种对账户进行排序的方式。例如,假设您想创建一个包含多行的财务报告,但是您无法找到一个规则来根据其 code 分配账户。解决方案是使用标签,为每个报告行使用一个标签,以按照您的要求筛选账户。

将标签放在 data/account_account_tag_data.xml 文件中。

Example

addons/l10n_lt/data/account.account.template.csv

"id","name","code","account_type","chart_template_id/id","tag_ids/id","reconcile"
"account_account_template_1130","Software Acquisition Cost",1130,"asset_non_current","l10n_lt.account_chart_template_lithuania","l10n_lt.account_account_tag_a_1_3","False"
"account_account_template_1138","Amortization of Software Value (-)",1138,"asset_non_current","l10n_lt.account_chart_template_lithuania","l10n_lt.account_account_tag_a_1_3","False"
"account_account_template_1200","Land Acquisition Cost",1200,"asset_fixed","l10n_lt.account_chart_template_lithuania","l10n_lt.account_account_tag_a_2_1","False"
"account_account_template_1201","Change of Land Value after Revaluation",1201,"asset_fixed","l10n_lt.account_chart_template_lithuania","l10n_lt.account_account_tag_a_2_1","False"

Example

addons/l10n_at/data/account_account_template.xml

        <record id="chart_at_template_0010" model="account.account.template">
          <field name="name">Aufwendungen für das Ingangsetzen und Erweitern eines Betriebes</field>
          <field name="code">0010</field>
          <field name="reconcile" eval="False"/>
          <field name="chart_template_id" ref="l10n_at_chart_template"/>
          <field name="account_type">asset_non_current</field>
          <field name="tag_ids" eval="[(6, 0, [ref('l10n_at.account_tag_l10n_at_AAI1')])]" />
        </record>

账户

显然, 科目表 不能没有 账户 。你需要在 data/account.account.template.csv 中指定它们。

Example

addons/l10n_ch/data/account.account.template.csv

"id","name","code","account_type","chart_template_id/id","reconcile"
"ch_coa_1060","Securities (with stock exchange price)","1060","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1069","Accumulated depreciation on securities","1069","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1091","Transfer account: Salaries","1091","asset_current","l10n_ch.l10nch_chart_template","True"
"ch_coa_1099","Transfer account: miscellaneous","1099","asset_current","l10n_ch.l10nch_chart_template","True"
"ch_coa_1100","Accounts receivable from goods and services (Debtors)","1100","asset_receivable","l10n_ch.l10nch_chart_template","True"
"ch_coa_1101","Receivable (PoS)","1101","asset_receivable","l10n_ch.l10nch_chart_template","True"
"ch_coa_1109","Del credere (Acc. depr. on debtors)","1109","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1140","Advances and loans","1140","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1149","Advances and loans adjustments","1149","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1170","Input Tax (VAT) receivable on material, goods, services, energy","1170","asset_current","l10n_ch.l10nch_chart_template","False"
"ch_coa_1171","Input Tax (VAT) receivable on investments, other operating expenses","1171","asset_current","l10n_ch.l10nch_chart_template","False"

CSV 是首选,但您也可以使用 XML 格式。

Example

addons/l10n_at/data/account_account_template.xml

        <record id="chart_at_template_0010" model="account.account.template">
          <field name="name">Aufwendungen für das Ingangsetzen und Erweitern eines Betriebes</field>
          <field name="code">0010</field>
          <field name="reconcile" eval="False"/>
          <field name="chart_template_id" ref="l10n_at_chart_template"/>
          <field name="account_type">asset_non_current</field>
          <field name="tag_ids" eval="[(6, 0, [ref('l10n_at.account_tag_l10n_at_AAI1')])]" />
        </record>

警告

  • 避免使用流动性 account.account.type!实际上,银行和现金账户是在本地化模块安装时直接创建的,然后与 account.journal 相关联。

  • 一般情况下,只需要一个应付/应收账户。但是我们还需要定义一个点 of Sale 应收账户(在 CoA 中链接)。

  • 不要创建太多账户:200-300个足够了。但是,我们主要是要找到一个良好的平衡点,使大多数公司在之后使用时,会对会计科目表进行最小限度的调整。

下一步,会在一个单独的文件中设置账户表的其他设置,因为我们需要首先提供一个 账户列表。在 data/account_chart_post_data.xml 中,我们设置了一些默认账户:

Example

addons/l10n_ch/data/l10n_ch_chart_post_data.xml

    <record id="l10nch_chart_template" model="account.chart.template">
        <field name="property_account_receivable_id" ref="ch_coa_1100"/>
        <field name="property_account_payable_id" ref="ch_coa_2000"/>
        <field name="property_account_expense_categ_id" ref="ch_coa_4200"/>
        <field name="property_account_income_categ_id" ref="ch_coa_3200"/>
        <field name="income_currency_exchange_account_id" ref="ch_coa_3806"/>
        <field name="expense_currency_exchange_account_id" ref="ch_coa_4906"/>
        <field name="default_pos_receivable_account_id" ref="ch_coa_1101" />
        <field name="account_journal_early_pay_discount_loss_account_id" ref="ch_coa_4901"/>
        <field name="account_journal_early_pay_discount_gain_account_id" ref="ch_coa_3801"/>
        <field name="property_tax_payable_account_id" ref="ch_coa_2201"/>
        <field name="property_tax_receivable_account_id" ref="ch_coa_1176"/>
        <field name="default_cash_difference_expense_account_id" ref="ch_coa_4991"/>
        <field name="default_cash_difference_income_account_id" ref="ch_coa_4992"/>
    </record>

账户组

账户组允许描述账户表的分层结构。需要在报告中激活过滤器,然后当您展开成日志条目时,它将显示账户的父级。

它使用前缀 start/end,所以每个代码以 startend 之间的内容开头的账户都将有此 account.group 作为父组。此外,账户组也可以有一个父账户组,以形成层次结构。

Example

addons/l10n_il/data/account.group.template.csv

编号

代码前缀开始

代码前缀结尾

名称

图表模板 ID/编号

il_group_100100

100100

100499

固定资产

l10n_il.il_chart_template

il_group_101110

101110

101400

流动资产

l10n_il.il_chart_template

il_group_101401

101401

101799

银行和现金

l10n_il.il_chart_template

il_group_111000

111000

111999

流动负债

l10n_il.il_chart_template

il_group_112000

112000

112210

非流动负债

l10n_il.il_chart_template

il_group_200000

200000

200199

销售收入

l10n_il.il_chart_template

il_group_200200

200200

200300

其他收入

l10n_il.il_chart_template

il_group_201000

201000

201299

商品成本

l10n_il.il_chart_template

il_group_202000

202000

220900

费用

l10n_il.il_chart_template

il_group_300000

300000

399999

股本和股份

l10n_il.il_chart_template

税费

另请参阅

要添加税收,您首先需要指定税收组。通常,每个税率只需要一个税收组,除了0%之外,您经常需要区分免税、0%、不适用等税收。此模型只有两个必填字段: namecountry 。创建文件 data/account_tax_group_data.xml 并列出组:

<odoo>
    <data noupdate="1">
        <record id="tax_group_tva_0" model="account.tax.group">
            <field name="name">TVA 0%</field>
            <field name="country_id" ref="base.ch"/>
        </record>

        ...
    </data>
</odoo>

Example

addons/l10n_ch/data/account_tax_group_data.xml

        <!-- Account Tax Group (pre-2024 rates change) -->
        <record id="tax_group_tva_0" model="account.tax.group">
            <field name="name">VAT 0%</field>
            <field name="country_id" ref="base.ch"/>
        </record>
        <record id="tax_group_tva_25" model="account.tax.group">
            <field name="name">VAT 2.5%</field>
            <field name="country_id" ref="base.ch"/>
        </record>
        <record id="tax_group_tva_37" model="account.tax.group">
            <field name="name">VAT 3.7%</field>
            <field name="country_id" ref="base.ch"/>
        </record>
        <record id="tax_group_tva_77" model="account.tax.group">
            <field name="name">VAT 7.7%</field>
            <field name="country_id" ref="base.ch"/>
        </record>
        <record id="tax_group_tva_100" model="account.tax.group">
            <field name="name">VAT 100%</field>
            <field name="country_id" ref="base.ch"/>
        </record>
        <!-- Account Tax Group (post-2024 rates change) -->
        <record id="tax_group_vat_26" model="account.tax.group">
            <field name="name">VAT 2.6%</field>
            <field name="country_id" ref="base.ch"/>
        </record>
        <record id="tax_group_vat_38" model="account.tax.group">
            <field name="name">VAT 3.8%</field>
            <field name="country_id" ref="base.ch"/>
        </record>
        <record id="tax_group_vat_81" model="account.tax.group">
            <field name="name">VAT 8.1%</field>
            <field name="country_id" ref="base.ch"/>
        </record>

Example

addons/l10n_uk/data/account.tax.group.csv

id,name,country_id/id
tax_group_0,TAX 0%,base.uk
tax_group_5,TAX 5%,base.uk
tax_group_175,TAX 17.5%,base.uk
tax_group_20,TAX 20%,base.uk

现在,您可以通过 data/account_tax_template_data.xml 文件添加税项。您定义的第一个购买/销售税项也将成为产品的默认购买/销售税项。

Example

addons/l10n_ae/data/account_tax_template_data.xml

    <record id="uae_sale_tax_5_dubai" model="account.tax.template">
        <field name="name">VAT 5% (Dubai)</field>
        <field name="type_tax_use">sale</field>
        <field name="amount">5</field>
        <field name="amount_type">percent</field>
        <field name="description">VAT 5%</field>
        <field name="tax_group_id" ref="ae_tax_group_5"/>
        <field name="chart_template_id" ref="uae_chart_template_standard"/>
        <field name="invoice_repartition_line_ids" eval="[(5, 0, 0),
            (0,0, {
                'repartition_type': 'base',
                'plus_report_expression_ids': [ref('tax_report_line_standard_rated_supplies_base_dubai_tag')],
            }),
            (0,0, {
                'repartition_type': 'tax',
                'account_id': ref('uae_account_201017'),
                'plus_report_expression_ids': [ref('tax_report_line_standard_rated_supplies_vat_dubai_tag')],
            }),
        ]"/>
        <field name="refund_repartition_line_ids" eval="[(5, 0, 0),
            (0,0, {
                'repartition_type': 'base',
                'minus_report_expression_ids': [ref('tax_report_line_standard_rated_supplies_base_dubai_tag')],
            }),
            (0,0, {
                'repartition_type': 'tax',
                'account_id': ref('uae_account_201017'),
                'minus_report_expression_ids': [ref('tax_report_line_standard_rated_supplies_vat_dubai_tag')],
            }),
        ]"/>
    </record>

如果某些账户应该使用默认税率,您可以在 data/account_account_template_post_data.xml 中设置它们

税务报告

Enterprise feature

税务报告在 发票 (account) 应用程序中声明,但是只有在安装了 会计 (account_accountant) 后才能访问该报告。

在前一节中,您注意到了字段 invoice_repartition_line_idsrefund_repartition_line_ids,可能对它们一无所知。好消息是:您并不孤单,对此一无所知。坏消息是:您必须自己弄明白一点。这个主题很复杂。确实:

digraph foo {
  graph [
    newrank=true,
    overlap=false,
  ];
  node [
    fontname="Ubuntu"
    fontsize=10,
    style="filled,setlinewidth(6)",
    shape=box,
    height=0.1,
    width=0.1,
  ];
  edge [
    fontsize=8,
  ];
  res_country[label="res.country", fillcolor=white, penwidth=1];
  subgraph cluster_invoice {
    style = filled;
    label = "Invoices";
    color = lightyellow;
    node [style=filled, color=white];
    edge [fontsize=8,];
    account_move_line[label="account.move.line"]
    account_tax[label="account.tax"]
    account_tax_repartition_line[label="account.tax.repartition.line"];
    account_account_tag[label="account.account.tag"];
    account_move_line -> account_tax [label="tax_ids | tax_line_ids"];
    account_move_line -> account_tax_repartition_line [label="tax_repartition_line_id"];
    account_move_line -> account_account_tag [label="tag_ids"];
    account_tax_repartition_line -> account_account_tag [label="tag_ids"];
    account_tax -> account_tax_repartition_line [label="1 for base, 1..* for tax amount"];
  }
  subgraph cluster_reporting {
    style = filled;
    label = "Reporting";
    color = mistyrose;
    node [style=filled, color=white];
    edge [fontsize=8,];
    account_tax_report [label="account.report"];
    account_tax_report_line [label="account.report.line"];
    account_report_expression [label="account.report.expression"];
    account_tax_report -> account_tax_report_line [label="0..*"]
  }
  subgraph cluster_templates {
    style = filled;
    label = "Templates";
    color = lightblue;
    node [style=filled, color=white];
    edge [fontsize=8,];
    account_tax_template[label="account.tax.template"];
    account_tax_repartition_line_template[label="account.tax.repartition.line.template"];
    account_tax_template -> account_tax_repartition_line_template [label="1 for base, 1..* for tax amount"];
  }
  {
    rank=same;
    account_move_line;
    account_tax_report;
  }
  {
    rank=same;
    account_tax;
    account_tax_repartition_line;
    account_account_tag;
    res_country;
  }
  {
    rank=same;
    account_report_expression;
    account_tax_template;
    account_tax_repartition_line_template;
  }
  account_tax -> account_tax_template [label="    Creates when\n    installing CoA", dir=back];
  account_tax_repartition_line -> account_tax_repartition_line_template[label="    Creates when\n   installing CoA", dir=back];
  account_tax_repartition_line_template -> account_account_tag [label="tag_ids"];
  account_tax_report_line -> account_report_expression [label="0..*"];
  account_tax_report_line -> account_tax_report_line [label="children_ids"];
  account_report_expression -> account_account_tag [label="Engine tax_tags 1..*"];
  account_tax_report -> res_country [label="0..1"];
  account_account_tag -> res_country [label="0..1"];
}

简单来说,在税务模板中,您可以在发票/退款分配行中指示税金的基数或百分比应该报告在哪个报告行中(通过 minus/plus_report_line_ids 字段)。当您在Odoo界面中检查税务配置时(或查看文档 Tax ReferencesTax Repartition References ),这也变得清晰明了。

所以,一旦您正确配置了税收,您只需要添加 :文件:data/account_tax_report_data.xml 文件,并为您的 account.report 添加一条记录。为了将其视为税务报告,您需要 为其提供正确的 root_report_id

<odoo>
    <record id="tax_report" model="account.report">
        <field name="name">Tax Report</field>
        <field name="root_report_id" ref="account.generic_tax_report"/>
        <field name="country_id" ref="base.XX"/>
    </record>

    ...
</odoo>

… 接着是其行的声明,作为 account.report.line 记录。

Example

addons/l10n_au/data/account_tax_report_data.xml

    <record id="tax_report" model="account.report">
        <field name="name">Tax Report</field>
        <field name="root_report_id" ref="account.generic_tax_report"/>
        <field name="country_id" ref="base.au"/>
        <field name="filter_fiscal_position" eval="True"/>
        <field name="availability_condition">country</field>
        <field name="column_ids">
            <record id="tax_report_balance" model="account.report.column">
                <field name="name">Balance</field>
                <field name="expression_label">balance</field>
            </record>
        </field>
        <field name="line_ids">
            <record id="account_tax_report_gstrpt_sale_total" model="account.report.line">
                <field name="name">GST amounts you owe the Tax Office from sales</field>
                <field name="children_ids">
                    <record id="account_tax_report_gstrpt_g1" model="account.report.line">
                        <field name="name">G1: Total Sales (including any GST)</field>
                        <field name="code">G1</field>
                        <field name="expression_ids">
                            <record id="account_tax_report_gstrpt_g1_tag" model="account.report.expression">
                                <field name="label">balance</field>
                                <field name="engine">tax_tags</field>
                                <field name="formula">G1</field>
                            </record>
                        </field>
                        <field name="children_ids">
                            <record id="account_tax_report_gstrpt_g2" model="account.report.line">
                                <field name="name">G2: Export sales</field>
                                <field name="code">G2</field>
                                <field name="expression_ids">
                                    <record id="account_tax_report_gstrpt_g2_tag" model="account.report.expression">
                                        <field name="label">balance</field>
                                        <field name="engine">tax_tags</field>
                                        <field name="formula">G2</field>
                                    </record>
                                </field>
                            </record>

财政状况

data/account_fiscal_position_template_data.xml 文件中指定财务位置。

Example

addons/l10n_es/data/account_fiscal_position_template_data.xml

        <record id="fp_nacional" model="account.fiscal.position.template">
            <field name="sequence">1</field>
            <field name="name">Régimen Nacional</field>
            <field name="chart_template_id" ref="account_chart_template_common"/>
            <field name="auto_apply" eval="True"/>
            <field name="vat_required" eval="True"/>
            <field name="country_id" ref="base.es"/>
        </record>

最后的步骤

安装本地化模块的最后一步是尝试将其会计科目表应用于当前公司(如果尚未存在)。文件 data/account_chart_template_try_loading.xml 负责此操作。

Example

addons/l10n_ch/data/account_chart_template_data.xml

        <function model="account.chart.template" name="try_loading">
            <value eval="[ref('l10n_ch.l10nch_chart_template')]"/>
        </function>

最后,您可以添加一个演示公司,以便可以在演示模式下轻松测试本地化。

Example

addons/l10n_ch/demo/demo_company.xml

    <record id="partner_demo_company_ch" model="res.partner">
        <field name="name">CH Company</field>
        <field name="vat">CHE-530781296TVA</field>
        <field name="street">14 Meierskappelerstrasse</field>
        <field name="city">Risch-Rotkreuz</field>
        <field name="country_id" ref="base.ch"/>
        
        <field name="zip">6343</field>
        <field name="phone">+41 78 123 45 67</field>
        <field name="email">info@company.chexample.com</field>
        <field name="website">www.chexample.com</field>
    </record>

    <record id="partner_demo_company_bank_account" model="res.partner.bank">
        <field name="acc_type">iban</field>
        <field name="acc_number">CH4431999123000889012</field>
        <field name="bank_id" ref="base.bank_ing" />
        <field name="partner_id" ref="l10n_ch.partner_demo_company_ch"/>
    </record>

    <record id="demo_company_ch" model="res.company">
        <field name="name">CH Company</field>
        <field name="partner_id" ref="partner_demo_company_ch"/>
    </record>

    <function model="res.company" name="_onchange_country_id">
        <value eval="[ref('demo_company_ch')]"/>
    </function>

    <function model="res.users" name="write">
        <value eval="[ref('base.user_root'), ref('base.user_admin'), ref('base.user_demo')]"/>
        <value eval="{'company_ids': [(4, ref('l10n_ch.demo_company_ch'))]}"/>
    </function>

    <function model="account.chart.template" name="try_loading">
        <value eval="[ref('l10n_ch.l10nch_chart_template')]"/>
        <value model="res.company" eval="obj().env.ref('l10n_ch.demo_company_ch')"/>
    </function>

会计报告

Enterprise feature

另请参阅

报告

应通过单独的模块 l10n_XX_reports 添加会计报告,该模块应放在 enterprise 仓库 中。

基本 __manifest__.py 文件如下所示:

{
    "name": "COUNTRY - Accounting Reports",
    "category": "Accounting/Localizations/Reporting",
    "version": "1.0.0",
    "license": "OEEL-1",
    "depends": [
        "l10n_XX", "account_reports"
    ],
    "data": [
        "data/balance_sheet.xml",
        "data/profit_and_loss.xml",
    ],
    "auto_install": True,
}

财务报告的功能概述在这里: 报告 .

一些好的例子:

您可以在此处查看字段的含义:

如果您给报表指定了 root_report_id,它现在可以在其变体选择器中使用。如果没有,您仍然需要为其添加一个菜单项。可以通过在报表的表单视图中点击 操作 ‣ 创建菜单项 来创建一个默认菜单项。然后需要刷新页面才能看到它。或者,要在 报告 菜单中创建一个专门的新报表部分,您需要在主要的 l10n_XX 模块中创建一个新的 ir.ui.menu 记录,并在新的报表 XML 文件中创建一个新的 ir.actions.client,该 ir.actions.client 调用 account.report 并传入新的 报表 id。然后,在操作模型中将新菜单设置为 parent_id 字段。