[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:
@@ -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."
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user