diff --git a/fusion_accounting_reports/__manifest__.py b/fusion_accounting_reports/__manifest__.py index f5bfaed1..013e8100 100644 --- a/fusion_accounting_reports/__manifest__.py +++ b/fusion_accounting_reports/__manifest__.py @@ -1,6 +1,6 @@ { 'name': 'Fusion Accounting Reports', - 'version': '19.0.1.0.31', + 'version': '19.0.1.0.32', 'category': 'Accounting/Accounting', 'summary': 'AI-augmented financial reports (P&L, balance sheet, trial balance, GL).', 'description': """ @@ -38,6 +38,7 @@ menu hides; the engine and AI tools remain available for the chat. 'data/cron.xml', 'reports/report_pdf_template.xml', 'wizards/xlsx_export_wizard_views.xml', + 'wizards/period_picker_wizard_views.xml', ], 'external_dependencies': { 'python': ['xlsxwriter'], diff --git a/fusion_accounting_reports/security/ir.model.access.csv b/fusion_accounting_reports/security/ir.model.access.csv index 750413ec..887902b4 100644 --- a/fusion_accounting_reports/security/ir.model.access.csv +++ b/fusion_accounting_reports/security/ir.model.access.csv @@ -4,3 +4,4 @@ access_fusion_report_admin,fusion.report.admin,model_fusion_report,fusion_accoun access_fusion_report_commentary,fusion.report.commentary,model_fusion_report_commentary,base.group_user,1,1,1,0 access_fusion_report_anomaly,fusion.report.anomaly,model_fusion_report_anomaly,base.group_user,1,1,1,0 access_fusion_xlsx_export_wizard_user,fusion.xlsx.export.wizard.user,model_fusion_xlsx_export_wizard,base.group_user,1,1,1,0 +access_fusion_period_picker_wizard_user,fusion.period.picker.wizard.user,model_fusion_period_picker_wizard,base.group_user,1,1,1,0 diff --git a/fusion_accounting_reports/tests/__init__.py b/fusion_accounting_reports/tests/__init__.py index cffbaa01..ec92123c 100644 --- a/fusion_accounting_reports/tests/__init__.py +++ b/fusion_accounting_reports/tests/__init__.py @@ -20,3 +20,4 @@ from . import test_account_balance_mv from . import test_cron from . import test_pdf_export from . import test_xlsx_export +from . import test_period_picker diff --git a/fusion_accounting_reports/tests/test_period_picker.py b/fusion_accounting_reports/tests/test_period_picker.py new file mode 100644 index 00000000..05e35ae3 --- /dev/null +++ b/fusion_accounting_reports/tests/test_period_picker.py @@ -0,0 +1,36 @@ +"""Tests for period picker wizard.""" + +from odoo.tests.common import TransactionCase, tagged + + +@tagged('post_install', '-at_install') +class TestPeriodPickerWizard(TransactionCase): + + def test_this_month_preset_fills_dates(self): + wizard = self.env['fusion.period.picker.wizard'].create({ + 'report_type': 'pnl', + 'period_preset': 'this_month', + }) + wizard._onchange_period_preset() + self.assertTrue(wizard.date_from) + self.assertTrue(wizard.date_to) + self.assertEqual(wizard.date_from.day, 1) + + def test_this_year_preset_uses_ytd(self): + wizard = self.env['fusion.period.picker.wizard'].create({ + 'report_type': 'pnl', + 'period_preset': 'this_year', + }) + wizard._onchange_period_preset() + self.assertEqual(wizard.date_from.month, 1) + self.assertEqual(wizard.date_from.day, 1) + + def test_action_open_report_returns_client_action(self): + wizard = self.env['fusion.period.picker.wizard'].create({ + 'report_type': 'pnl', + 'period_preset': 'this_year', + }) + wizard._onchange_period_preset() + action = wizard.action_open_report() + self.assertEqual(action['type'], 'ir.actions.client') + self.assertEqual(action['tag'], 'fusion_reports') diff --git a/fusion_accounting_reports/wizards/__init__.py b/fusion_accounting_reports/wizards/__init__.py index 99bf00b3..53eebe52 100644 --- a/fusion_accounting_reports/wizards/__init__.py +++ b/fusion_accounting_reports/wizards/__init__.py @@ -1 +1,2 @@ from . import xlsx_export_wizard +from . import period_picker_wizard diff --git a/fusion_accounting_reports/wizards/period_picker_wizard.py b/fusion_accounting_reports/wizards/period_picker_wizard.py new file mode 100644 index 00000000..ff00f311 --- /dev/null +++ b/fusion_accounting_reports/wizards/period_picker_wizard.py @@ -0,0 +1,77 @@ +"""Period selection + comparison wizard. + +Pre-fills date ranges for common report periods (current month, YTD, etc.).""" + +from datetime import timedelta + +from odoo import api, fields, models + +from ..services.date_periods import ( + fiscal_year_bounds, month_bounds, quarter_bounds, +) + + +class FusionPeriodPickerWizard(models.TransientModel): + _name = "fusion.period.picker.wizard" + _description = "Period Selection Wizard" + + report_type = fields.Selection([ + ('pnl', 'P&L'), + ('balance_sheet', 'Balance Sheet'), + ('trial_balance', 'Trial Balance'), + ('general_ledger', 'General Ledger'), + ], required=True, default='pnl') + period_preset = fields.Selection([ + ('this_month', 'This Month'), + ('last_month', 'Last Month'), + ('this_quarter', 'This Quarter'), + ('last_quarter', 'Last Quarter'), + ('this_year', 'This Year (YTD)'), + ('last_year', 'Last Year'), + ('custom', 'Custom Range'), + ], default='this_month', required=True) + date_from = fields.Date() + date_to = fields.Date() + comparison = fields.Selection([ + ('none', 'No Comparison'), + ('previous_period', 'Previous Period'), + ('previous_year', 'Previous Year'), + ], default='none') + + @api.onchange('period_preset') + def _onchange_period_preset(self): + today = fields.Date.today() + if self.period_preset == 'this_month': + p = month_bounds(today) + self.date_from, self.date_to = p.date_from, p.date_to + elif self.period_preset == 'last_month': + p = month_bounds(today.replace(day=1) - timedelta(days=1)) + self.date_from, self.date_to = p.date_from, p.date_to + elif self.period_preset == 'this_quarter': + p = quarter_bounds(today) + self.date_from, self.date_to = p.date_from, p.date_to + elif self.period_preset == 'last_quarter': + this_q = quarter_bounds(today) + p = quarter_bounds(this_q.date_from - timedelta(days=1)) + self.date_from, self.date_to = p.date_from, p.date_to + elif self.period_preset == 'this_year': + p = fiscal_year_bounds(today) + self.date_from, self.date_to = p.date_from, today + elif self.period_preset == 'last_year': + last_year = today.replace(year=today.year - 1) + p = fiscal_year_bounds(last_year) + self.date_from, self.date_to = p.date_from, p.date_to + + def action_open_report(self): + """Open the fusion reports viewer pre-filled with selected period.""" + self.ensure_one() + return { + 'type': 'ir.actions.client', + 'tag': 'fusion_reports', + 'context': { + 'default_report_type': self.report_type, + 'default_date_from': str(self.date_from), + 'default_date_to': str(self.date_to), + 'default_comparison': self.comparison, + }, + } diff --git a/fusion_accounting_reports/wizards/period_picker_wizard_views.xml b/fusion_accounting_reports/wizards/period_picker_wizard_views.xml new file mode 100644 index 00000000..11ac9994 --- /dev/null +++ b/fusion_accounting_reports/wizards/period_picker_wizard_views.xml @@ -0,0 +1,32 @@ + + + + fusion.period.picker.wizard.form + fusion.period.picker.wizard + +
+ + + + + + + +
+
+
+
+
+ + + Open Financial Report + fusion.period.picker.wizard + form + new + +