From 137789cd79d5b220b7295e43ad28bf33eddc55ee Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Tue, 28 May 2024 11:35:24 -0400 Subject: [PATCH 1/9] Add videoconference sync and fix some bugs: - Properly synchronize the timezone for users with timezones set in Odoo - Properly synchronize attendees, i.e. remove the organizer from the attendees list on the CalDAV server and re-add them on the event attendees in Odoo (to show up in the calendar view). --- caldav_sync/__manifest__.py | 5 ++- caldav_sync/models/calendar_event.py | 48 ++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/caldav_sync/__manifest__.py b/caldav_sync/__manifest__.py index 0ad599a..fbed16b 100644 --- a/caldav_sync/__manifest__.py +++ b/caldav_sync/__manifest__.py @@ -8,7 +8,7 @@ { 'name': 'CalDAV Synchronization', - 'version': '17.0.0.5.2', + 'version': '17.0.0.5.3', 'license': 'LGPL-3', 'category': 'Productivity', 'summary': 'Synchronize Odoo Calendar Events with CalDAV Servers', @@ -20,6 +20,9 @@ 'author': 'Bemade Inc.', 'website': 'https://www.bemade.org', 'depends': ['base', 'calendar'], + 'external_dependencies': { + 'python': ['caldav', 'icalendar', 'bs4'], + }, 'images': ['static/description/images/main_screenshot.png'], 'data': [ 'views/res_users_views.xml', diff --git a/caldav_sync/models/calendar_event.py b/caldav_sync/models/calendar_event.py index 44de0f9..f228952 100644 --- a/caldav_sync/models/calendar_event.py +++ b/caldav_sync/models/calendar_event.py @@ -2,12 +2,13 @@ import uuid from odoo import models, api, fields import caldav import logging -from datetime import datetime -from icalendar import Calendar, Event, vCalAddress, Alarm, vText, vWeekday +from datetime import datetime, timezone +from icalendar import Calendar, Event, vCalAddress, vText, vWeekday from bs4 import BeautifulSoup from datetime import timedelta import dateutil import re +from pytz import timezone, utc _logger = logging.getLogger(__name__) @@ -143,16 +144,32 @@ class CalendarEvent(models.Model): calendar.add('version', '2.0') for event in self: + user_tz = timezone('UTC') + if event.user_id.tz: + user_tz = timezone(event.user_id.tz) ical_event = Event() ical_event.add('uid', event.caldav_uid) - ical_event.add('dtstamp', event.write_date.replace(tzinfo=None)) + ical_event.add('dtstamp', utc.localize(event.write_date).astimezone(user_tz)) if event.name: ical_event.add('summary', event.name) - if event.description: - ical_event.add('description', event.description) + if event.description and self._html_to_text(event.description): + ical_event.add('description', self._html_to_text(event.description)) if event.location: ical_event.add('location', event.location) - + if event.videocall_location: + ical_event.add('CONFERENCE', event.videocall_location) + for partner in event.partner_ids: + if partner == event.user_id.partner_id: + continue + attendee = vCalAddress(f'MAILTO:{partner.email}') + attendee.params['cn'] = vText(partner.name) + attendee_record = self.env['calendar.attendee'].search([('event_id', '=', event.id), ('partner_id', '=', partner.id)], limit=1) + if attendee_record: + attendee.params['partstat'] = vText(self._map_attendee_status(attendee_record.state)) + ical_event.add('attendee', attendee, encode=0) + organizer = vCalAddress(f"MAILTO:{event.user_id.email}") + organizer.params['cn'] = event.user_id.name + ical_event.add('organizer', organizer) # Add RRULE if the event is recurrent if event.recurrency and event.recurrence_id: rrule = event.recurrence_id._get_rrule() @@ -160,8 +177,8 @@ class CalendarEvent(models.Model): ical_event.add('rrule', rrule_dict) # Add DTSTART and DTEND - ical_event.add('dtstart', event.start.replace(tzinfo=None)) - ical_event.add('dtend', event.stop.replace(tzinfo=None)) + ical_event.add('dtstart', utc.localize(event.start).astimezone(user_tz)) + ical_event.add('dtend', utc.localize(event.stop).astimezone(user_tz)) calendar.add_component(ical_event) @@ -269,7 +286,6 @@ class CalendarEvent(models.Model): def sync_event_from_ical(self, ical_event): email_regex = re.compile(r'[a-z0-9\.\-+_]+@[a-z0-9\.\-+_]+\.[a-z]+') - now = datetime.now() current_user_email = self.env.user.email.lower() for component in ical_event.subcomponents: @@ -300,16 +316,18 @@ class CalendarEvent(models.Model): existing_instance = self._get_existing_instance(uid, recurrence_id) start = component.decoded('dtstart') if isinstance(start, datetime): - start = start.replace(tzinfo=None) + start = start.astimezone(utc).replace(tzinfo=None) end = component.decoded('dtend') if isinstance(end, datetime): - end = end.replace(tzinfo=None) + end = end.astimezone(utc).replace(tzinfo=None) + values = { 'name': str(component.get('summary')), 'start': start, 'stop': end, - 'description': str(component.get('description')), - 'location': str(component.get('location')), + 'description': self._extract_component_text(component, 'description'), + 'location': self._extract_component_text(component, 'location'), + 'videocall_location': self._extract_component_text(component, 'conference'), 'caldav_uid': uid, 'partner_ids': [(6, 0, attendee_ids.ids)], } @@ -328,6 +346,10 @@ class CalendarEvent(models.Model): }) existing_instance.with_context({'caldav_no_sync': True}).write(values) + @staticmethod + def _extract_component_text(component, subcomponent_name): + text = str(component.get(subcomponent_name)) + text = text if text != 'None' else '' @staticmethod def _html_to_text(html): From a050ce6221a48a33cf6904b2d6101fd86dcb3dcf Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Tue, 28 May 2024 14:29:09 -0400 Subject: [PATCH 2/9] add a new module for aged partner balance reports, NA style --- aged_partner_balance_na/__init__.py | 10 + aged_partner_balance_na/__manifest__.py | 32 +++ aged_partner_balance_na/models/__init__.py | 1 + .../models/aged_partner_balance.py | 242 ++++++++++++++++++ .../wizard/choose_delivery_package_views.xml | 8 +- multi_account_statement_import/__init__.py | 0 .../__manifest__.py | 32 +++ 7 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 aged_partner_balance_na/__init__.py create mode 100644 aged_partner_balance_na/__manifest__.py create mode 100644 aged_partner_balance_na/models/__init__.py create mode 100644 aged_partner_balance_na/models/aged_partner_balance.py create mode 100644 multi_account_statement_import/__init__.py create mode 100644 multi_account_statement_import/__manifest__.py diff --git a/aged_partner_balance_na/__init__.py b/aged_partner_balance_na/__init__.py new file mode 100644 index 0000000..e63df36 --- /dev/null +++ b/aged_partner_balance_na/__init__.py @@ -0,0 +1,10 @@ +from . import models + + +def post_init(env): + new_receivable_report = env.ref('account_reports.aged_receivable_report').copy() + new_payable_report = env.ref('account_reports.aged_payable_report').copy() + new_receivable_report.line_ids.mapped('expression_ids').write({ + 'formula': '_report_custom_engine_aged_receivable_na' + }) + new_payable_report.line_ids.mapped('expression_ids').write({'formula': '_report_custom_engine_aged_payable_na'}) diff --git a/aged_partner_balance_na/__manifest__.py b/aged_partner_balance_na/__manifest__.py new file mode 100644 index 0000000..02c7e15 --- /dev/null +++ b/aged_partner_balance_na/__manifest__.py @@ -0,0 +1,32 @@ +# +# Bemade Inc. +# +# Copyright (C) 2023-June Bemade Inc. (). +# Author: Marc Durepos (Contact : marc@bemade.org) +# +# This program is under the terms of the Odoo Proprietary License v1.0 (OPL-1) +# It is forbidden to publish, distribute, sublicense, or sell copies of the Software +# or modified copies of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +{ + 'name': 'Aged Partner Balance (North American Style)', + 'version': '17.0.1.0.0', + 'summary': 'Present aged partner balance as predictive rather than past due.', + 'category': 'Accounting', + 'author': 'Bemade Inc.', + 'website': 'http://www.bemade.org', + 'license': 'LGPL-3', + 'depends': ['account_reports'], + 'assets': {}, + 'installable': True, + 'auto_install': False, + 'post_init_hook': 'post_init', +} diff --git a/aged_partner_balance_na/models/__init__.py b/aged_partner_balance_na/models/__init__.py new file mode 100644 index 0000000..06ce624 --- /dev/null +++ b/aged_partner_balance_na/models/__init__.py @@ -0,0 +1 @@ +from . import aged_partner_balance \ No newline at end of file diff --git a/aged_partner_balance_na/models/aged_partner_balance.py b/aged_partner_balance_na/models/aged_partner_balance.py new file mode 100644 index 0000000..5ad1911 --- /dev/null +++ b/aged_partner_balance_na/models/aged_partner_balance.py @@ -0,0 +1,242 @@ +from odoo import models, fields +from itertools import chain +from dateutil.relativedelta import relativedelta + + +class AgedPartnerBalanceCustomHandler(models.AbstractModel): + _inherit = "account.aged.partner.balance.report.handler" + + def _report_custom_engine_aged_receivable_na( + self, + expressions, + options, + date_scope, + current_groupby, + next_groupby, + offset=0, + limit=None, + warnings=None + ): + return self._aged_partner_report_custom_engine_common_na( + options, + 'asset_receivable', + current_groupby, + next_groupby, + offset=offset, + limit=limit + ) + + def _report_custom_engine_aged_payable_na( + self, + expressions, + options, + date_scope, + current_groupby, + next_groupby, + offset=0, + limit=None, + warnings=None + ): + return self._aged_partner_report_custom_engine_common_na( + options, + 'liability_payable', + current_groupby, + next_groupby, + offset=offset, + limit=limit + ) + + def _aged_partner_report_custom_engine_common_na(self, options, internal_type, current_groupby, next_groupby, offset=0, limit=None): + report = self.env['account.report'].browse(options['report_id']) + report._check_groupby_fields((next_groupby.split(',') if next_groupby else []) + ([current_groupby] if current_groupby else [])) + + def plus_days(date_obj, days): + return fields.Date.to_string(date_obj - relativedelta(days=days)) + + date_to = fields.Date.from_string(options['date']['date_to']) + periods = [ + (False, fields.Date.to_string(date_to)), + (date_to, plus_days(date_to, 29)), + (plus_days(date_to, 30), plus_days(date_to, 59)), + (plus_days(date_to, 60), plus_days(date_to, 89)), + (plus_days(date_to, 90), plus_days(date_to, 119)), + (plus_days(date_to, 120), False), + ] + + def build_result_dict(report, query_res_lines): + rslt = {f'period{i}': 0 for i in range(len(periods))} + + for query_res in query_res_lines: + for i in range(len(periods)): + period_key = f'period{i}' + rslt[period_key] += query_res[period_key] + + if current_groupby == 'id': + query_res = query_res_lines[0] # We're grouping by id, so there is only 1 element in query_res_lines anyway + currency = self.env['res.currency'].browse(query_res['currency_id'][0]) if len(query_res['currency_id']) == 1 else None + expected_date = len(query_res['expected_date']) == 1 and query_res['expected_date'][0] or len(query_res['due_date']) == 1 and query_res['due_date'][0] + rslt.update({ + 'invoice_date': query_res['invoice_date'][0] if len(query_res['invoice_date']) == 1 else None, + 'due_date': query_res['due_date'][0] if len(query_res['due_date']) == 1 else None, + 'amount_currency': query_res['amount_currency'], + 'currency_id': query_res['currency_id'][0] if len(query_res['currency_id']) == 1 else None, + 'currency': currency.display_name if currency else None, + 'account_name': query_res['account_name'][0] if len(query_res['account_name']) == 1 else None, + 'expected_date': expected_date or None, + 'total': None, + 'has_sublines': query_res['aml_count'] > 0, + + # Needed by the custom_unfold_all_batch_data_generator, to speed-up unfold_all + 'partner_id': query_res['partner_id'][0] if query_res['partner_id'] else None, + }) + else: + rslt.update({ + 'invoice_date': None, + 'due_date': None, + 'amount_currency': None, + 'currency_id': None, + 'currency': None, + 'account_name': None, + 'expected_date': None, + 'total': sum(rslt[f'period{i}'] for i in range(len(periods))), + 'has_sublines': False, + }) + + return rslt + + # Build period table + period_table_format = ('(VALUES %s)' % ','.join("(%s, %s, %s)" for period in periods)) + params = list(chain.from_iterable( + (period[0] or None, period[1] or None, i) + for i, period in enumerate(periods) + )) + period_table = self.env.cr.mogrify(period_table_format, params).decode(self.env.cr.connection.encoding) + + # Build query + tables, where_clause, where_params = report._query_get(options, 'strict_range', domain=[('account_id.account_type', '=', internal_type)]) + + currency_table = report._get_query_currency_table(options) + always_present_groupby = "period_table.period_index, currency_table.rate, currency_table.precision" + if current_groupby: + select_from_groupby = f"account_move_line.{current_groupby} AS grouping_key," + groupby_clause = f"account_move_line.{current_groupby}, {always_present_groupby}" + else: + select_from_groupby = '' + groupby_clause = always_present_groupby + select_period_query = ','.join( + f""" + CASE WHEN period_table.period_index = {i} + THEN %s * ( + SUM(ROUND(account_move_line.balance * currency_table.rate, currency_table.precision)) + - COALESCE(SUM(ROUND(part_debit.amount * currency_table.rate, currency_table.precision)), 0) + + COALESCE(SUM(ROUND(part_credit.amount * currency_table.rate, currency_table.precision)), 0) + ) + ELSE 5 END AS period{i} + """ + for i in range(len(periods)) + ) + + tail_query, tail_params = report._get_engine_query_tail(offset, limit) + query = f""" + WITH period_table(date_start, date_stop, period_index) AS ({period_table}) + + SELECT + {select_from_groupby} + %s * ( + SUM(account_move_line.amount_currency) + - COALESCE(SUM(part_debit.debit_amount_currency), 0) + + COALESCE(SUM(part_credit.credit_amount_currency), 0) + ) AS amount_currency, + ARRAY_AGG(DISTINCT account_move_line.partner_id) AS partner_id, + ARRAY_AGG(account_move_line.payment_id) AS payment_id, + ARRAY_AGG(DISTINCT move.invoice_date) AS invoice_date, + ARRAY_AGG(DISTINCT COALESCE(account_move_line.date_maturity, account_move_line.date)) AS report_date, + ARRAY_AGG(DISTINCT account_move_line.expected_pay_date) AS expected_date, + ARRAY_AGG(DISTINCT account.code) AS account_name, + ARRAY_AGG(DISTINCT COALESCE(account_move_line.date_maturity, account_move_line.date)) AS due_date, + ARRAY_AGG(DISTINCT account_move_line.currency_id) AS currency_id, + COUNT(account_move_line.id) AS aml_count, + ARRAY_AGG(account.code) AS account_code, + {select_period_query} + + FROM {tables} + + JOIN account_journal journal ON journal.id = account_move_line.journal_id + JOIN account_account account ON account.id = account_move_line.account_id + JOIN account_move move ON move.id = account_move_line.move_id + JOIN {currency_table} ON currency_table.company_id = account_move_line.company_id + + LEFT JOIN LATERAL ( + SELECT + SUM(part.amount) AS amount, + SUM(part.debit_amount_currency) AS debit_amount_currency, + part.debit_move_id + FROM account_partial_reconcile part + WHERE part.max_date <= %s AND part.debit_move_id = account_move_line.id + GROUP BY part.debit_move_id + ) part_debit ON TRUE + + LEFT JOIN LATERAL ( + SELECT + SUM(part.amount) AS amount, + SUM(part.credit_amount_currency) AS credit_amount_currency, + part.credit_move_id + FROM account_partial_reconcile part + WHERE part.max_date <= %s AND part.credit_move_id = account_move_line.id + GROUP BY part.credit_move_id + ) part_credit ON TRUE + + JOIN period_table ON + ( + period_table.date_start IS NULL + OR COALESCE(account_move_line.date_maturity, account_move_line.date) <= DATE(period_table.date_start) + ) + AND + ( + period_table.date_stop IS NULL + OR COALESCE(account_move_line.date_maturity, account_move_line.date) >= DATE(period_table.date_stop) + ) + + WHERE {where_clause} + + GROUP BY {groupby_clause} + + HAVING + ( + SUM(ROUND(account_move_line.debit * currency_table.rate, currency_table.precision)) + - COALESCE(SUM(ROUND(part_debit.amount * currency_table.rate, currency_table.precision)), 0) + ) != 0 + OR + ( + SUM(ROUND(account_move_line.credit * currency_table.rate, currency_table.precision)) + - COALESCE(SUM(ROUND(part_credit.amount * currency_table.rate, currency_table.precision)), 0) + ) != 0 + {tail_query} + """ + + multiplicator = -1 if internal_type == 'liability_payable' else 1 + params = [ + multiplicator, + *([multiplicator] * len(periods)), + date_to, + date_to, + *where_params, + *tail_params, + ] + self._cr.execute(query, params) + query_res_lines = self._cr.dictfetchall() + + if not current_groupby: + return build_result_dict(report, query_res_lines) + else: + rslt = [] + + all_res_per_grouping_key = {} + for query_res in query_res_lines: + grouping_key = query_res['grouping_key'] + all_res_per_grouping_key.setdefault(grouping_key, []).append(query_res) + + for grouping_key, query_res_lines in all_res_per_grouping_key.items(): + rslt.append((grouping_key, build_result_dict(report, query_res_lines))) + + return rslt diff --git a/bemade_packing_wizard/wizard/choose_delivery_package_views.xml b/bemade_packing_wizard/wizard/choose_delivery_package_views.xml index 1b85781..97cd641 100644 --- a/bemade_packing_wizard/wizard/choose_delivery_package_views.xml +++ b/bemade_packing_wizard/wizard/choose_delivery_package_views.xml @@ -7,10 +7,14 @@ - + - + + + diff --git a/multi_account_statement_import/__init__.py b/multi_account_statement_import/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/multi_account_statement_import/__manifest__.py b/multi_account_statement_import/__manifest__.py new file mode 100644 index 0000000..1a516b2 --- /dev/null +++ b/multi_account_statement_import/__manifest__.py @@ -0,0 +1,32 @@ +# +# Bemade Inc. +# +# Copyright (C) 2023-June Bemade Inc. (). +# Author: Marc Durepos (Contact : marc@bemade.org) +# +# This program is under the terms of the Odoo Proprietary License v1.0 (OPL-1) +# It is forbidden to publish, distribute, sublicense, or sell copies of the Software +# or modified copies of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +{ + 'name': 'Multi Account Statement Import', + 'version': '17.0.0.1.0', + 'summary': 'Import Bank Statements for Multiple Accounts', + 'category': 'Accounting/Accounting', + 'author': 'Bemade Inc.', + 'website': 'http://www.bemade.org', + 'license': 'LGPL-3', + 'depends': ['account_bank_statement_import'], + 'data': [], + 'assets': {}, + 'installable': True, + 'auto_install': False, +} From 7cdefa1a9c5d28209c1420799afef336066e4d4d Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Tue, 28 May 2024 14:57:22 -0400 Subject: [PATCH 3/9] improvements to aged partner balance na reports --- aged_partner_balance_na/__init__.py | 23 +++++++++++++++++++ .../models/aged_partner_balance.py | 4 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/aged_partner_balance_na/__init__.py b/aged_partner_balance_na/__init__.py index e63df36..c7752aa 100644 --- a/aged_partner_balance_na/__init__.py +++ b/aged_partner_balance_na/__init__.py @@ -2,9 +2,32 @@ from . import models def post_init(env): + env.['account.report'].search([('name', 'ilike', 'aged_%_report_na')]).unlink() new_receivable_report = env.ref('account_reports.aged_receivable_report').copy() new_payable_report = env.ref('account_reports.aged_payable_report').copy() new_receivable_report.line_ids.mapped('expression_ids').write({ 'formula': '_report_custom_engine_aged_receivable_na' }) new_payable_report.line_ids.mapped('expression_ids').write({'formula': '_report_custom_engine_aged_payable_na'}) + new_receivable_report.write({ + 'name': 'Aged Receivable - North America', + 'root_report_id': env.ref('account_reports.aged_receivable_report').id, + 'availability_condition': 'always', + }) + new_payable_report.write({ + 'name': 'Aged Payable - North America', + 'root_report_id': env.ref('account_reports.aged_payable_report').id, + 'availability_condition': 'always', + }) + col_name_mapping = [ + ('At Date', '0-29'), + ('1-30', '30-59'), + ('31-60', '60-89'), + ('61-90', '90-119'), + ('91-120', '120-159'), + ('Older', 'Later'), + ] + for old_name, new_name in col_name_mapping: + ((new_payable_report | new_receivable_report) + .mapped('column_ids') + .filtered(lambda col: col.name == old_name)).write({'name': new_name}) diff --git a/aged_partner_balance_na/models/aged_partner_balance.py b/aged_partner_balance_na/models/aged_partner_balance.py index 5ad1911..aa1024a 100644 --- a/aged_partner_balance_na/models/aged_partner_balance.py +++ b/aged_partner_balance_na/models/aged_partner_balance.py @@ -55,12 +55,12 @@ class AgedPartnerBalanceCustomHandler(models.AbstractModel): date_to = fields.Date.from_string(options['date']['date_to']) periods = [ - (False, fields.Date.to_string(date_to)), (date_to, plus_days(date_to, 29)), (plus_days(date_to, 30), plus_days(date_to, 59)), (plus_days(date_to, 60), plus_days(date_to, 89)), (plus_days(date_to, 90), plus_days(date_to, 119)), - (plus_days(date_to, 120), False), + (plus_days(date_to, 120), plus_days(date_to, 159)), + (plus_days(date_to, 160), False), ] def build_result_dict(report, query_res_lines): From 7c51f050889b73b4f3df507c2a8c389e16f0723a Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Tue, 28 May 2024 14:59:00 -0400 Subject: [PATCH 4/9] fix syntax error in partner reports --- aged_partner_balance_na/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aged_partner_balance_na/__init__.py b/aged_partner_balance_na/__init__.py index c7752aa..83411f0 100644 --- a/aged_partner_balance_na/__init__.py +++ b/aged_partner_balance_na/__init__.py @@ -2,7 +2,7 @@ from . import models def post_init(env): - env.['account.report'].search([('name', 'ilike', 'aged_%_report_na')]).unlink() + env['account.report'].search([('name', 'ilike', 'aged_%_report_na')]).unlink() new_receivable_report = env.ref('account_reports.aged_receivable_report').copy() new_payable_report = env.ref('account_reports.aged_payable_report').copy() new_receivable_report.line_ids.mapped('expression_ids').write({ From 6ffd75f2993df5b10d37c0ffecd7d6fbe61571ab Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Tue, 28 May 2024 15:26:30 -0400 Subject: [PATCH 5/9] fix for aged partner balance na --- aged_partner_balance_na/__init__.py | 2 +- aged_partner_balance_na/models/aged_partner_balance.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aged_partner_balance_na/__init__.py b/aged_partner_balance_na/__init__.py index 83411f0..095b9a8 100644 --- a/aged_partner_balance_na/__init__.py +++ b/aged_partner_balance_na/__init__.py @@ -2,7 +2,7 @@ from . import models def post_init(env): - env['account.report'].search([('name', 'ilike', 'aged_%_report_na')]).unlink() + env['account.report'].search([('name', 'ilike', 'Aged % - North America')]).unlink() new_receivable_report = env.ref('account_reports.aged_receivable_report').copy() new_payable_report = env.ref('account_reports.aged_payable_report').copy() new_receivable_report.line_ids.mapped('expression_ids').write({ diff --git a/aged_partner_balance_na/models/aged_partner_balance.py b/aged_partner_balance_na/models/aged_partner_balance.py index aa1024a..e3bb751 100644 --- a/aged_partner_balance_na/models/aged_partner_balance.py +++ b/aged_partner_balance_na/models/aged_partner_balance.py @@ -131,7 +131,7 @@ class AgedPartnerBalanceCustomHandler(models.AbstractModel): - COALESCE(SUM(ROUND(part_debit.amount * currency_table.rate, currency_table.precision)), 0) + COALESCE(SUM(ROUND(part_credit.amount * currency_table.rate, currency_table.precision)), 0) ) - ELSE 5 END AS period{i} + ELSE 0 END AS period{i} """ for i in range(len(periods)) ) From 564f6e022262b7c06864ef10dc4ba0df335f48b2 Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Tue, 28 May 2024 15:41:13 -0400 Subject: [PATCH 6/9] fix miscalculation in aged partner balance na --- aged_partner_balance_na/__init__.py | 10 +++++----- aged_partner_balance_na/models/aged_partner_balance.py | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/aged_partner_balance_na/__init__.py b/aged_partner_balance_na/__init__.py index 095b9a8..f9f04df 100644 --- a/aged_partner_balance_na/__init__.py +++ b/aged_partner_balance_na/__init__.py @@ -20,11 +20,11 @@ def post_init(env): 'availability_condition': 'always', }) col_name_mapping = [ - ('At Date', '0-29'), - ('1-30', '30-59'), - ('31-60', '60-89'), - ('61-90', '90-119'), - ('91-120', '120-159'), + ('At Date', 'Overdue'), + ('1-30', '0-29'), + ('31-60', '30-59'), + ('61-90', '60-89'), + ('91-120', '90-119'), ('Older', 'Later'), ] for old_name, new_name in col_name_mapping: diff --git a/aged_partner_balance_na/models/aged_partner_balance.py b/aged_partner_balance_na/models/aged_partner_balance.py index e3bb751..5095991 100644 --- a/aged_partner_balance_na/models/aged_partner_balance.py +++ b/aged_partner_balance_na/models/aged_partner_balance.py @@ -51,10 +51,14 @@ class AgedPartnerBalanceCustomHandler(models.AbstractModel): report._check_groupby_fields((next_groupby.split(',') if next_groupby else []) + ([current_groupby] if current_groupby else [])) def plus_days(date_obj, days): + return fields.Date.to_string(date_obj + relativedelta(days=days)) + + def minus_days(date_obj, days): return fields.Date.to_string(date_obj - relativedelta(days=days)) date_to = fields.Date.from_string(options['date']['date_to']) periods = [ + (False, minus_days(date_to, 1)) (date_to, plus_days(date_to, 29)), (plus_days(date_to, 30), plus_days(date_to, 59)), (plus_days(date_to, 60), plus_days(date_to, 89)), From b6d17bd3cf44a257fa1fbdb8435c3610beb00113 Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Tue, 28 May 2024 15:45:16 -0400 Subject: [PATCH 7/9] fix syntax error in aged partner balance na --- aged_partner_balance_na/models/aged_partner_balance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aged_partner_balance_na/models/aged_partner_balance.py b/aged_partner_balance_na/models/aged_partner_balance.py index 5095991..40de342 100644 --- a/aged_partner_balance_na/models/aged_partner_balance.py +++ b/aged_partner_balance_na/models/aged_partner_balance.py @@ -58,7 +58,7 @@ class AgedPartnerBalanceCustomHandler(models.AbstractModel): date_to = fields.Date.from_string(options['date']['date_to']) periods = [ - (False, minus_days(date_to, 1)) + (False, minus_days(date_to, 1)), (date_to, plus_days(date_to, 29)), (plus_days(date_to, 30), plus_days(date_to, 59)), (plus_days(date_to, 60), plus_days(date_to, 89)), From cc7c73ad9a712d0550dbb3e436113136d2d767e4 Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Tue, 28 May 2024 15:52:35 -0400 Subject: [PATCH 8/9] working on error in aged_partner_balance_na --- aged_partner_balance_na/models/aged_partner_balance.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aged_partner_balance_na/models/aged_partner_balance.py b/aged_partner_balance_na/models/aged_partner_balance.py index 40de342..ba9dbcc 100644 --- a/aged_partner_balance_na/models/aged_partner_balance.py +++ b/aged_partner_balance_na/models/aged_partner_balance.py @@ -63,8 +63,7 @@ class AgedPartnerBalanceCustomHandler(models.AbstractModel): (plus_days(date_to, 30), plus_days(date_to, 59)), (plus_days(date_to, 60), plus_days(date_to, 89)), (plus_days(date_to, 90), plus_days(date_to, 119)), - (plus_days(date_to, 120), plus_days(date_to, 159)), - (plus_days(date_to, 160), False), + (plus_days(date_to, 120), False), ] def build_result_dict(report, query_res_lines): From 9c0ddb4812b7c047c1afd660ee509503ee3d9def Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Tue, 28 May 2024 16:03:44 -0400 Subject: [PATCH 9/9] working on error in aged_partner_balance_na --- aged_partner_balance_na/models/aged_partner_balance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aged_partner_balance_na/models/aged_partner_balance.py b/aged_partner_balance_na/models/aged_partner_balance.py index ba9dbcc..18b2c24 100644 --- a/aged_partner_balance_na/models/aged_partner_balance.py +++ b/aged_partner_balance_na/models/aged_partner_balance.py @@ -192,12 +192,12 @@ class AgedPartnerBalanceCustomHandler(models.AbstractModel): JOIN period_table ON ( period_table.date_start IS NULL - OR COALESCE(account_move_line.date_maturity, account_move_line.date) <= DATE(period_table.date_start) + OR COALESCE(account_move_line.date_maturity, account_move_line.date) >= DATE(period_table.date_start) ) AND ( period_table.date_stop IS NULL - OR COALESCE(account_move_line.date_maturity, account_move_line.date) >= DATE(period_table.date_stop) + OR COALESCE(account_move_line.date_maturity, account_move_line.date) <= DATE(period_table.date_stop) ) WHERE {where_clause}