Browse Source

:Dec 30 [FIX] Bug Fixed 'dynamic_accounts_report'

18.0
Risvana Cybro 2 days ago
parent
commit
b653547137
  1. 2
      dynamic_accounts_report/__manifest__.py
  2. 5
      dynamic_accounts_report/doc/RELEASE_NOTES.md
  3. 125
      dynamic_accounts_report/models/account_trial_balance.py
  4. 2
      dynamic_accounts_report/report/financial_reports_views.xml
  5. 38
      dynamic_accounts_report/report/trial_balance.xml
  6. 97
      dynamic_accounts_report/static/src/js/trial_balance.js
  7. 117
      dynamic_accounts_report/static/src/xml/trial_balance_view.xml

2
dynamic_accounts_report/__manifest__.py

@ -21,7 +21,7 @@
################################################################################ ################################################################################
{ {
'name': 'Odoo18 Dynamic Accounting Reports', 'name': 'Odoo18 Dynamic Accounting Reports',
'version': '18.0.1.3.0', 'version': '18.0.1.3.1',
'category': 'Accounting', '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", '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" 'description': "This module creates dynamic Accounting General Ledger, Trial"

5
dynamic_accounts_report/doc/RELEASE_NOTES.md

@ -39,3 +39,8 @@
#### Version 18.0.1.3.0 #### Version 18.0.1.3.0
#### UPDT #### UPDT
- Commit for adding partner, partner tag, and account filter in the Partner Ledger report. - 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.

125
dynamic_accounts_report/models/account_trial_balance.py

@ -22,7 +22,8 @@
import calendar import calendar
import io import io
import json import json
from datetime import datetime import logging
from datetime import datetime, timedelta
import xlsxwriter import xlsxwriter
from odoo import api, fields, models from odoo import api, fields, models
from odoo.tools.date_utils import get_month, get_fiscal_year, \ 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([], [ 'journal_ids': self.env['account.journal'].search_read([], [
'name']) 'name'])
} }
return move_line_list, journal
# Calculate totals
totals = self._calculate_totals(move_line_list, None)
return move_line_list, journal, totals
@api.model @api.model
def get_filter_values(self, start_date, end_date, comparison_number, 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_ids = self.env['account.move.line'].search([]).mapped(
'account_id') 'account_id')
move_line_list = [] 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 = \ start_date_first = \
get_fiscal_year(datetime.strptime(start_date, "%Y-%m-%d").date())[ get_fiscal_year(datetime.strptime(start_date, "%Y-%m-%d").date())[
0] if comparison_type == 'year' else datetime.strptime( 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}", f"dynamic_total_credit_{eval(comparison_number) + 1 - i}",
0.0) 0.0)
move_line_list.append(data) 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 @api.model
def get_month_name(self, date): def get_month_name(self, date):
@ -446,6 +542,29 @@ class AccountTrialBalance(models.TransientModel):
sheet.write(row, col + j + 3, sheet.write(row, col + j + 3,
move_line['end_total_credit'], txt_name) move_line['end_total_credit'], txt_name)
row += 1 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() workbook.close()
output.seek(0) output.seek(0)
response.stream.write(output.read()) response.stream.write(output.read())

2
dynamic_accounts_report/report/financial_reports_views.xml

@ -63,6 +63,8 @@
<field name="report_type">qweb-pdf</field> <field name="report_type">qweb-pdf</field>
<field name="report_name">dynamic_accounts_report.trial_balance</field> <field name="report_name">dynamic_accounts_report.trial_balance</field>
<field name="report_file">dynamic_accounts_report.trial_balance</field> <field name="report_file">dynamic_accounts_report.trial_balance</field>
<field name="binding_model_id" ref="model_account_trial_balance"/>
<field name="binding_type">report</field>
</record> </record>
<record id="action_print_tax_report" model="ir.actions.report"> <record id="action_print_tax_report" model="ir.actions.report">
<field name="name">Tax Report</field> <field name="name">Tax Report</field>

38
dynamic_accounts_report/report/trial_balance.xml

@ -162,6 +162,44 @@
</th> </th>
</tr> </tr>
</t> </t>
<!-- Totals Row -->
<t t-if="totals">
<tr class="border-bottom"
style="border-spacing: 0 10px;color:#000;font-weight:bold;">
<th colspan="6">Total</th>
<th style="text-align:center;">
<t t-esc="totals.get('initial_total_debit', '0.00')"/>
</th>
<th style="text-align:center;">
<t t-esc="totals.get('initial_total_credit', '0.00')"/>
</th>
<t t-if="apply_comparison == true">
<t t-set="number_of_periods"
t-value="comparison_number_range"/>
<t t-foreach="number_of_periods"
t-as="nb" t-key="nb">
<th style="text-align:center;">
<t t-esc="totals.get('dynamic_total_debit_' + nb, '0.00')"/>
</th>
<th style="text-align:center;">
<t t-esc="totals.get('dynamic_total_credit_' + nb, '0.00')"/>
</th>
</t>
</t>
<th style="text-align:center;">
<t t-esc="totals.get('total_debit', '0.00')"/>
</th>
<th style="text-align:center;">
<t t-esc="totals.get('total_credit', '0.00')"/>
</th>
<th style="text-align:center;">
<t t-esc="totals.get('end_total_debit', '0.00')"/>
</th>
<th style="text-align:center;">
<t t-esc="totals.get('end_total_credit', '0.00')"/>
</th>
</tr>
</t>
</t> </t>
</tbody> </tbody>
</table> </table>

97
dynamic_accounts_report/static/src/js/trial_balance.js

@ -24,7 +24,7 @@ class TrialBalance extends owl.Component {
move_line: null, move_line: null,
default_report: true, default_report: true,
data: null, data: null,
total: null, totals: null,
journals: null, journals: null,
accounts: null, accounts: null,
selected_analytic: [], selected_analytic: [],
@ -38,6 +38,8 @@ class TrialBalance extends owl.Component {
date_viewed: [], date_viewed: [],
comparison_number: null, comparison_number: null,
options: null, options: null,
has_filters: false,
filter_version: 0, // Add this to force re-render
method: { method: {
'accural': true 'accural': true
}, },
@ -46,7 +48,8 @@ class TrialBalance extends owl.Component {
} }
async load_data() { 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_line_list = []
let move_lines_total = '' let move_lines_total = ''
@ -57,12 +60,17 @@ class TrialBalance extends owl.Component {
var today = new Date(); var today = new Date();
var startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); var startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
var endOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0); 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.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.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.date_viewed.push(monthNamesShort[today.getMonth()] + ' ' + today.getFullYear())
self.state.journals = self.state.data[1]['journal_ids'] self.state.journals = result[1]['journal_ids']
self.state.accounts = self.state.data[0] 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) { $.each(self.state.data, function (index, value) {
self.state.journals = value.journal_ids self.state.journals = value.journal_ids
}) })
@ -73,13 +81,8 @@ class TrialBalance extends owl.Component {
} }
async applyFilter(val, ev, is_delete) { async applyFilter(val, ev, is_delete) {
/** /**
* Asynchronously applies filters and loads data for the trial balance report. * Asynchronously applies filters to the trial balance report.
* Modifies state variables based on the selected filter options. * Fetches data based on selected filters and updates the component state.
* 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.
* Updates 'state.data' with the retrieved data. * Updates 'state.data' with the retrieved data.
* Handles the comparison logic and updates 'state.date_viewed' accordingly. * Handles the comparison logic and updates 'state.date_viewed' accordingly.
* Reverses the order of 'state.date_viewed' if data exists. * 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. * @param {boolean} is_delete - Flag indicating if the filter is being deleted.
* @returns {Promise<void>} Resolves when the filter is applied and data is loaded. * @returns {Promise<void>} 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') { 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; const lastIndex = this.state.date_viewed.length - 1;
this.state.date_viewed.splice(0, lastIndex); this.state.date_viewed.splice(0, lastIndex);
} }
if (ev) { if (ev) {
if (ev.input && ev.input.attributes.placeholder.value == 'Account' && !is_delete) { if (ev.input && ev.input.attributes.placeholder.value == 'Account' && !is_delete) {
this.state.selected_analytic.push(val[0].id) this.state.selected_analytic.push(val[0].id)
@ -129,6 +139,10 @@ class TrialBalance extends owl.Component {
start_date: this.start_date.el.value, start_date: this.start_date.el.value,
end_date: this.end_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') { } else if (val && val.target.attributes["data-value"].value == 'year') {
this.start_date.el.value = today.startOf('year').toFormat('yyyy-MM-dd') this.start_date.el.value = today.startOf('year').toFormat('yyyy-MM-dd')
this.end_date.el.value = today.endOf('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, start_date: this.start_date.el.value,
end_date: this.end_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') { } else if (val && val.target.attributes["data-value"].value == 'quarter') {
this.start_date.el.value = today.startOf('quarter').toFormat('yyyy-MM-dd') 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.end_date.el.value = today.endOf('quarter').toFormat('yyyy-MM-dd')
this.state.date_viewed = [] this.state.date_viewed = []
this.state.date_viewed.push('Q' + ' ' + today.quarter) 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.date_type = val.target.attributes["data-value"].value
this.state.comparison_type = this.state.date_type
this.state.date_range = { this.state.date_range = {
start_date: this.start_date.el.value, start_date: this.start_date.el.value,
end_date: this.end_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') { } 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.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') 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_viewed.push(today.startOf('month').minus({ days: 1 }).monthShort + ' ' + today.startOf('month').minus({ days: 1 }).c.year)
this.state.date_type = 'month' this.state.date_type = 'month'
this.state.comparison_type = this.state.date_type this.state.comparison_type = this.state.date_type
console.log("amrutha test")
this.state.date_range = { this.state.date_range = {
start_date: this.start_date.el.value, start_date: this.start_date.el.value,
end_date: this.end_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') { } 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.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') 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, start_date: this.start_date.el.value,
end_date: this.end_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') { } 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.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') 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, start_date: this.start_date.el.value,
end_date: this.end_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') { } else if (val && val.target.attributes["data-value"].value == 'journal') {
if (!val.target.classList.contains("selected-filter")) { if (!val.target.classList.contains("selected-filter")) {
this.state.selected_journal_list.push(parseInt(val.target.attributes["data-id"].value, 10)) 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 this.state.selected_journal_list = updatedList
val.target.classList.remove("selected-filter"); 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') { } else if (val && val.target.attributes["data-value"].value === 'draft') {
if (val.target.classList.contains("selected-filter")) { if (val.target.classList.contains("selected-filter")) {
const { draft, ...updatedAccount } = this.state.options; const { draft, ...updatedAccount } = this.state.options;
@ -205,18 +244,22 @@ class TrialBalance extends owl.Component {
}; };
val.target.classList.add("selected-filter"); 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') { }else if (val.target.attributes["data-value"].value === 'cash-basis') {
if (val.target.classList.contains("selected-filter")) { if (this.start_date.el.value) {
const { cash, ...updatedAccount } = this.state.method; var current_year = new Date(this.start_date.el.value).getFullYear();
this.state.method = updatedAccount; var month = new Date(this.start_date.el.value).getMonth();
val.target.classList.remove("selected-filter");
} else { } else {
this.state.method = { var current_year = new Date(today).getFullYear();
...this.state.method, var month = new Date(today).getMonth()
'cash': true
};
val.target.classList.add("selected-filter");
} }
// 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) { 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.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 = [] var date_viewed = []
if (date_viewed.length !== 0) { if (date_viewed.length !== 0) {
this.state.date_viewed = date_viewed.reverse() this.state.date_viewed = date_viewed.reverse()
@ -297,7 +341,7 @@ class TrialBalance extends owl.Component {
} }
sumByKey(data, key) { sumByKey(data, key) {
if (!Array.isArray(data)) return 0; if (!Array.isArray(data)) return 0;
return data.reduce((acc, item) => { const total = data.reduce((acc, item) => {
let raw = item[key]; let raw = item[key];
if (typeof raw === 'string') { if (typeof raw === 'string') {
raw = raw.replace(/,/g, ''); // remove commas raw = raw.replace(/,/g, ''); // remove commas
@ -305,6 +349,8 @@ class TrialBalance extends owl.Component {
const val = parseFloat(raw); const val = parseFloat(raw);
return acc + (isNaN(val) ? 0 : val); return acc + (isNaN(val) ? 0 : val);
}, 0); }, 0);
// Format with commas and 2 decimal places
return total.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
} }
get comparison_number_range() { get comparison_number_range() {
/** /**
@ -373,6 +419,7 @@ class TrialBalance extends owl.Component {
var action_title = self.props.action.display_name; var action_title = self.props.action.display_name;
let comparison_number_range = self.comparison_number_range let comparison_number_range = self.comparison_number_range
let data_viewed = self.state.date_viewed let data_viewed = self.state.date_viewed
if (self.state.apply_comparison) { if (self.state.apply_comparison) {
if (self.comparison_number_range.length > 10) { if (self.comparison_number_range.length > 10) {
comparison_number_range = self.comparison_number_range.slice(-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', 'report_file': 'dynamic_accounts_report.trial_balance',
'data': { 'data': {
'data': this.normalizeReportData(self.state.data), 'data': this.normalizeReportData(self.state.data),
'totals': self.state.totals,
'date_viewed': data_viewed, 'date_viewed': data_viewed,
'filters': this.filter(), 'filters': this.filter(),
'apply_comparison': self.state.apply_comparison, 'apply_comparison': self.state.apply_comparison,
@ -470,6 +518,7 @@ class TrialBalance extends owl.Component {
var action_title = self.props.action.display_name; var action_title = self.props.action.display_name;
var datas = { var datas = {
'data': this.normalizeReportData(self.state.data), 'data': this.normalizeReportData(self.state.data),
'totals': self.state.totals,
'date_viewed': self.state.date_viewed, 'date_viewed': self.state.date_viewed,
'filters': this.filter(), 'filters': this.filter(),
'apply_comparison': self.state.apply_comparison, 'apply_comparison': self.state.apply_comparison,

117
dynamic_accounts_report/static/src/xml/trial_balance_view.xml

@ -384,6 +384,48 @@
</th> </th>
</tr> </tr>
</t> </t>
<!-- Totals Row - Show for filtered data when data exists -->
<t t-if="state.data and state.data.length > 0">
<tr class="border-bottom"
style="border-spacing: 0 10px;color:#000;font-weight:bold;background-color:#f8f9fa;">
<th colspan="6">Total</th>
<!-- Initial Balance Totals -->
<th style="text-align:center;">
<t t-esc="sumByKey(state.data, 'initial_total_debit')"/>
</th>
<th style="text-align:center;">
<t t-esc="sumByKey(state.data, 'initial_total_credit')"/>
</th>
<!-- Dynamic Period Totals (when comparison is applied) -->
<t t-if="state.apply_comparison == true">
<t t-set="number_of_periods"
t-value="comparison_number_range"/>
<t t-foreach="number_of_periods"
t-as="num" t-key="num">
<th style="text-align:center;">
<t t-esc="sumByKey(state.data, 'dynamic_total_debit_' + num)"/>
</th>
<th style="text-align:center;">
<t t-esc="sumByKey(state.data, 'dynamic_total_credit_' + num)"/>
</th>
</t>
</t>
<!-- Current Period Totals -->
<th style="text-align:center;">
<t t-esc="sumByKey(state.data, 'total_debit')"/>
</th>
<th style="text-align:center;">
<t t-esc="sumByKey(state.data, 'total_credit')"/>
</th>
<!-- End Balance Totals -->
<th style="text-align:center;">
<t t-esc="sumByKey(state.data, 'end_total_debit')"/>
</th>
<th style="text-align:center;">
<t t-esc="sumByKey(state.data, 'end_total_credit')"/>
</th>
</tr>
</t>
</t> </t>
</t> </t>
<t t-if="this.state.default_report == true"> <t t-if="this.state.default_report == true">
@ -462,41 +504,48 @@
</th> </th>
</tr> </tr>
</t> </t>
<tr class="border-bottom" <!-- Totals Row - Show for all cases when data exists -->
style="border-spacing: 0 10px;color:#000"> <t t-if="state.data and state.data.length > 0">
<th colspan="6">Total</th> <tr class="border-bottom"
<th style="text-align:center;"> style="border-spacing: 0 10px;color:#000;font-weight:bold;background-color:#f8f9fa;">
<t t-esc="sumByKey(state.accounts, 'initial_total_debit')"/> <th colspan="6">Total</th>
</th> <!-- Initial Balance Totals -->
<th style="text-align:center;"> <th style="text-align:center;">
<t t-esc="sumByKey(state.accounts, 'initial_total_credit')"/> <t t-esc="sumByKey(state.data, 'initial_total_debit')"/>
</th> </th>
<t t-if="state.apply_comparison == true"> <th style="text-align:center;">
<t t-set="number_of_periods" <t t-esc="sumByKey(state.data, 'initial_total_credit')"/>
t-value="comparison_number_range"/> </th>
<t t-foreach="number_of_periods" <!-- Dynamic Period Totals (when comparison is applied) -->
t-as="nb" t-key="nb"> <t t-if="state.apply_comparison == true">
<th style="text-align:center;"> <t t-set="number_of_periods"
<t t-esc="sumByKey(state.accounts, 'dynamic_total_debit_' + nb)"/> t-value="comparison_number_range"/>
</th> <t t-foreach="number_of_periods"
<th style="text-align:center;"> t-as="num" t-key="num">
<t t-esc="sumByKey(state.accounts, 'dynamic_total_credit_' + nb)"/> <th style="text-align:center;">
</th> <t t-esc="sumByKey(state.data, 'dynamic_total_debit_' + num)"/>
</th>
<th style="text-align:center;">
<t t-esc="sumByKey(state.data, 'dynamic_total_credit_' + num)"/>
</th>
</t>
</t> </t>
</t> <!-- Current Period Totals -->
<th style="text-align:center;"> <th style="text-align:center;">
<t t-esc="sumByKey(state.accounts, 'total_debit')"/> <t t-esc="sumByKey(state.data, 'total_debit')"/>
</th> </th>
<th style="text-align:center;"> <th style="text-align:center;">
<t t-esc="sumByKey(state.accounts, 'total_credit')"/> <t t-esc="sumByKey(state.data, 'total_credit')"/>
</th> </th>
<th style="text-align:center;"> <!-- End Balance Totals -->
<t t-esc="sumByKey(state.accounts, 'end_total_debit')"/> <th style="text-align:center;">
</th> <t t-esc="sumByKey(state.data, 'end_total_debit')"/>
<th style="text-align:center;"> </th>
<t t-esc="sumByKey(state.accounts, 'end_total_credit')"/> <th style="text-align:center;">
</th> <t t-esc="sumByKey(state.data, 'end_total_credit')"/>
</tr> </th>
</tr>
</t>
</t> </t>
</t> </t>
</tbody> </tbody>

Loading…
Cancel
Save