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,205 @@
"""
Fusion Accounting - EDI Format Registry
Provides a configuration model for registering electronic document
interchange formats. Each format record carries a unique code and
delegates the actual XML generation / parsing to dedicated generator
classes (e.g. ``FusionUBLGenerator``, ``FusionCIIGenerator``).
Administrators may restrict a format to customer invoices, vendor bills,
or allow it for both through the ``applicable_to`` field.
Original implementation by Nexa Systems Inc.
"""
import logging
from odoo import api, fields, models, _
from odoo.exceptions import UserError
_log = logging.getLogger(__name__)
class FusionEDIFormat(models.Model):
"""
Registry entry for a supported EDI format.
This model acts as a strategy-pattern dispatcher: the ``code`` field
selects the concrete generator/parser to invoke when creating or
reading an electronic document. Format records are typically seeded
via XML data files and should not be deleted while EDI documents
reference them.
"""
_name = "fusion.edi.format"
_description = "Fusion EDI Format"
_order = "sequence, name"
_rec_name = "name"
# ------------------------------------------------------------------
# Fields
# ------------------------------------------------------------------
name = fields.Char(
string="Format Name",
required=True,
help="Human-readable name shown in selection lists.",
)
code = fields.Char(
string="Code",
required=True,
help=(
"Unique technical identifier used to dispatch generation / "
"parsing logic. Examples: 'ubl_21', 'cii', 'facturx'."
),
)
description = fields.Text(
string="Description",
help="Optional notes about the format, its version, or usage.",
)
applicable_to = fields.Selection(
selection=[
("invoices", "Customer Invoices / Credit Notes"),
("bills", "Vendor Bills"),
("both", "Both"),
],
string="Applicable To",
default="both",
required=True,
help="Restricts this format to customer-side, vendor-side, or both.",
)
active = fields.Boolean(
string="Active",
default=True,
help="Inactive formats are hidden from selection lists.",
)
sequence = fields.Integer(
string="Sequence",
default=10,
help="Controls display ordering in lists and dropdowns.",
)
# ------------------------------------------------------------------
# Constraints
# ------------------------------------------------------------------
_sql_constraints = [
(
"code_unique",
"UNIQUE(code)",
"Each EDI format must have a unique code.",
),
]
# ------------------------------------------------------------------
# Generation / Parsing Dispatch
# ------------------------------------------------------------------
def generate_document(self, move):
"""Generate an electronic document for the given journal entry.
Dispatches to the appropriate generator based on ``self.code``.
Args:
move: An ``account.move`` recordset (single record).
Returns:
bytes: The XML payload of the generated document.
Raises:
UserError: When no generator is registered for this format
code or the move type is incompatible.
"""
self.ensure_one()
move.ensure_one()
self._check_applicability(move)
generator_map = self._get_generator_map()
generator_method = generator_map.get(self.code)
if not generator_method:
raise UserError(
_("No generator is registered for EDI format '%s'.", self.code)
)
return generator_method(move)
def parse_document(self, xml_bytes):
"""Parse an incoming EDI XML document and return invoice data.
Dispatches to the appropriate parser based on ``self.code``.
Args:
xml_bytes (bytes): Raw XML content to parse.
Returns:
dict: A dictionary of invoice field values ready for
``account.move.create()``.
Raises:
UserError: When no parser is registered for this format code.
"""
self.ensure_one()
parser_map = self._get_parser_map()
parser_method = parser_map.get(self.code)
if not parser_method:
raise UserError(
_("No parser is registered for EDI format '%s'.", self.code)
)
return parser_method(xml_bytes)
# ------------------------------------------------------------------
# Internal dispatch helpers
# ------------------------------------------------------------------
def _get_generator_map(self):
"""Return a mapping of format codes to generator callables.
Each callable accepts a single ``account.move`` record and
returns ``bytes`` (the XML payload).
"""
ubl = self.env["fusion.ubl.generator"]
cii = self.env["fusion.cii.generator"]
return {
"ubl_21": ubl.generate_ubl_invoice,
"cii": cii.generate_cii_invoice,
"facturx": cii.generate_cii_invoice,
}
def _get_parser_map(self):
"""Return a mapping of format codes to parser callables.
Each callable accepts ``bytes`` (raw XML) and returns a ``dict``
of invoice values.
"""
ubl = self.env["fusion.ubl.generator"]
cii = self.env["fusion.cii.generator"]
return {
"ubl_21": ubl.parse_ubl_invoice,
"cii": cii.parse_cii_invoice,
"facturx": cii.parse_cii_invoice,
}
def _check_applicability(self, move):
"""Verify that this format is applicable to the given move type.
Raises:
UserError: When the format/move combination is invalid.
"""
self.ensure_one()
if self.applicable_to == "invoices" and move.move_type in (
"in_invoice",
"in_refund",
):
raise UserError(
_(
"EDI format '%s' is restricted to customer invoices / "
"credit notes and cannot be used for vendor bills.",
self.name,
)
)
if self.applicable_to == "bills" and move.move_type in (
"out_invoice",
"out_refund",
):
raise UserError(
_(
"EDI format '%s' is restricted to vendor bills and "
"cannot be used for customer invoices.",
self.name,
)
)