diff --git a/partner_statement/report/activity_statement.py b/partner_statement/report/activity_statement.py index cb1f8b2b..bde4fa21 100644 --- a/partner_statement/report/activity_statement.py +++ b/partner_statement/report/activity_statement.py @@ -5,6 +5,8 @@ from collections import defaultdict from odoo import api, models +from .outstanding_statement import OutstandingStatement + class ActivityStatement(models.AbstractModel): """Model of Activity Statement""" @@ -17,40 +19,74 @@ class ActivityStatement(models.AbstractModel): return str( self._cr.mogrify( """ - SELECT l.partner_id, l.currency_id, l.company_id, - sum(CASE WHEN l.currency_id is not null AND l.amount_currency > 0.0 - THEN l.amount_currency - ELSE l.debit - END) as debit, - sum(CASE WHEN l.currency_id is not null AND l.amount_currency < 0.0 - THEN l.amount_currency * (-1) - ELSE l.credit - END) as credit + SELECT l.partner_id, l.currency_id, l.company_id, l.id, + CASE WHEN l.balance > 0.0 + THEN l.balance - sum(coalesce(pd.amount, 0.0)) + ELSE l.balance + sum(coalesce(pc.amount, 0.0)) + END AS open_amount, + CASE WHEN l.balance > 0.0 + THEN l.amount_currency - sum(coalesce(pd.debit_amount_currency, 0.0)) + ELSE l.amount_currency + sum(coalesce(pc.credit_amount_currency, 0.0)) + END AS open_amount_currency FROM account_move_line l JOIN account_account aa ON (aa.id = l.account_id) JOIN account_account_type at ON (at.id = aa.user_type_id) JOIN account_move m ON (l.move_id = m.id) + LEFT JOIN (SELECT pr.* + FROM account_partial_reconcile pr + INNER JOIN account_move_line l2 + ON pr.credit_move_id = l2.id + WHERE l2.date < %(date_start)s + ) as pd ON pd.debit_move_id = l.id + LEFT JOIN (SELECT pr.* + FROM account_partial_reconcile pr + INNER JOIN account_move_line l2 + ON pr.debit_move_id = l2.id + WHERE l2.date < %(date_start)s + ) as pc ON pc.credit_move_id = l.id WHERE l.partner_id IN %(partners)s AND at.type = %(account_type)s AND l.date < %(date_start)s AND not l.blocked AND m.state IN ('posted') - GROUP BY l.partner_id, l.currency_id, l.company_id + AND ( + (pd.id IS NOT NULL AND + pd.max_date < %(date_start)s) OR + (pc.id IS NOT NULL AND + pc.max_date < %(date_start)s) OR + (pd.id IS NULL AND pc.id IS NULL) + ) + GROUP BY l.partner_id, l.currency_id, l.company_id, l.balance, l.id """, locals(), ), "utf-8", ) - def _initial_balance_sql_q2(self, company_id): + def _initial_balance_sql_q2(self, sub): return str( self._cr.mogrify( - """ - SELECT Q1.partner_id, debit-credit AS balance, - COALESCE(Q1.currency_id, c.currency_id) AS currency_id - FROM Q1 - JOIN res_company c ON (c.id = Q1.company_id) - WHERE c.id = %(company_id)s - """, + f""" + SELECT {sub}.partner_id, {sub}.currency_id, + sum(CASE WHEN {sub}.currency_id is not null + THEN {sub}.open_amount_currency + ELSE {sub}.open_amount + END) as balance, {sub}.company_id + FROM {sub} + GROUP BY {sub}.partner_id, {sub}.currency_id, {sub}.company_id""", + locals(), + ), + "utf-8", + ) + + def _initial_balance_sql_q3(self, sub, company_id): + return str( + self._cr.mogrify( + f""" + SELECT {sub}.partner_id, {sub}.balance, + COALESCE({sub}.currency_id, c.currency_id) AS currency_id + FROM {sub} + JOIN res_company c ON (c.id = {sub}.company_id) + WHERE c.id = %(company_id)s""", locals(), ), "utf-8", @@ -63,12 +99,16 @@ class ActivityStatement(models.AbstractModel): partners = tuple(partner_ids) # pylint: disable=E8103 self.env.cr.execute( - """WITH Q1 AS (%s), Q2 AS (%s) - SELECT partner_id, currency_id, balance - FROM Q2""" + """WITH Q1 AS (%s), + Q2 AS (%s), + Q3 AS (%s) + SELECT partner_id, currency_id, sum(balance) as balance + FROM Q2 + GROUP BY partner_id, currency_id""" % ( self._initial_balance_sql_q1(partners, date_start, account_type), - self._initial_balance_sql_q2(company_id), + self._initial_balance_sql_q2("Q1"), + self._initial_balance_sql_q3("Q2", company_id), ) ) for row in self.env.cr.dictfetchall(): @@ -155,8 +195,9 @@ class ActivityStatement(models.AbstractModel): """ WITH Q1 AS (%s), Q2 AS (%s) - SELECT partner_id, move_id, date, date_maturity, name, ref, debit, - ids, credit, amount, blocked, currency_id + SELECT partner_id, move_id, date, date_maturity, ids, + COALESCE(name, '') as name, COALESCE(ref, '') as ref, + debit, credit, amount, blocked, currency_id FROM Q2 ORDER BY date, date_maturity, move_id""" % ( @@ -170,6 +211,101 @@ class ActivityStatement(models.AbstractModel): res[row.pop("partner_id")].append(row) return res + def _display_activity_reconciled_lines_sql_q1(self, sub): + return str( + self._cr.mogrify( + f""" + SELECT unnest(ids) as id + FROM {sub} + """, + locals(), + ), + "utf-8", + ) + + def _display_activity_reconciled_lines_sql_q2(self, sub, date_end): + return str( + self._cr.mogrify( + f""" + SELECT l.id as rel_id, m.name AS move_id, l.partner_id, l.date, l.name, + l.blocked, l.currency_id, l.company_id, {sub}.id, + CASE WHEN l.ref IS NOT NULL + THEN l.ref + ELSE m.ref + END as ref, + CASE WHEN (l.currency_id is not null AND l.amount_currency > 0.0) + THEN avg(l.amount_currency) + ELSE avg(l.debit) + END as debit, + CASE WHEN (l.currency_id is not null AND l.amount_currency < 0.0) + THEN avg(l.amount_currency * (-1)) + ELSE avg(l.credit) + END as credit, + CASE WHEN l.balance > 0.0 + THEN sum(coalesce(pc.amount, 0.0)) + ELSE -sum(coalesce(pd.amount, 0.0)) + END AS open_amount, + CASE WHEN l.balance > 0.0 + THEN sum(coalesce(pc.debit_amount_currency, 0.0)) + ELSE -sum(coalesce(pd.credit_amount_currency, 0.0)) + END AS open_amount_currency, + CASE WHEN l.date_maturity is null + THEN l.date + ELSE l.date_maturity + END as date_maturity + FROM {sub} + LEFT JOIN account_partial_reconcile pd ON ( + pd.debit_move_id = {sub}.id AND pd.max_date <= %(date_end)s) + LEFT JOIN account_partial_reconcile pc ON ( + pc.credit_move_id = {sub}.id AND pc.max_date <= %(date_end)s) + LEFT JOIN account_move_line l ON ( + pd.credit_move_id = l.id OR pc.debit_move_id = l.id) + LEFT JOIN account_move m ON (l.move_id = m.id) + WHERE l.date <= %(date_end)s AND m.state IN ('posted') + GROUP BY l.id, l.partner_id, m.name, l.date, l.date_maturity, l.name, + CASE WHEN l.ref IS NOT NULL + THEN l.ref + ELSE m.ref + END, {sub}.id, + l.blocked, l.currency_id, l.balance, l.amount_currency, l.company_id + """, + locals(), + ), + "utf-8", + ) + + def _get_account_display_reconciled_lines( + self, company_id, partner_ids, date_start, date_end, account_type + ): + partners = tuple(partner_ids) + + # pylint: disable=E8103 + self.env.cr.execute( + """ + WITH Q1 AS (%s), + Q2 AS (%s), + Q3 AS (%s), + Q4 AS (%s), + Q5 AS (%s), + Q6 AS (%s) + SELECT partner_id, currency_id, move_id, date, date_maturity, debit, + credit, amount, open_amount, COALESCE(name, '') as name, + COALESCE(ref, '') as ref, blocked, id + FROM Q6 + ORDER BY date, date_maturity, move_id""" + % ( + self._display_activity_lines_sql_q1( + partners, date_start, date_end, account_type + ), + self._display_activity_lines_sql_q2("Q1", company_id), + self._display_activity_reconciled_lines_sql_q1("Q2"), + self._display_activity_reconciled_lines_sql_q2("Q3", date_end), + self._display_outstanding_lines_sql_q2("Q4"), + self._display_outstanding_lines_sql_q3("Q5", company_id), + ) + ) + return self.env.cr.dictfetchall() + @api.model def _get_report_values(self, docids, data=None): if not data: @@ -181,3 +317,11 @@ class ActivityStatement(models.AbstractModel): data.update(wiz.create({})._prepare_statement()) data["amount_field"] = "amount" return super()._get_report_values(docids, data) + + +ActivityStatement._display_outstanding_lines_sql_q2 = ( + OutstandingStatement._display_outstanding_lines_sql_q2 +) +ActivityStatement._display_outstanding_lines_sql_q3 = ( + OutstandingStatement._display_outstanding_lines_sql_q3 +) diff --git a/partner_statement/report/activity_statement_xlsx.py b/partner_statement/report/activity_statement_xlsx.py index b142771b..28e57da5 100644 --- a/partner_statement/report/activity_statement_xlsx.py +++ b/partner_statement/report/activity_statement_xlsx.py @@ -56,18 +56,25 @@ class ActivityStatementXslx(models.AbstractModel): row_pos, 2, row_pos, - 4, + 3, _("Description"), FORMATS["format_theader_yellow_center"], ) - sheet.write(row_pos, 5, _("Amount"), FORMATS["format_theader_yellow_center"]) - sheet.write(row_pos, 6, _("Balance"), FORMATS["format_theader_yellow_center"]) + sheet.write( + row_pos, 4, _("Original Amount"), FORMATS["format_theader_yellow_center"] + ) + sheet.write( + row_pos, 5, _("Applied Amount"), FORMATS["format_theader_yellow_center"] + ) + sheet.write( + row_pos, 6, _("Open Amount"), FORMATS["format_theader_yellow_center"] + ) row_pos += 1 sheet.write( row_pos, 1, partner_data.get("prior_day"), FORMATS["format_tcell_date_left"] ) sheet.merge_range( - row_pos, 2, row_pos, 4, _("Balance Forward"), FORMATS["format_tcell_left"] + row_pos, 2, row_pos, 5, _("Balance Forward"), FORMATS["format_tcell_left"] ) sheet.write( row_pos, @@ -89,7 +96,7 @@ class ActivityStatementXslx(models.AbstractModel): name_to_show = ( line.get("name", "") == "/" or not line.get("name", "") ) and line.get("ref", "") - if line.get("name", "") != "/": + if line.get("name", "") and line.get("name", "") != "/": if not line.get("ref", ""): name_to_show = line.get("name", "") else: @@ -101,18 +108,24 @@ class ActivityStatementXslx(models.AbstractModel): name_to_show = line.get("ref", "") sheet.write(row_pos, 0, line.get("move_id", ""), format_tcell_left) sheet.write(row_pos, 1, line.get("date", ""), format_tcell_date_left) - sheet.merge_range(row_pos, 2, row_pos, 4, name_to_show, format_distributed) - sheet.write(row_pos, 5, line.get("amount", ""), current_money_format) - sheet.write(row_pos, 6, line.get("balance", ""), current_money_format) + sheet.merge_range(row_pos, 2, row_pos, 3, name_to_show, format_distributed) + sheet.write(row_pos, 4, line.get("amount", ""), current_money_format) + sheet.write( + row_pos, 5, line.get("applied_amount", ""), current_money_format + ) + sheet.write(row_pos, 6, line.get("open_amount", ""), current_money_format) row_pos += 1 sheet.write( row_pos, 1, partner_data.get("end"), FORMATS["format_tcell_date_left"] ) sheet.merge_range( - row_pos, 2, row_pos, 4, _("Ending Balance"), FORMATS["format_tcell_left"] + row_pos, 2, row_pos, 5, _("Ending Balance"), FORMATS["format_tcell_left"] ) sheet.write( - row_pos, 6, currency_data.get("amount_due"), FORMATS["current_money_format"] + row_pos, + 6, + currency_data.get("amount_due"), + FORMATS["current_money_format"], ) return row_pos diff --git a/partner_statement/report/detailed_activity_statement.py b/partner_statement/report/detailed_activity_statement.py index 91733b8a..7507dd4d 100644 --- a/partner_statement/report/detailed_activity_statement.py +++ b/partner_statement/report/detailed_activity_statement.py @@ -20,103 +20,6 @@ class DetailedActivityStatement(models.AbstractModel): company_id, partner_ids, date_start, date_end, account_type ) - def _display_activity_reconciled_lines_sql_q1(self, sub): - return str( - self._cr.mogrify( - f""" - SELECT unnest(ids) as id - FROM {sub} - """, - locals(), - ), - "utf-8", - ) - - def _display_activity_reconciled_lines_sql_q2(self, sub, date_end): - return str( - self._cr.mogrify( - f""" - SELECT l.id as rel_id, m.name AS move_id, l.partner_id, l.date, l.name, - l.blocked, l.currency_id, l.company_id, {sub}.id, - CASE WHEN l.ref IS NOT NULL - THEN l.ref - ELSE m.ref - END as ref, - CASE WHEN (l.currency_id is not null AND l.amount_currency > 0.0) - THEN avg(l.amount_currency) - ELSE avg(l.debit) - END as debit, - CASE WHEN (l.currency_id is not null AND l.amount_currency < 0.0) - THEN avg(l.amount_currency * (-1)) - ELSE avg(l.credit) - END as credit, - CASE WHEN l.balance > 0.0 - THEN sum(coalesce(pc.amount, 0.0)) - ELSE -sum(coalesce(pd.amount, 0.0)) - END AS open_amount, - CASE WHEN l.balance > 0.0 - THEN sum(coalesce(pc.debit_amount_currency, 0.0)) - ELSE -sum(coalesce(pd.credit_amount_currency, 0.0)) - END AS open_amount_currency, - CASE WHEN l.date_maturity is null - THEN l.date - ELSE l.date_maturity - END as date_maturity - FROM {sub} - LEFT JOIN account_partial_reconcile pd ON ( - pd.debit_move_id = {sub}.id AND pd.max_date <= %(date_end)s) - LEFT JOIN account_partial_reconcile pc ON ( - pc.credit_move_id = {sub}.id AND pc.max_date <= %(date_end)s) - LEFT JOIN account_move_line l ON ( - pd.credit_move_id = l.id OR pc.debit_move_id = l.id) - LEFT JOIN account_move m ON (l.move_id = m.id) - WHERE l.date <= %(date_end)s AND m.state IN ('posted') - GROUP BY l.id, l.partner_id, m.name, l.date, l.date_maturity, l.name, - CASE WHEN l.ref IS NOT NULL - THEN l.ref - ELSE m.ref - END, {sub}.id, - l.blocked, l.currency_id, l.balance, l.amount_currency, l.company_id - """, - locals(), - ), - "utf-8", - ) - - def _get_account_display_reconciled_lines( - self, company_id, partner_ids, date_start, date_end, account_type - ): - res = dict(map(lambda x: (x, []), partner_ids)) - partners = tuple(partner_ids) - - # pylint: disable=E8103 - self.env.cr.execute( - """ - WITH Q1 AS (%s), - Q2 AS (%s), - Q3 AS (%s), - Q4 AS (%s), - Q5 AS (%s), - Q6 AS (%s) - SELECT partner_id, currency_id, move_id, date, date_maturity, debit, - credit, amount, open_amount, name, ref, blocked, id - FROM Q6 - ORDER BY date, date_maturity, move_id""" - % ( - self._display_activity_lines_sql_q1( - partners, date_start, date_end, account_type - ), - self._display_activity_lines_sql_q2("Q1", company_id), - self._display_activity_reconciled_lines_sql_q1("Q2"), - self._display_activity_reconciled_lines_sql_q2("Q3", date_end), - self._display_outstanding_lines_sql_q2("Q4"), - self._display_outstanding_lines_sql_q3("Q5", company_id), - ) - ) - for row in self.env.cr.dictfetchall(): - res[row.pop("partner_id")].append(row) - return res - def _get_account_display_ending_lines( self, company_id, partner_ids, date_start, date_end, account_type ): @@ -127,9 +30,6 @@ class DetailedActivityStatement(models.AbstractModel): def _add_currency_prior_line(self, line, currency): return self._add_currency_line2(line, currency) - def _add_currency_reconciled_line(self, line, currency): - return self._add_currency_line2(line, currency) - def _add_currency_ending_line(self, line, currency): return self._add_currency_line2(line, currency) @@ -140,10 +40,4 @@ DetailedActivityStatement._get_account_display_lines2 = ( DetailedActivityStatement._display_outstanding_lines_sql_q1 = ( OutstandingStatement._display_outstanding_lines_sql_q1 ) -DetailedActivityStatement._display_outstanding_lines_sql_q2 = ( - OutstandingStatement._display_outstanding_lines_sql_q2 -) -DetailedActivityStatement._display_outstanding_lines_sql_q3 = ( - OutstandingStatement._display_outstanding_lines_sql_q3 -) DetailedActivityStatement._add_currency_line2 = OutstandingStatement._add_currency_line diff --git a/partner_statement/report/detailed_activity_statement_xlsx.py b/partner_statement/report/detailed_activity_statement_xlsx.py index c5ae0fb0..1b83db13 100644 --- a/partner_statement/report/detailed_activity_statement_xlsx.py +++ b/partner_statement/report/detailed_activity_statement_xlsx.py @@ -37,7 +37,6 @@ class DetailedActivityStatementXslx(models.AbstractModel): partner_data = data.get("data", {}).get(partner.id, {}) currency_data = partner_data.get("currencies", {}).get(currency.id) account_type = data.get("account_type", False) - show_balance = data.get("show_balance", True) row_pos += 2 statement_header = _("Detailed %sStatement between %s and %s in %s") % ( account_type == "payable" and _("Supplier ") or "", @@ -49,7 +48,7 @@ class DetailedActivityStatementXslx(models.AbstractModel): row_pos, 0, row_pos, - 7 if show_balance else 6, + 6, statement_header, FORMATS["format_left_bold"], ) @@ -66,17 +65,15 @@ class DetailedActivityStatementXslx(models.AbstractModel): _("Description"), FORMATS["format_theader_yellow_center"], ) - sheet.write(row_pos, 4, _("Original"), FORMATS["format_theader_yellow_center"]) + sheet.write( + row_pos, 4, _("Original Amount"), FORMATS["format_theader_yellow_center"] + ) sheet.write( row_pos, 5, _("Applied Amount"), FORMATS["format_theader_yellow_center"] ) sheet.write( row_pos, 6, _("Open Amount"), FORMATS["format_theader_yellow_center"] ) - if show_balance: - sheet.write( - row_pos, 7, _("Balance"), FORMATS["format_theader_yellow_center"] - ) row_pos += 1 sheet.write( row_pos, 1, partner_data.get("prior_day"), FORMATS["format_tcell_date_left"] @@ -85,13 +82,13 @@ class DetailedActivityStatementXslx(models.AbstractModel): row_pos, 2, row_pos, - 6 if show_balance else 5, + 5, _("Initial Balance"), FORMATS["format_tcell_left"], ) sheet.write( row_pos, - 7 if show_balance else 6, + 6, currency_data.get("balance_forward"), FORMATS["current_money_format"], ) @@ -124,7 +121,7 @@ class DetailedActivityStatementXslx(models.AbstractModel): name_to_show = ( line.get("name", "") == "/" or not line.get("name", "") ) and line.get("ref", "") - if line.get("name", "") != "/": + if line.get("name", "") and line.get("name", "") != "/": if not line.get("ref", ""): name_to_show = line.get("name", "") else: @@ -152,8 +149,6 @@ class DetailedActivityStatementXslx(models.AbstractModel): line.get("open_amount", "") if not line.get("reconciled_line") else "", current_money_format, ) - if show_balance: - sheet.write(row_pos, 7, line.get("balance", ""), current_money_format) row_pos += 1 sheet.write( row_pos, 1, partner_data.get("end"), FORMATS["format_tcell_date_left"] @@ -162,13 +157,13 @@ class DetailedActivityStatementXslx(models.AbstractModel): row_pos, 2, row_pos, - 6 if show_balance else 5, + 5, _("Ending Balance"), FORMATS["format_tcell_left"], ) sheet.write( row_pos, - 7 if show_balance else 6, + 6, currency_data.get("amount_due"), FORMATS["current_money_format"], ) @@ -178,7 +173,6 @@ class DetailedActivityStatementXslx(models.AbstractModel): partner_data = data.get("data", {}).get(partner.id, {}) currency_data = partner_data.get("currencies", {}).get(currency.id) account_type = data.get("account_type", False) - show_balance = data.get("show_balance", True) row_pos += 2 statement_header = _("%sStatement up to %s in %s") % ( account_type == "payable" and _("Supplier ") or "", @@ -189,7 +183,7 @@ class DetailedActivityStatementXslx(models.AbstractModel): row_pos, 0, row_pos, - 7 if show_balance else 6, + 6, statement_header, FORMATS["format_left_bold"], ) @@ -199,22 +193,17 @@ class DetailedActivityStatementXslx(models.AbstractModel): ) sheet.write(row_pos, 1, _("Date"), FORMATS["format_theader_yellow_center"]) sheet.write(row_pos, 2, _("Due Date"), FORMATS["format_theader_yellow_center"]) - sheet.merge_range( + sheet.write( row_pos, 3, - row_pos, - 4, _("Description"), FORMATS["format_theader_yellow_center"], ) - sheet.write(row_pos, 5, _("Original"), FORMATS["format_theader_yellow_center"]) + sheet.write(row_pos, 4, _("Original"), FORMATS["format_theader_yellow_center"]) sheet.write( - row_pos, 6, _("Open Amount"), FORMATS["format_theader_yellow_center"] + row_pos, 5, _("Open Amount"), FORMATS["format_theader_yellow_center"] ) - if show_balance: - sheet.write( - row_pos, 7, _("Balance"), FORMATS["format_theader_yellow_center"] - ) + sheet.write(row_pos, 6, _("Balance"), FORMATS["format_theader_yellow_center"]) format_tcell_left = FORMATS["format_tcell_left"] format_tcell_date_left = FORMATS["format_tcell_date_left"] format_distributed = FORMATS["format_distributed"] @@ -243,7 +232,7 @@ class DetailedActivityStatementXslx(models.AbstractModel): name_to_show = ( line.get("name", "") == "/" or not line.get("name", "") ) and line.get("ref", "") - if line.get("name", "") != "/": + if line.get("name", "") and line.get("name", "") != "/": if not line.get("ref", ""): name_to_show = line.get("name", "") else: @@ -261,11 +250,10 @@ class DetailedActivityStatementXslx(models.AbstractModel): line.get("date_maturity", ""), format_tcell_date_left, ) - sheet.merge_range(row_pos, 3, row_pos, 4, name_to_show, format_distributed) - sheet.write(row_pos, 5, line.get("amount", ""), current_money_format) - sheet.write(row_pos, 6, line.get("open_amount", ""), current_money_format) - if show_balance: - sheet.write(row_pos, 7, line.get("balance", ""), current_money_format) + sheet.write(row_pos, 3, name_to_show, format_distributed) + sheet.write(row_pos, 4, line.get("amount", ""), current_money_format) + sheet.write(row_pos, 5, line.get("open_amount", ""), current_money_format) + sheet.write(row_pos, 6, line.get("balance", ""), current_money_format) row_pos += 1 sheet.write( row_pos, 1, partner_data.get("prior_day"), FORMATS["format_tcell_date_left"] @@ -274,14 +262,14 @@ class DetailedActivityStatementXslx(models.AbstractModel): row_pos, 2, row_pos, - 6 if show_balance else 5, + 5, _("Ending Balance"), FORMATS["format_tcell_left"], ) sheet.write( row_pos, - 7 if show_balance else 6, - currency_data.get("amount_due"), + 6, + currency_data.get("balance_forward"), FORMATS["current_money_format"], ) return row_pos @@ -290,7 +278,6 @@ class DetailedActivityStatementXslx(models.AbstractModel): partner_data = data.get("data", {}).get(partner.id, {}) currency_data = partner_data.get("currencies", {}).get(currency.id) account_type = data.get("account_type", False) - show_balance = data.get("show_balance", True) row_pos += 2 statement_header = _("%sStatement up to %s in %s") % ( account_type == "payable" and _("Supplier ") or "", @@ -301,7 +288,7 @@ class DetailedActivityStatementXslx(models.AbstractModel): row_pos, 0, row_pos, - 7 if show_balance else 6, + 6, statement_header, FORMATS["format_left_bold"], ) @@ -311,22 +298,17 @@ class DetailedActivityStatementXslx(models.AbstractModel): ) sheet.write(row_pos, 1, _("Date"), FORMATS["format_theader_yellow_center"]) sheet.write(row_pos, 2, _("Due Date"), FORMATS["format_theader_yellow_center"]) - sheet.merge_range( + sheet.write( row_pos, 3, - row_pos, - 4, _("Description"), FORMATS["format_theader_yellow_center"], ) - sheet.write(row_pos, 5, _("Original"), FORMATS["format_theader_yellow_center"]) + sheet.write(row_pos, 4, _("Original"), FORMATS["format_theader_yellow_center"]) sheet.write( - row_pos, 6, _("Open Amount"), FORMATS["format_theader_yellow_center"] + row_pos, 5, _("Open Amount"), FORMATS["format_theader_yellow_center"] ) - if show_balance: - sheet.write( - row_pos, 7, _("Balance"), FORMATS["format_theader_yellow_center"] - ) + sheet.write(row_pos, 6, _("Balance"), FORMATS["format_theader_yellow_center"]) format_tcell_left = FORMATS["format_tcell_left"] format_tcell_date_left = FORMATS["format_tcell_date_left"] format_distributed = FORMATS["format_distributed"] @@ -355,7 +337,7 @@ class DetailedActivityStatementXslx(models.AbstractModel): name_to_show = ( line.get("name", "") == "/" or not line.get("name", "") ) and line.get("ref", "") - if line.get("name", "") != "/": + if line.get("name", "") and line.get("name", "") != "/": if not line.get("ref", ""): name_to_show = line.get("name", "") else: @@ -373,11 +355,10 @@ class DetailedActivityStatementXslx(models.AbstractModel): line.get("date_maturity", ""), format_tcell_date_left, ) - sheet.merge_range(row_pos, 3, row_pos, 4, name_to_show, format_distributed) - sheet.write(row_pos, 5, line.get("amount", ""), current_money_format) - sheet.write(row_pos, 6, line.get("open_amount", ""), current_money_format) - if show_balance: - sheet.write(row_pos, 7, line.get("balance", ""), current_money_format) + sheet.write(row_pos, 3, name_to_show, format_distributed) + sheet.write(row_pos, 4, line.get("amount", ""), current_money_format) + sheet.write(row_pos, 5, line.get("open_amount", ""), current_money_format) + sheet.write(row_pos, 6, line.get("balance", ""), current_money_format) row_pos += 1 sheet.write( row_pos, 1, partner_data.get("end"), FORMATS["format_tcell_date_left"] @@ -386,21 +367,20 @@ class DetailedActivityStatementXslx(models.AbstractModel): row_pos, 2, row_pos, - 6 if show_balance else 5, + 5, _("Ending Balance"), FORMATS["format_tcell_left"], ) sheet.write( row_pos, - 7 if show_balance else 6, + 6, currency_data.get("amount_due"), FORMATS["current_money_format"], ) return row_pos def _size_columns(self, sheet, data): - show_balance = data.get("show_balance", True) - for i in range(8 if show_balance else 7): + for i in range(7): sheet.set_column(0, i, 20) def generate_xlsx_report(self, workbook, data, objects): @@ -413,7 +393,6 @@ class DetailedActivityStatementXslx(models.AbstractModel): else: company = self.env.user.company_id data.update(report_model._get_report_values(data.get("partner_ids"), data)) - show_balance = data.get("show_balance", True) partners = self.env["res.partner"].browse(data.get("partner_ids")) sheet = workbook.add_worksheet(_("Detailed Activity Statement")) sheet.set_landscape() @@ -422,7 +401,7 @@ class DetailedActivityStatementXslx(models.AbstractModel): row_pos, 0, row_pos, - 7 if show_balance else 6, + 6, _("Statement of Account from %s") % (company.display_name,), FORMATS["format_ws_title"], ) diff --git a/partner_statement/report/outstanding_statement.py b/partner_statement/report/outstanding_statement.py index d055b4dc..a4d69a3c 100644 --- a/partner_statement/report/outstanding_statement.py +++ b/partner_statement/report/outstanding_statement.py @@ -60,13 +60,13 @@ class OutstandingStatement(models.AbstractModel): WHERE l2.date <= %(date_end)s ) as pc ON pc.credit_move_id = l.id WHERE l.partner_id IN %(partners)s AND at.type = %(account_type)s - AND ( - (pd.id IS NOT NULL AND - pd.max_date <= %(date_end)s) OR - (pc.id IS NOT NULL AND - pc.max_date <= %(date_end)s) OR - (pd.id IS NULL AND pc.id IS NULL) - ) AND l.date <= %(date_end)s AND m.state IN ('posted') + AND ( + (pd.id IS NOT NULL AND + pd.max_date <= %(date_end)s) OR + (pc.id IS NOT NULL AND + pc.max_date <= %(date_end)s) OR + (pd.id IS NULL AND pc.id IS NULL) + ) AND l.date <= %(date_end)s AND m.state IN ('posted') GROUP BY l.id, l.partner_id, m.name, l.date, l.date_maturity, l.name, CASE WHEN l.ref IS NOT NULL THEN l.ref @@ -86,10 +86,10 @@ class OutstandingStatement(models.AbstractModel): SELECT {sub}.partner_id, {sub}.currency_id, {sub}.move_id, {sub}.date, {sub}.date_maturity, {sub}.debit, {sub}.credit, {sub}.name, {sub}.ref, {sub}.blocked, {sub}.company_id, - CASE WHEN {sub}.currency_id is not null - THEN {sub}.open_amount_currency - ELSE {sub}.open_amount - END as open_amount, {sub}.id + CASE WHEN {sub}.currency_id is not null + THEN {sub}.open_amount_currency + ELSE {sub}.open_amount + END as open_amount, {sub}.id FROM {sub} """, locals(), @@ -101,11 +101,11 @@ class OutstandingStatement(models.AbstractModel): return str( self._cr.mogrify( f""" - SELECT {sub}.partner_id, {sub}.move_id, {sub}.date, {sub}.date_maturity, - {sub}.name, {sub}.ref, {sub}.debit, {sub}.credit, - {sub}.debit-{sub}.credit AS amount, blocked, - COALESCE({sub}.currency_id, c.currency_id) AS currency_id, - {sub}.open_amount, {sub}.id + SELECT {sub}.partner_id, {sub}.move_id, {sub}.date, + {sub}.date_maturity, {sub}.name, {sub}.ref, {sub}.debit, + {sub}.credit, {sub}.debit-{sub}.credit AS amount, + COALESCE({sub}.currency_id, c.currency_id) AS currency_id, + {sub}.open_amount, {sub}.blocked, {sub}.id FROM {sub} JOIN res_company c ON (c.id = {sub}.company_id) WHERE c.id = %(company_id)s AND {sub}.open_amount != 0.0 @@ -127,7 +127,8 @@ class OutstandingStatement(models.AbstractModel): Q2 AS (%s), Q3 AS (%s) SELECT partner_id, currency_id, move_id, date, date_maturity, debit, - credit, amount, open_amount, name, ref, blocked, id + credit, amount, open_amount, COALESCE(name, '') as name, + COALESCE(ref, '') as ref, blocked, id FROM Q3 ORDER BY date, date_maturity, move_id""" % ( diff --git a/partner_statement/report/outstanting_statement_xlsx.py b/partner_statement/report/outstanting_statement_xlsx.py index e6cb41d6..6d37744a 100644 --- a/partner_statement/report/outstanting_statement_xlsx.py +++ b/partner_statement/report/outstanting_statement_xlsx.py @@ -74,7 +74,7 @@ class OutstandingStatementXslx(models.AbstractModel): name_to_show = ( line.get("name", "") == "/" or not line.get("name", "") ) and line.get("ref", "") - if line.get("name", "") != "/": + if line.get("name", "") and line.get("name", "") != "/": if not line.get("ref", ""): name_to_show = line.get("name", "") else: diff --git a/partner_statement/report/report_statement_common.py b/partner_statement/report/report_statement_common.py index ed75483d..297bf9fc 100644 --- a/partner_statement/report/report_statement_common.py +++ b/partner_statement/report/report_statement_common.py @@ -302,6 +302,7 @@ class ReportStatementCommon(models.AbstractModel): "buckets": [], "balance_forward": balance_forward, "amount_due": amount_due, + "ending_balance": 0.0, }, currencies, ) @@ -312,9 +313,6 @@ class ReportStatementCommon(models.AbstractModel): def _add_currency_prior_line(self, line, currency): return [line] - def _add_currency_reconciled_line(self, line, currency): - return [line] - def _add_currency_ending_line(self, line, currency): return [line] @@ -353,9 +351,8 @@ class ReportStatementCommon(models.AbstractModel): date_end = datetime.strptime(date_end, DEFAULT_SERVER_DATE_FORMAT).date() account_type = data["account_type"] aging_type = data["aging_type"] - show_balance = data.get("show_balance", True) - is_detailed = data.get("is_detailed") and data.get("is_activity") - # because detailed outstanding doesn't exist (yet) + is_activity = data.get("is_activity") + is_detailed = data.get("is_detailed") today = fields.Date.today() amount_field = data.get("amount_field", "amount") @@ -397,7 +394,7 @@ class ReportStatementCommon(models.AbstractModel): self._get_account_display_reconciled_lines( company_id, partner_ids, date_start, date_end, account_type ) - if is_detailed + if is_activity else {} ) balances_forward = self._get_account_initial_balance( @@ -412,7 +409,7 @@ class ReportStatementCommon(models.AbstractModel): else: bucket_labels = {} - # organise and format for report + # organize and format for report format_date = self._format_date_to_partner_lang partners_to_remove = set() for partner_id in partner_ids: @@ -472,8 +469,12 @@ class ReportStatementCommon(models.AbstractModel): ) line_currency = currency_dict[line["currency_id"]] if not line["blocked"]: - line_currency["amount_due"] += line[amount_field] - line["balance"] = line_currency["amount_due"] + if not is_activity: + line_currency["amount_due"] += line[amount_field] + line["balance"] = line_currency["amount_due"] + else: + line_currency["ending_balance"] += line[amount_field] + line["balance"] = line_currency["ending_balance"] line["date"] = format_date( line["date"], date_formats.get(partner_id, default_fmt) ) @@ -481,12 +482,13 @@ class ReportStatementCommon(models.AbstractModel): line["date_maturity"], date_formats.get(partner_id, default_fmt) ) line["reconciled_line"] = False - if is_detailed: + if is_activity: line["open_amount"] = 0.0 + line["applied_amount"] = 0.0 line_currency["lines"].extend( self._add_currency_line(line, currencies[line["currency_id"]]) ) - for line2 in reconciled_lines.get(partner_id, []): + for line2 in reconciled_lines: if line2["id"] in line["ids"]: line2["date"] = format_date( line2["date"], date_formats.get(partner_id, default_fmt) @@ -497,56 +499,37 @@ class ReportStatementCommon(models.AbstractModel): ) line2["reconciled_line"] = True line2["applied_amount"] = line2["open_amount"] - line_currency["lines"].extend( - self._add_currency_reconciled_line( - line2, currencies[line["currency_id"]] + line["applied_amount"] += line2["open_amount"] + if is_detailed: + line_currency["lines"].extend( + self._add_currency_line( + line2, currencies[line["currency_id"]] + ) ) - ) + if is_activity: + line["open_amount"] = line["amount"] + line["applied_amount"] + line_currency["amount_due"] += line["open_amount"] + + if is_detailed: + for line_currency in currency_dict.values(): + line_currency["amount_due"] = 0.0 for line in ending_lines.get(partner_id, []): line_currency = currency_dict[line["currency_id"]] - ending_balance = 0.0 - for line2 in prior_lines.get(partner_id, []): - if line["id"] == line2["id"]: - if not line["blocked"]: - ending_balance += line["open_amount"] - line["balance"] = ending_balance - line["date"] = format_date( - line["date"], date_formats.get(partner_id, default_fmt) - ) - line["date_maturity"] = format_date( - line["date_maturity"], - date_formats.get(partner_id, default_fmt), - ) - line_currency["ending_lines"].extend( - self._add_currency_ending_line( - line, currencies[line["currency_id"]] - ) - ) - for line in ending_lines.get(partner_id, []): - line_currency = currency_dict[line["currency_id"]] - for line2 in lines.get(partner_id, []): - if line2["reconciled_line"]: - continue - if line["id"] == line2["ids"][0]: - same_lines = [ - ln - for ln in ending_lines[partner_id] - if ln["id"] in set(line2["ids"]) - ] - line2["open_amount"] = sum( - ln["open_amount"] for ln in same_lines - ) - line_currency["ending_lines"].extend( - self._add_currency_ending_line( - line2, currencies[line["currency_id"]] - ) - ) - if is_detailed: - for line in lines[partner_id]: - if line["reconciled_line"]: - continue - line["applied_amount"] = line["open_amount"] - line["amount"] + if not line["blocked"]: + line_currency["amount_due"] += line["open_amount"] + line["balance"] = line_currency["amount_due"] + line["date"] = format_date( + line["date"], date_formats.get(partner_id, default_fmt) + ) + line["date_maturity"] = format_date( + line["date_maturity"], date_formats.get(partner_id, default_fmt) + ) + line_currency["ending_lines"].extend( + self._add_currency_ending_line( + line, currencies[line["currency_id"]] + ) + ) if data["show_aging_buckets"]: for line in buckets[partner_id]: @@ -585,7 +568,6 @@ class ReportStatementCommon(models.AbstractModel): "Currencies": currencies, "account_type": account_type, "is_detailed": is_detailed, - "show_balance": show_balance, "bucket_labels": bucket_labels, "get_inv_addr": self._get_invoice_address, } diff --git a/partner_statement/views/activity_statement.xml b/partner_statement/views/activity_statement.xml index 6374fa4a..c8c371f7 100644 --- a/partner_statement/views/activity_statement.xml +++ b/partner_statement/views/activity_statement.xml @@ -17,12 +17,9 @@ Reference number Date Description - OriginalAmount - Applied Amount - Open Amount - Balance + Original Amount + Applied Amount + Open Amount @@ -33,9 +30,8 @@ Initial Balance Balance Forward - - - + + - + - + - - - @@ -114,9 +103,8 @@ Ending Balance - - - + + Description Original Open Amount - Balance + Balance @@ -72,7 +72,7 @@ t-options="{'widget': 'monetary', 'display_currency': display_currency}" /> - + - + Detailed Activity Statement Wizard detailed.activity.statement.wizard - + primary - - - + + The detailed activity statement is an extension of the activity statement, and intends to explain the transactions +that have happened during the period, also providing with a Prior Balance section and an Ending Balance section. + +
+
+
+ + +