feat(fusion_accounting_reports): fusion.report definition model
Persistent definition of a Fusion financial report. Each report (P&L, balance sheet, trial balance, GL) has one row in fusion.report holding its metadata + line specs (stored as JSON for layout flexibility). V19 conventions: models.Constraint inline, no _sql_constraints. Per- company uniqueness on (company_id, code). 3 new tests, 27 total passing. Made-with: Cursor
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
from . import services
|
from . import services
|
||||||
|
from . import models
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
'name': 'Fusion Accounting Reports',
|
'name': 'Fusion Accounting Reports',
|
||||||
'version': '19.0.1.0.0',
|
'version': '19.0.1.0.1',
|
||||||
'category': 'Accounting/Accounting',
|
'category': 'Accounting/Accounting',
|
||||||
'summary': 'AI-augmented financial reports (P&L, balance sheet, trial balance, GL).',
|
'summary': 'AI-augmented financial reports (P&L, balance sheet, trial balance, GL).',
|
||||||
'description': """
|
'description': """
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
from . import fusion_report
|
||||||
|
|||||||
63
fusion_accounting_reports/models/fusion_report.py
Normal file
63
fusion_accounting_reports/models/fusion_report.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
"""Persistent definition of a Fusion financial report.
|
||||||
|
|
||||||
|
Each report (P&L, balance sheet, trial balance, GL) has ONE row in
|
||||||
|
fusion.report describing its metadata + line specs. The line specs
|
||||||
|
are stored as a JSON-typed field for flexibility (each line spec
|
||||||
|
includes account_type filter, sub-totaling rules, sign convention)."""
|
||||||
|
|
||||||
|
from odoo import _, api, fields, models
|
||||||
|
|
||||||
|
|
||||||
|
REPORT_TYPES = [
|
||||||
|
('pnl', 'Income Statement (P&L)'),
|
||||||
|
('balance_sheet', 'Balance Sheet'),
|
||||||
|
('trial_balance', 'Trial Balance'),
|
||||||
|
('general_ledger', 'General Ledger'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FusionReport(models.Model):
|
||||||
|
_name = "fusion.report"
|
||||||
|
_description = "Fusion Financial Report Definition"
|
||||||
|
_order = "sequence, id"
|
||||||
|
|
||||||
|
name = fields.Char(required=True, translate=True)
|
||||||
|
code = fields.Char(
|
||||||
|
required=True,
|
||||||
|
help="Unique technical code (e.g. 'pnl', 'balance_sheet').",
|
||||||
|
)
|
||||||
|
report_type = fields.Selection(REPORT_TYPES, required=True)
|
||||||
|
sequence = fields.Integer(default=10)
|
||||||
|
description = fields.Text()
|
||||||
|
active = fields.Boolean(default=True)
|
||||||
|
|
||||||
|
# Layout config - stored as JSON for flexibility per report type.
|
||||||
|
# Example for P&L:
|
||||||
|
# [
|
||||||
|
# {"label": "Revenue", "account_type_prefix": "income_", "sign": 1},
|
||||||
|
# {"label": "Cost of Goods Sold", "account_type_prefix": "expense_direct_", "sign": -1},
|
||||||
|
# {"label": "Gross Profit", "compute": "subtotal", "above": 2},
|
||||||
|
# ...
|
||||||
|
# ]
|
||||||
|
line_specs = fields.Json(string="Line Specs")
|
||||||
|
|
||||||
|
show_zero_balances = fields.Boolean(default=False)
|
||||||
|
show_unposted = fields.Boolean(default=False)
|
||||||
|
default_comparison_mode = fields.Selection(
|
||||||
|
[
|
||||||
|
('none', 'No comparison'),
|
||||||
|
('previous_period', 'Previous Period'),
|
||||||
|
('previous_year', 'Previous Year'),
|
||||||
|
],
|
||||||
|
default='none',
|
||||||
|
)
|
||||||
|
|
||||||
|
company_id = fields.Many2one(
|
||||||
|
'res.company',
|
||||||
|
default=lambda self: self.env.company,
|
||||||
|
)
|
||||||
|
|
||||||
|
_unique_company_code = models.Constraint(
|
||||||
|
'UNIQUE(company_id, code)',
|
||||||
|
'Report code must be unique per company.',
|
||||||
|
)
|
||||||
@@ -1 +1,3 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_fusion_report_user,fusion.report.user,model_fusion_report,base.group_user,1,0,0,0
|
||||||
|
access_fusion_report_admin,fusion.report.admin,model_fusion_report,fusion_accounting_core.group_fusion_accounting_admin,1,1,1,1
|
||||||
|
|||||||
|
@@ -1,2 +1,3 @@
|
|||||||
from . import test_services_unit
|
from . import test_services_unit
|
||||||
from . import test_currency_conversion
|
from . import test_currency_conversion
|
||||||
|
from . import test_fusion_report
|
||||||
|
|||||||
44
fusion_accounting_reports/tests/test_fusion_report.py
Normal file
44
fusion_accounting_reports/tests/test_fusion_report.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"""Tests for fusion.report definition model."""
|
||||||
|
|
||||||
|
from odoo.tests.common import TransactionCase, tagged
|
||||||
|
|
||||||
|
|
||||||
|
@tagged('post_install', '-at_install')
|
||||||
|
class TestFusionReport(TransactionCase):
|
||||||
|
|
||||||
|
def test_create_minimal(self):
|
||||||
|
report = self.env['fusion.report'].create({
|
||||||
|
'name': 'Test P&L',
|
||||||
|
'code': 'test_pnl_minimal',
|
||||||
|
'report_type': 'pnl',
|
||||||
|
})
|
||||||
|
self.assertEqual(report.name, 'Test P&L')
|
||||||
|
self.assertTrue(report.active)
|
||||||
|
self.assertEqual(report.default_comparison_mode, 'none')
|
||||||
|
|
||||||
|
def test_line_specs_json_roundtrip(self):
|
||||||
|
specs = [
|
||||||
|
{'label': 'Revenue', 'account_type_prefix': 'income_', 'sign': 1},
|
||||||
|
{'label': 'COGS', 'account_type_prefix': 'expense_direct_', 'sign': -1},
|
||||||
|
]
|
||||||
|
report = self.env['fusion.report'].create({
|
||||||
|
'name': 'Test',
|
||||||
|
'code': 'test_json_roundtrip',
|
||||||
|
'report_type': 'pnl',
|
||||||
|
'line_specs': specs,
|
||||||
|
})
|
||||||
|
self.assertEqual(report.line_specs, specs)
|
||||||
|
self.assertEqual(report.line_specs[0]['label'], 'Revenue')
|
||||||
|
|
||||||
|
def test_company_code_uniqueness(self):
|
||||||
|
self.env['fusion.report'].create({
|
||||||
|
'name': 'A',
|
||||||
|
'code': 'dup_code_test',
|
||||||
|
'report_type': 'pnl',
|
||||||
|
})
|
||||||
|
with self.assertRaises(Exception):
|
||||||
|
self.env['fusion.report'].create({
|
||||||
|
'name': 'B',
|
||||||
|
'code': 'dup_code_test',
|
||||||
|
'report_type': 'pnl',
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user