diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
index f4b855b4aad..8b769016a90 100644
--- a/addons/account/account_invoice.py
+++ b/addons/account/account_invoice.py
@@ -520,12 +520,10 @@ class AccountInvoice(models.Model):
tax_grouped[key]['amount'] += val['amount']
return tax_grouped
- @api.multi
+ @api.one
def register_payment(self, payment_line, writeoff_acc_id=False, writeoff_journal_id=False):
""" Reconcile payable/receivable lines from the invoice with payment_line """
- line_to_reconcile = self.env['account.move.line']
- for inv in self:
- line_to_reconcile += inv.move_id.line_ids.filtered(lambda r: not r.reconciled and r.account_id.internal_type in ('payable', 'receivable'))
+ line_to_reconcile = self.move_id.line_ids.filtered(lambda r: not r.reconciled and r.account_id.internal_type in ('payable', 'receivable'))
return (line_to_reconcile + payment_line).reconcile(writeoff_acc_id, writeoff_journal_id)
@api.v7
diff --git a/addons/account/account_move.py b/addons/account/account_move.py
index acb682e88bf..61a8bffd3cd 100644
--- a/addons/account/account_move.py
+++ b/addons/account/account_move.py
@@ -695,17 +695,14 @@ class AccountMoveLine(models.Model):
def _get_pair_to_reconcile(self):
#field is either 'amount_residual' or 'amount_residual_currency' (if the reconciled account has a secondary currency set)
field = self[0].account_id.currency_id and 'amount_residual_currency' or 'amount_residual'
- #target the pair of move in self that are the oldest
- sorted_moves = sorted(self, key=lambda a: a.date)
- debit = credit = False
- for aml in sorted_moves:
- if credit != False and credit != False:
- break
- if aml[field] > 0 and debit == False:
- debit = aml
- elif aml[field] < 0 and credit == False:
- credit = aml
- return debit, credit
+ #target the pair of move in self with smallest debit, credit
+ smallest_debit = smallest_credit = False
+ for aml in self:
+ if aml[field] > 0:
+ smallest_debit = (not smallest_debit or aml[field] < smallest_debit[field]) and aml or smallest_debit
+ elif aml[field] < 0:
+ smallest_credit = (not smallest_credit or aml[field] > smallest_credit[field]) and aml or smallest_credit
+ return smallest_debit, smallest_credit
def auto_reconcile_lines(self):
""" This function iterates recursively on the recordset given as parameter as long as it
diff --git a/addons/account/account_payment.py b/addons/account/account_payment.py
index 70d38d6978b..bd0fc240653 100644
--- a/addons/account/account_payment.py
+++ b/addons/account/account_payment.py
@@ -146,7 +146,7 @@ class account_register_payments(models.TransientModel):
'communication': self.communication,
'invoice_ids': [(4, inv.id, None) for inv in self._get_invoices()],
'payment_type': self.payment_type,
- 'amount': self.amount,
+ 'amount': self._compute_total_invoices_amount(),
'currency_id': self.currency_id.id,
'partner_id': self.partner_id.id,
'partner_type': self.partner_type,
@@ -175,7 +175,11 @@ class account_payment(models.Model):
def _compute_payment_difference(self):
if len(self.invoice_ids) == 0:
return
- self.payment_difference = self._compute_total_invoices_amount() - self.amount
+ # A payment on multiple invoices must pay them entirely (and amount be readonly of course)
+ if len(self.invoice_ids) != 1:
+ self.payment_difference = 0
+ else:
+ self.payment_difference = self._compute_total_invoices_amount() - self.amount
company_id = fields.Many2one(store=True)
@@ -310,7 +314,7 @@ class account_payment(models.Model):
@api.multi
def unlink(self):
if any(rec.state != 'draft' for rec in self):
- raise UserError(_("You can not delete a payment that is already posted"))
+ raise UserError(_("In order to delete a payment, it must first be canceled."))
return super(account_payment, self).unlink()
@api.multi
@@ -363,24 +367,42 @@ class account_payment(models.Model):
Return the journal entry.
"""
aml_obj = self.env['account.move.line'].with_context(check_move_validity=False)
- debit, credit, amount_currency = aml_obj.with_context(date=self.payment_date).compute_amount_fields(amount, self.currency_id, self.company_id.currency_id)
+ invoice_id = len(self.invoice_ids) == 1 and self.invoice_ids[0] or False
+ total_debit, total_credit, total_amount_currency = aml_obj.with_context(date=self.payment_date).compute_amount_fields(amount, self.currency_id, self.company_id.currency_id)
move = self.env['account.move'].create(self._get_move_vals())
- #Write line corresponding to invoice payment
- counterpart_aml_dict = self._get_shared_move_line_vals(debit, credit, amount_currency, move.id, False)
- counterpart_aml_dict.update(self._get_counterpart_move_line_vals(self.invoice_ids))
- counterpart_aml_dict.update({'currency_id': self.currency_id != self.company_id.currency_id and self.currency_id.id or False})
- counterpart_aml = aml_obj.create(counterpart_aml_dict)
-
- #Reconcile with the invoices
- if self.payment_difference_handling == 'reconcile':
- self.invoice_ids.register_payment(counterpart_aml, self.writeoff_account, self.journal_id)
+ if len(self.invoice_ids) > 1:
+ total_amount = 0
+ for invoice_id in self.invoice_ids:
+ # Create a reconciliable journal item corresponding to the invoice
+ inv_amount = -invoice_id.residual * MAP_INVOICE_TYPE_PAYMENT_SIGN[invoice_id.type]
+ debit = inv_amount > 0 and inv_amount or 0
+ credit = inv_amount < 0 and -inv_amount or 0
+ amount_currency = self.currency_id != self.company_id.currency_id and self.company_id.currency_id.with_context(date=self.payment_date).compute(inv_amount, self.currency_id) or 0
+ # Avoid unbalanced journal entry due to rounding error
+ total_amount = total_amount + debit - credit
+ counterpart_aml_dict = self._get_shared_move_line_vals(debit, credit, amount_currency, move.id, invoice_id)
+ counterpart_aml_dict.update(self._get_counterpart_move_line_vals(invoice_id))
+ counterpart_aml_dict.update({'currency_id': self.currency_id != self.company_id.currency_id and self.currency_id.id or False})
+ counterpart_aml = aml_obj.create(counterpart_aml_dict)
+ invoice_id.register_payment(counterpart_aml)
+ total_debit = total_amount > 0 and total_amount or 0
+ total_credit = total_amount < 0 and -total_amount or 0
else:
- self.invoice_ids.register_payment(counterpart_aml)
+ # Create reconciliable journal item
+ counterpart_aml_dict = self._get_shared_move_line_vals(total_debit, total_credit, total_amount_currency, move.id, invoice_id)
+ counterpart_aml_dict.update(self._get_counterpart_move_line_vals(invoice_id))
+ counterpart_aml = aml_obj.create(counterpart_aml_dict)
- #Write counterpart lines
- liquidity_aml_dict = self._get_shared_move_line_vals(credit, debit, -amount_currency, move.id, False)
+ # Reconcile it with the invoice if present
+ if invoice_id:
+ if self.payment_difference_handling == 'reconcile':
+ invoice_id.register_payment(counterpart_aml, self.writeoff_account, self.journal_id)
+ else:
+ invoice_id.register_payment(counterpart_aml)
+
+ liquidity_aml_dict = self._get_shared_move_line_vals(total_credit, total_debit, -total_amount_currency, move.id, invoice_id)
liquidity_aml_dict.update(self._get_liquidity_move_line_vals(-amount))
aml_obj.create(liquidity_aml_dict)
@@ -453,7 +475,7 @@ class account_payment(models.Model):
if self.payment_type == 'transfer':
name = self.name
else:
- name = ''
+ name = invoice and invoice.number + ': ' or ''
if self.partner_type == 'customer':
if self.payment_type == 'inbound':
name += _("Customer Payment")
@@ -464,11 +486,6 @@ class account_payment(models.Model):
name += _("Supplier Refund")
elif self.payment_type == 'outbound':
name += _("Supplier Payment")
- if invoice:
- name += ': '
- for inv in invoice:
- name += inv.number+', '
- name = name[:len(name)-2]
return {
'name': name,
'account_id': self.destination_account_id.id,
diff --git a/addons/account/views/account_payment_view.xml b/addons/account/views/account_payment_view.xml
index 0ff503e29fe..d15c91629c1 100644
--- a/addons/account/views/account_payment_view.xml
+++ b/addons/account/views/account_payment_view.xml
@@ -244,7 +244,7 @@
-
+