[FIX] account,sale: split partner credit from sales and invoices

Since 7bd93cc64b, we add the amounts to
invoice from sales order to the credit limit warning. When looking at
the credit amount on a partner from an accounting perspective, it is
not correct though that sales orders to invoice are considered as well.

In this change we split the credit amount from invoices and from sales
orders to invoice. On the partner we only show the credit amount from
invoices. In other places we add both.

task-3375260

closes odoo/odoo#128158

X-original-commit: 94eae9b73995dbf2175ecee65548ace5a382f5f8
Signed-off-by: John Laterre (jol) <jol@odoo.com>
Signed-off-by: Dylan Kiss (dyki) <dyki@odoo.com>
This commit is contained in:
Dylan Kiss (dyki)
2023-07-13 02:21:50 +02:00
parent 0be5070983
commit 75c6917b4e
6 changed files with 99 additions and 33 deletions
+39 -11
View File
@@ -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 "%<span class=\"px-3\"/>("
@@ -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."
+36 -12
View File
@@ -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):
+9
View File
@@ -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',
+5 -3
View File
@@ -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
+3 -2
View File
@@ -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):
@@ -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"
)