From b65354713733e8367e9a3dc2eafd5d8b0f1e79f6 Mon Sep 17 00:00:00 2001 From: Risvana Cybro Date: Tue, 30 Dec 2025 14:25:42 +0530 Subject: [PATCH] :Dec 30 [FIX] Bug Fixed 'dynamic_accounts_report' --- dynamic_accounts_report/__manifest__.py | 2 +- dynamic_accounts_report/doc/RELEASE_NOTES.md | 5 + .../models/account_trial_balance.py | 125 +++++++++++++++++- .../report/financial_reports_views.xml | 2 + .../report/trial_balance.xml | 38 ++++++ .../static/src/js/trial_balance.js | 97 ++++++++++---- .../static/src/xml/trial_balance_view.xml | 117 +++++++++++----- 7 files changed, 324 insertions(+), 62 deletions(-) diff --git a/dynamic_accounts_report/__manifest__.py b/dynamic_accounts_report/__manifest__.py index f292e45a1..31e62ece5 100644 --- a/dynamic_accounts_report/__manifest__.py +++ b/dynamic_accounts_report/__manifest__.py @@ -21,7 +21,7 @@ ################################################################################ { 'name': 'Odoo18 Dynamic Accounting Reports', - 'version': '18.0.1.3.0', + 'version': '18.0.1.3.1', 'category': 'Accounting', 'summary': "Odoo 18 Accounting Financial Reports,Dynamic Accounting Reports, Dynamic Financial Reports,Dynamic Report Odoo18, Odoo18,Financial Reports, Odoo18 Accounting,Accounting, Odoo Apps", 'description': "This module creates dynamic Accounting General Ledger, Trial" diff --git a/dynamic_accounts_report/doc/RELEASE_NOTES.md b/dynamic_accounts_report/doc/RELEASE_NOTES.md index 2c07ae52f..0ff88230a 100644 --- a/dynamic_accounts_report/doc/RELEASE_NOTES.md +++ b/dynamic_accounts_report/doc/RELEASE_NOTES.md @@ -39,3 +39,8 @@ #### Version 18.0.1.3.0 #### UPDT - Commit for adding partner, partner tag, and account filter in the Partner Ledger report. + +#### 22.12.2025 +#### Version 18.0.1.3.1 +#### UPDT +- Added Total to the Trial Balance and report. Fixed the filter issue and the date range RPC error. \ No newline at end of file diff --git a/dynamic_accounts_report/models/account_trial_balance.py b/dynamic_accounts_report/models/account_trial_balance.py index cae5a2c49..766f71659 100644 --- a/dynamic_accounts_report/models/account_trial_balance.py +++ b/dynamic_accounts_report/models/account_trial_balance.py @@ -22,7 +22,8 @@ import calendar import io import json -from datetime import datetime +import logging +from datetime import datetime, timedelta import xlsxwriter from odoo import api, fields, models from odoo.tools.date_utils import get_month, get_fiscal_year, \ @@ -90,7 +91,11 @@ class AccountTrialBalance(models.TransientModel): 'journal_ids': self.env['account.journal'].search_read([], [ 'name']) } - return move_line_list, journal + + # Calculate totals + totals = self._calculate_totals(move_line_list, None) + + return move_line_list, journal, totals @api.model def get_filter_values(self, start_date, end_date, comparison_number, @@ -130,6 +135,12 @@ class AccountTrialBalance(models.TransientModel): account_ids = self.env['account.move.line'].search([]).mapped( 'account_id') move_line_list = [] + # Handle empty dates that can occur with language changes + if not start_date or not end_date: + today = fields.Date.today() + start_date = get_month(today)[0].strftime('%Y-%m-%d') + end_date = get_month(today)[1].strftime('%Y-%m-%d') + start_date_first = \ get_fiscal_year(datetime.strptime(start_date, "%Y-%m-%d").date())[ 0] if comparison_type == 'year' else datetime.strptime( @@ -313,7 +324,92 @@ class AccountTrialBalance(models.TransientModel): f"dynamic_total_credit_{eval(comparison_number) + 1 - i}", 0.0) move_line_list.append(data) - return move_line_list + + # Calculate totals + totals = self._calculate_totals(move_line_list, comparison_number) + + return move_line_list, totals + + def _calculate_totals(self, move_line_list, comparison_number): + """ + Calculate totals for all monetary fields in the trial balance. + :param move_line_list: List of account data dictionaries + :param comparison_number: Number of comparison periods + :return: Dictionary containing all totals + """ + totals = { + 'initial_total_debit': 0.0, + 'initial_total_credit': 0.0, + 'total_debit': 0.0, + 'total_credit': 0.0, + 'end_total_debit': 0.0, + 'end_total_credit': 0.0 + } + + # Add dynamic period totals if comparison is enabled + if comparison_number: + for i in range(1, eval(comparison_number) + 1): + totals[f'dynamic_total_debit_{i}'] = 0.0 + totals[f'dynamic_total_credit_{i}'] = 0.0 + + # Helper function to convert value to float + def to_float(value): + if isinstance(value, str): + # Remove commas and convert to float + try: + return float(value.replace(',', '')) + except ValueError: + return 0.0 + return float(value) if value is not None else 0.0 + + # Sum all values + for account_data in move_line_list: + totals['initial_total_debit'] += to_float(account_data.get('initial_total_debit', 0)) + totals['initial_total_credit'] += to_float(account_data.get('initial_total_credit', 0)) + totals['total_debit'] += to_float(account_data.get('total_debit', 0)) + totals['total_credit'] += to_float(account_data.get('total_credit', 0)) + totals['end_total_debit'] += to_float(account_data.get('end_total_debit', 0)) + totals['end_total_credit'] += to_float(account_data.get('end_total_credit', 0)) + + if comparison_number: + for i in range(1, eval(comparison_number) + 1): + totals[f'dynamic_total_debit_{i}'] += to_float(account_data.get(f'dynamic_total_debit_{i}', 0)) + totals[f'dynamic_total_credit_{i}'] += to_float(account_data.get(f'dynamic_total_credit_{i}', 0)) + + # Format totals as strings with commas and 2 decimal places + for key in totals: + totals[key] = "{:,.2f}".format(totals[key]) + + return totals + + def _get_report_values(self, docids, data=None): + """ + Get the report values for the trial balance PDF report. + This method is called by the Odoo report engine. + """ + if not data: + data = {} + + # Extract data from the data dictionary passed from JavaScript + report_data = data.get('data', []) + totals = data.get('totals', {}) + date_viewed = data.get('date_viewed', []) + filters = data.get('filters', {}) + apply_comparison = data.get('apply_comparison', False) + comparison_number_range = data.get('comparison_number_range', []) + title = data.get('title', 'Trial Balance') + report_name = data.get('report_name', 'Trial Balance') + + return { + 'data': report_data, + 'totals': totals, + 'date_viewed': date_viewed, + 'filters': filters, + 'apply_comparison': apply_comparison, + 'comparison_number_range': comparison_number_range, + 'title': title, + 'report_name': report_name, + } @api.model def get_month_name(self, date): @@ -446,6 +542,29 @@ class AccountTrialBalance(models.TransientModel): sheet.write(row, col + j + 3, move_line['end_total_credit'], txt_name) row += 1 + + # Add totals row + if 'totals' in data and data['totals']: + totals = data['totals'] + # Create bold format for totals + totals_format = workbook.add_format( + {'bold': True, 'bg_color': '#E0E0E0', 'border': 1}) + + sheet.write(row, col, 'Total', totals_format) + sheet.write(row, col + 1, totals.get('initial_total_debit', '0.00'), + totals_format) + sheet.write(row, col + 2, totals.get('initial_total_credit', '0.00'), totals_format) + j = 3 + if data['apply_comparison']: + number_of_periods = data['comparison_number_range'] + for num in number_of_periods: + sheet.write(row, col + j, totals.get(f'dynamic_total_debit_{num}', '0.00'), totals_format) + sheet.write(row, col + j + 1, totals.get(f'dynamic_total_credit_{num}', '0.00'), totals_format) + j += 2 + sheet.write(row, col + j, totals.get('total_debit', '0.00'), totals_format) + sheet.write(row, col + j + 1, totals.get('total_credit', '0.00'), totals_format) + sheet.write(row, col + j + 2, totals.get('end_total_debit', '0.00'), totals_format) + sheet.write(row, col + j + 3, totals.get('end_total_credit', '0.00'), totals_format) workbook.close() output.seek(0) response.stream.write(output.read()) diff --git a/dynamic_accounts_report/report/financial_reports_views.xml b/dynamic_accounts_report/report/financial_reports_views.xml index 40767da75..4133de75a 100644 --- a/dynamic_accounts_report/report/financial_reports_views.xml +++ b/dynamic_accounts_report/report/financial_reports_views.xml @@ -63,6 +63,8 @@ qweb-pdf dynamic_accounts_report.trial_balance dynamic_accounts_report.trial_balance + + report Tax Report diff --git a/dynamic_accounts_report/report/trial_balance.xml b/dynamic_accounts_report/report/trial_balance.xml index b363fd013..45c470aa7 100644 --- a/dynamic_accounts_report/report/trial_balance.xml +++ b/dynamic_accounts_report/report/trial_balance.xml @@ -162,6 +162,44 @@ + + + + Total + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dynamic_accounts_report/static/src/js/trial_balance.js b/dynamic_accounts_report/static/src/js/trial_balance.js index fd32990dd..414ad71b7 100644 --- a/dynamic_accounts_report/static/src/js/trial_balance.js +++ b/dynamic_accounts_report/static/src/js/trial_balance.js @@ -24,7 +24,7 @@ class TrialBalance extends owl.Component { move_line: null, default_report: true, data: null, - total: null, + totals: null, journals: null, accounts: null, selected_analytic: [], @@ -38,6 +38,8 @@ class TrialBalance extends owl.Component { date_viewed: [], comparison_number: null, options: null, + has_filters: false, + filter_version: 0, // Add this to force re-render method: { 'accural': true }, @@ -46,7 +48,8 @@ class TrialBalance extends owl.Component { } async load_data() { /** - * Loads the data for the trial balance report. + * Asynchronously loads initial data for the trial balance report. + * Fetches default trial balance data and populates the component state. */ let move_line_list = [] let move_lines_total = '' @@ -57,12 +60,17 @@ class TrialBalance extends owl.Component { var today = new Date(); var startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); var endOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0); - self.state.data = await self.orm.call("account.trial.balance", "view_report", []); + let result = await self.orm.call("account.trial.balance", "view_report", []); + self.state.data = result[0]; + self.state.totals = result[2]; self.start_date.el.value = startOfMonth.getFullYear() + '-' + String(startOfMonth.getMonth() + 1).padStart(2, '0') + '-' + String(startOfMonth.getDate()).padStart(2, '0'); self.end_date.el.value = endOfMonth.getFullYear() + '-' + String(endOfMonth.getMonth() + 1).padStart(2, '0') + '-' + String(endOfMonth.getDate()).padStart(2, '0'); self.state.date_viewed.push(monthNamesShort[today.getMonth()] + ' ' + today.getFullYear()) - self.state.journals = self.state.data[1]['journal_ids'] - self.state.accounts = self.state.data[0] + self.state.journals = result[1]['journal_ids'] + self.state.accounts = self.state.data + // Reset to default report state when loading initial data + self.state.default_report = true; + self.state.has_filters = false; // Reset filters flag $.each(self.state.data, function (index, value) { self.state.journals = value.journal_ids }) @@ -73,13 +81,8 @@ class TrialBalance extends owl.Component { } async applyFilter(val, ev, is_delete) { /** - * Asynchronously applies filters and loads data for the trial balance report. - * Modifies state variables based on the selected filter options. - * Updates 'move_line_list' and 'move_lines_total'. - * Sets the start and end date inputs based on selected filter options. - * Appends the selected date ranges to 'state.date_viewed'. - * Updates 'state.journals' based on the selected journal filter. - * Retrieves data using the 'account.trial.balance' API with the selected filter values. + * Asynchronously applies filters to the trial balance report. + * Fetches data based on selected filters and updates the component state. * Updates 'state.data' with the retrieved data. * Handles the comparison logic and updates 'state.date_viewed' accordingly. * Reverses the order of 'state.date_viewed' if data exists. @@ -89,10 +92,17 @@ class TrialBalance extends owl.Component { * @param {boolean} is_delete - Flag indicating if the filter is being deleted. * @returns {Promise} Resolves when the filter is applied and data is loaded. */ + + // Set filter flags for ANY filter operation (including date changes) + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; // Force re-render + if (ev && ev.target && ev.target.attributes["data-value"] && ev.target.attributes["data-value"].value == 'no comparison') { const lastIndex = this.state.date_viewed.length - 1; this.state.date_viewed.splice(0, lastIndex); } + if (ev) { if (ev.input && ev.input.attributes.placeholder.value == 'Account' && !is_delete) { this.state.selected_analytic.push(val[0].id) @@ -129,6 +139,10 @@ class TrialBalance extends owl.Component { start_date: this.start_date.el.value, end_date: this.end_date.el.value }; + // Set filter flags for date range selection + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; } else if (val && val.target.attributes["data-value"].value == 'year') { this.start_date.el.value = today.startOf('year').toFormat('yyyy-MM-dd') this.end_date.el.value = today.endOf('year').toFormat('yyyy-MM-dd') @@ -140,17 +154,25 @@ class TrialBalance extends owl.Component { start_date: this.start_date.el.value, end_date: this.end_date.el.value }; + // Set filter flags for date range selection + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; } else if (val && val.target.attributes["data-value"].value == 'quarter') { this.start_date.el.value = today.startOf('quarter').toFormat('yyyy-MM-dd') this.end_date.el.value = today.endOf('quarter').toFormat('yyyy-MM-dd') this.state.date_viewed = [] this.state.date_viewed.push('Q' + ' ' + today.quarter) - this.state.comparison_type = this.state.date_type this.state.date_type = val.target.attributes["data-value"].value + this.state.comparison_type = this.state.date_type this.state.date_range = { start_date: this.start_date.el.value, end_date: this.end_date.el.value }; + // Set filter flags for date range selection + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; } else if (val && val.target.attributes["data-value"].value == 'last-month') { this.start_date.el.value = today.startOf('month').minus({ days: 1 }).startOf('month').toFormat('yyyy-MM-dd') this.end_date.el.value = today.startOf('month').minus({ days: 1 }).toFormat('yyyy-MM-dd') @@ -158,10 +180,15 @@ class TrialBalance extends owl.Component { this.state.date_viewed.push(today.startOf('month').minus({ days: 1 }).monthShort + ' ' + today.startOf('month').minus({ days: 1 }).c.year) this.state.date_type = 'month' this.state.comparison_type = this.state.date_type + console.log("amrutha test") this.state.date_range = { start_date: this.start_date.el.value, end_date: this.end_date.el.value }; + // Set filter flags for date range selection + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; } else if (val && val.target.attributes["data-value"].value == 'last-year') { this.start_date.el.value = today.startOf('year').minus({ days: 1 }).startOf('year').toFormat('yyyy-MM-dd') this.end_date.el.value = today.startOf('year').minus({ days: 1 }).toFormat('yyyy-MM-dd') @@ -173,6 +200,10 @@ class TrialBalance extends owl.Component { start_date: this.start_date.el.value, end_date: this.end_date.el.value }; + // Set filter flags for date range selection + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; } else if (val && val.target.attributes["data-value"].value == 'last-quarter') { this.start_date.el.value = today.startOf('quarter').minus({ days: 1 }).startOf('quarter').toFormat('yyyy-MM-dd') this.end_date.el.value = today.startOf('quarter').minus({ days: 1 }).toFormat('yyyy-MM-dd') @@ -184,6 +215,10 @@ class TrialBalance extends owl.Component { start_date: this.start_date.el.value, end_date: this.end_date.el.value }; + // Set filter flags for date range selection + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; } else if (val && val.target.attributes["data-value"].value == 'journal') { if (!val.target.classList.contains("selected-filter")) { this.state.selected_journal_list.push(parseInt(val.target.attributes["data-id"].value, 10)) @@ -193,6 +228,10 @@ class TrialBalance extends owl.Component { this.state.selected_journal_list = updatedList val.target.classList.remove("selected-filter"); } + // Set filter flags for journal selection + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; } else if (val && val.target.attributes["data-value"].value === 'draft') { if (val.target.classList.contains("selected-filter")) { const { draft, ...updatedAccount } = this.state.options; @@ -205,18 +244,22 @@ class TrialBalance extends owl.Component { }; val.target.classList.add("selected-filter"); } + // Set filter flags for draft selection + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; }else if (val.target.attributes["data-value"].value === 'cash-basis') { - if (val.target.classList.contains("selected-filter")) { - const { cash, ...updatedAccount } = this.state.method; - this.state.method = updatedAccount; - val.target.classList.remove("selected-filter"); + if (this.start_date.el.value) { + var current_year = new Date(this.start_date.el.value).getFullYear(); + var month = new Date(this.start_date.el.value).getMonth(); } else { - this.state.method = { - ...this.state.method, - 'cash': true - }; - val.target.classList.add("selected-filter"); + var current_year = new Date(today).getFullYear(); + var month = new Date(today).getMonth() } + // Set filter flags for cash-basis selection + this.state.has_filters = true; + this.state.default_report = false; + this.state.filter_version += 1; } } if (this.state.apply_comparison == true) { @@ -243,7 +286,8 @@ class TrialBalance extends owl.Component { } } this.state.data = await this.orm.call("account.trial.balance", "get_filter_values", [this.start_date.el.value, this.end_date.el.value, this.state.comparison_number, this.state.comparison_type, this.state.selected_journal_list, this.state.selected_analytic, this.state.options,this.state.method,]); - this.state.default_report = false + this.state.totals = this.state.data[1]; + this.state.data = this.state.data[0]; var date_viewed = [] if (date_viewed.length !== 0) { this.state.date_viewed = date_viewed.reverse() @@ -297,7 +341,7 @@ class TrialBalance extends owl.Component { } sumByKey(data, key) { if (!Array.isArray(data)) return 0; - return data.reduce((acc, item) => { + const total = data.reduce((acc, item) => { let raw = item[key]; if (typeof raw === 'string') { raw = raw.replace(/,/g, ''); // remove commas @@ -305,6 +349,8 @@ class TrialBalance extends owl.Component { const val = parseFloat(raw); return acc + (isNaN(val) ? 0 : val); }, 0); + // Format with commas and 2 decimal places + return total.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); } get comparison_number_range() { /** @@ -373,6 +419,7 @@ class TrialBalance extends owl.Component { var action_title = self.props.action.display_name; let comparison_number_range = self.comparison_number_range let data_viewed = self.state.date_viewed + if (self.state.apply_comparison) { if (self.comparison_number_range.length > 10) { comparison_number_range = self.comparison_number_range.slice(-10); @@ -386,6 +433,7 @@ class TrialBalance extends owl.Component { 'report_file': 'dynamic_accounts_report.trial_balance', 'data': { 'data': this.normalizeReportData(self.state.data), + 'totals': self.state.totals, 'date_viewed': data_viewed, 'filters': this.filter(), 'apply_comparison': self.state.apply_comparison, @@ -470,6 +518,7 @@ class TrialBalance extends owl.Component { var action_title = self.props.action.display_name; var datas = { 'data': this.normalizeReportData(self.state.data), + 'totals': self.state.totals, 'date_viewed': self.state.date_viewed, 'filters': this.filter(), 'apply_comparison': self.state.apply_comparison, diff --git a/dynamic_accounts_report/static/src/xml/trial_balance_view.xml b/dynamic_accounts_report/static/src/xml/trial_balance_view.xml index 78384a4df..1eac0ece5 100644 --- a/dynamic_accounts_report/static/src/xml/trial_balance_view.xml +++ b/dynamic_accounts_report/static/src/xml/trial_balance_view.xml @@ -384,6 +384,48 @@ + + + + Total + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -462,41 +504,48 @@ - - Total - - - - - - - - - - - - - - - + + + + Total + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + +