diff --git a/addons/account/i18n/account.pot b/addons/account/i18n/account.pot index cef086a7d04..bc02aff6450 100644 --- a/addons/account/i18n/account.pot +++ b/addons/account/i18n/account.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server saas~16.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-30 05:08+0000\n" -"PO-Revision-Date: 2023-05-30 05:08+0000\n" +"POT-Creation-Date: 2023-07-04 14:39+0000\n" +"PO-Revision-Date: 2023-07-04 14:39+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -85,6 +85,13 @@ msgstr "" msgid "%(amount)s due %(date)s" msgstr "" +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "%(partner_name)s has reached its credit limit of: %(credit_limit)s" +msgstr "" + #. module: account #: model_terms:ir.ui.view,arch_db:account.account_automatic_entry_wizard_form msgid "%(" @@ -159,15 +166,6 @@ msgstr "" msgid "%s Incl. Taxes" msgstr "" -#. module: account -#. odoo-python -#: code:addons/account/models/account_move.py:0 -#, python-format -msgid "" -"%s has reached its Credit Limit of: %s\n" -"Total amount due" -msgstr "" - #. module: account #. odoo-python #: code:addons/account/models/account_move_line.py:0 @@ -13737,6 +13735,36 @@ msgstr "" msgid "Total Signed" msgstr "" +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "" +"Total amount due (including sales orders and this document): " +"%(total_credit)s" +msgstr "" + +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "Total amount due (including sales orders): %(total_credit)s" +msgstr "" + +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "Total amount due (including this document): %(total_credit)s" +msgstr "" + +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "Total amount due: %(total_credit)s" +msgstr "" + #. module: account #: model:ir.model.fields,help:account.field_account_automatic_entry_wizard__total_amount msgid "Total amount impacted by the automatic entry." diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 8a63563c8dc..63a3f6f6f2d 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -1428,31 +1428,55 @@ class AccountMove(models.Model): move.company_id.account_use_credit_limit if show_warning: move.partner_credit_warning = self._build_credit_warning_message( - move, move.partner_credit, move.tax_totals['amount_total'] > 0.0) + move, + current_amount=move.tax_totals['amount_total'], + exclude_current=True, + ) @api.depends('partner_id') def _compute_partner_credit(self): for move in self: move.partner_credit = move.partner_id.commercial_partner_id.credit - def _build_credit_warning_message(self, record, updated_credit, include): + def _build_credit_warning_message(self, record, current_amount=0.0, exclude_current=False): """ Build the warning message that will be displayed in a yellow banner on top of the current record if the partner exceeds a credit limit (set on the company or the partner itself). :param record: The record where the warning will appear (Invoice, Sales Order...). - :param updated_credit (float): The partner's updated credit limit including the current record. - :param include (bool): Whether the current record's amount is included in the warning message. + :param current_amount (float): The partner's outstanding credit amount from the current document. + :param exclude_current (bool): Whether to exclude `current_amount` from the credit to invoice. :return (str): The warning message to be showed. """ partner_id = record.partner_id.commercial_partner_id - if not partner_id.credit_limit or updated_credit <= partner_id.credit_limit: + credit_to_invoice = max(partner_id.credit_to_invoice - (current_amount if exclude_current else 0), 0) + total_credit = partner_id.credit + credit_to_invoice + current_amount + if not partner_id.credit_limit or total_credit <= partner_id.credit_limit: return '' - msg = _('%s has reached its Credit Limit of: %s\nTotal amount due', - partner_id.name, - formatLang(self.env, partner_id.credit_limit, currency_obj=record.company_id.currency_id)) - if include: - msg += _(' (including this document)') - msg += ': %s' % formatLang(self.env, updated_credit, currency_obj=record.company_id.currency_id) - return msg + msg = _( + '%(partner_name)s has reached its credit limit of: %(credit_limit)s', + partner_name=partner_id.name, + credit_limit=formatLang(self.env, partner_id.credit_limit, currency_obj=record.company_id.currency_id) + ) + total_credit_formatted = formatLang(self.env, total_credit, currency_obj=record.company_id.currency_id) + if credit_to_invoice > 0 and current_amount > 0: + return msg + '\n' + _( + 'Total amount due (including sales orders and this document): %(total_credit)s', + total_credit=total_credit_formatted + ) + elif credit_to_invoice > 0: + return msg + '\n' + _( + 'Total amount due (including sales orders): %(total_credit)s', + total_credit=total_credit_formatted + ) + elif current_amount > 0: + return msg + '\n' + _( + 'Total amount due (including this document): %(total_credit)s', + total_credit=total_credit_formatted + ) + else: + return msg + '\n' + _( + 'Total amount due: %(total_credit)s', + total_credit=total_credit_formatted + ) @api.depends('journal_id.type', 'company_id') def _compute_quick_edit_mode(self): diff --git a/addons/account/models/partner.py b/addons/account/models/partner.py index b66bd0cd7f1..e9a5a47e11c 100644 --- a/addons/account/models/partner.py +++ b/addons/account/models/partner.py @@ -358,6 +358,11 @@ class ResPartner(models.Model): remaining.debit = False remaining.credit = False + @api.depends_context('company') + def _compute_credit_to_invoice(self): + # To be overridden in Sales + self.credit_to_invoice = False + def _asset_difference_search(self, account_type, operator, operand): if operator not in ('<', '=', '>', '>=', '<='): return [] @@ -486,6 +491,10 @@ class ResPartner(models.Model): credit = fields.Monetary(compute='_credit_debit_get', search=_credit_search, string='Total Receivable', help="Total amount this customer owes you.", groups='account.group_account_invoice,account.group_account_readonly') + credit_to_invoice = fields.Monetary( + compute='_compute_credit_to_invoice', + groups='account.group_account_invoice,account.group_account_readonly' + ) credit_limit = fields.Float( string='Credit Limit', help='Credit limit specific to this partner.', groups='account.group_account_invoice,account.group_account_readonly', diff --git a/addons/sale/models/res_partner.py b/addons/sale/models/res_partner.py index f10da7aa9d5..51e2f63ca94 100644 --- a/addons/sale/models/res_partner.py +++ b/addons/sale/models/res_partner.py @@ -54,12 +54,14 @@ class ResPartner(models.Model): action["domain"] = [("partner_id", "in", all_child.ids)] return action - def _credit_debit_get(self): - super()._credit_debit_get() + def _compute_credit_to_invoice(self): + # EXTENDS 'account' + super()._compute_credit_to_invoice() domain = [('partner_id', 'in', self.ids), ('state', '=', 'sale')] group = self.env['sale.order']._read_group(domain, ['partner_id'], ['amount_to_invoice:sum']) for partner, amount_to_invoice_sum in group: - partner.credit += amount_to_invoice_sum + partner.credit_to_invoice += amount_to_invoice_sum + def unlink(self): # Unlink draft/cancelled SO so that the partner can be removed from database diff --git a/addons/sale/models/sale_order.py b/addons/sale/models/sale_order.py index 887d1a0e984..271035cf813 100644 --- a/addons/sale/models/sale_order.py +++ b/addons/sale/models/sale_order.py @@ -632,9 +632,10 @@ class SaleOrder(models.Model): show_warning = order.state in ('draft', 'sent') and \ order.company_id.account_use_credit_limit if show_warning: - updated_credit = order.partner_id.commercial_partner_id.credit + (order.amount_total * order.currency_rate) order.partner_credit_warning = self.env['account.move']._build_credit_warning_message( - order, updated_credit, order.amount_total > 0.0) + order, + current_amount=(order.amount_total * order.currency_rate), + ) @api.depends('order_line.tax_id', 'order_line.price_unit', 'amount_total', 'amount_untaxed', 'currency_id') def _compute_tax_totals(self): diff --git a/addons/sale/tests/test_sale_order_down_payment.py b/addons/sale/tests/test_sale_order_down_payment.py index e5a4c2c1a8a..fb0c6f62119 100644 --- a/addons/sale/tests/test_sale_order_down_payment.py +++ b/addons/sale/tests/test_sale_order_down_payment.py @@ -432,13 +432,15 @@ class TestSaleOrderDownPayment(TestSaleCommon): })] }) - # Check that partner_a's credit is 0.0. + # Check that partner_a's credit and credit_to_invoice is 0.0. self.assertEqual(self.partner_a.credit, 0.0) + self.assertEqual(self.partner_a.credit_to_invoice, 0.0) - # Make sure partner_a's credit includes the newly confirmed SO. + # Make sure partner_a's credit_to_invoice includes the newly confirmed SO. sale_order.action_confirm() - self.partner_a.invalidate_recordset(['credit']) - self.assertEqual(self.partner_a.credit, 1000.0) + self.partner_a.invalidate_recordset(['credit', 'credit_to_invoice']) + self.assertEqual(self.partner_a.credit, 0.0) + self.assertEqual(self.partner_a.credit_to_invoice, 1000.0) # Create a 50% down payment invoice. self.env['sale.advance.payment.inv'].with_context({ @@ -465,7 +467,7 @@ class TestSaleOrderDownPayment(TestSaleCommon): invoice.invoice_line_ids.quantity = 3 self.assertEqual( invoice.partner_credit_warning, - "partner_a has reached its Credit Limit of: $\xa01,000.00\n" + "partner_a has reached its credit limit of: $\xa01,000.00\n" "Total amount due (including this document): $\xa01,500.00" )