Initial commit

This commit is contained in:
gsinghpal
2026-02-22 01:22:18 -05:00
commit 5200d5baf0
2394 changed files with 386834 additions and 0 deletions

View File

@@ -0,0 +1,162 @@
"""
Fusion Accounting - Fiscal Categories
Provides a classification system for grouping general ledger accounts
into fiscal reporting categories (income, expense, asset, liability).
These categories drive structured fiscal reports and SAF-T exports,
allowing companies to map their chart of accounts onto standardised
government reporting taxonomies.
Original implementation by Nexa Systems Inc.
"""
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
class FusionFiscalCategory(models.Model):
"""
A fiscal reporting category that groups one or more GL accounts.
Each category carries a ``category_type`` that mirrors the four
fundamental pillars of double-entry bookkeeping. When a SAF-T or
Intrastat export is generated the accounts linked here determine
which transactions are included.
Uniqueness of ``code`` is enforced per company so that external
auditors can refer to categories unambiguously.
"""
_name = "fusion.fiscal.category"
_description = "Fiscal Category"
_order = "code, name"
_rec_name = "display_name"
# ------------------------------------------------------------------
# Fields
# ------------------------------------------------------------------
name = fields.Char(
string="Category Name",
required=True,
translate=True,
help="Human-readable label shown in reports and menus.",
)
code = fields.Char(
string="Code",
required=True,
help=(
"Short alphanumeric identifier used in fiscal exports "
"(e.g. SAF-T GroupingCode). Must be unique per company."
),
)
category_type = fields.Selection(
selection=[
("income", "Income"),
("expense", "Expense"),
("asset", "Asset"),
("liability", "Liability"),
],
string="Type",
required=True,
default="expense",
help="Determines the section of the fiscal report this category appears in.",
)
description = fields.Text(
string="Description",
translate=True,
help="Optional long description for internal documentation purposes.",
)
active = fields.Boolean(
string="Active",
default=True,
help="Archived categories are excluded from new exports but remain on historical records.",
)
company_id = fields.Many2one(
comodel_name="res.company",
string="Company",
required=True,
default=lambda self: self.env.company,
help="Company to which this fiscal category belongs.",
)
account_ids = fields.Many2many(
comodel_name="account.account",
relation="fusion_fiscal_category_account_rel",
column1="category_id",
column2="account_id",
string="Accounts",
help="General-ledger accounts assigned to this fiscal category.",
)
account_count = fields.Integer(
string="# Accounts",
compute="_compute_account_count",
store=False,
help="Number of accounts linked to this category.",
)
parent_id = fields.Many2one(
comodel_name="fusion.fiscal.category",
string="Parent Category",
index=True,
ondelete="restrict",
help="Optional parent for hierarchical fiscal taxonomies.",
)
child_ids = fields.One2many(
comodel_name="fusion.fiscal.category",
inverse_name="parent_id",
string="Sub-categories",
)
# ------------------------------------------------------------------
# SQL constraints
# ------------------------------------------------------------------
_sql_constraints = [
(
"unique_code_per_company",
"UNIQUE(code, company_id)",
"The fiscal category code must be unique within each company.",
),
]
# ------------------------------------------------------------------
# Computed fields
# ------------------------------------------------------------------
@api.depends("account_ids")
def _compute_account_count(self):
"""Count the number of accounts linked to each category."""
for record in self:
record.account_count = len(record.account_ids)
@api.depends("name", "code")
def _compute_display_name(self):
"""Build a display name combining code and name for clarity."""
for record in self:
if record.code:
record.display_name = f"[{record.code}] {record.name}"
else:
record.display_name = record.name or ""
# ------------------------------------------------------------------
# Constraints
# ------------------------------------------------------------------
@api.constrains("parent_id")
def _check_parent_recursion(self):
"""Prevent circular parent-child references."""
if not self._check_recursion():
raise ValidationError(
_("A fiscal category cannot be its own ancestor. "
"Please choose a different parent.")
)
@api.constrains("account_ids", "company_id")
def _check_account_company(self):
"""Ensure all linked accounts belong to the same company."""
for record in self:
foreign = record.account_ids.filtered(
lambda a: a.company_id != record.company_id
)
if foreign:
raise ValidationError(
_("All linked accounts must belong to company '%(company)s'. "
"The following accounts belong to a different company: %(accounts)s",
company=record.company_id.name,
accounts=", ".join(foreign.mapped("code")))
)