mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
MIG account_payment_disperse to 12.0
Significant changes to the built in payment methods, and also a UI/ORM bug.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
'name': 'Payment Disperse',
|
'name': 'Payment Disperse',
|
||||||
'version': '11.0.1.0.0',
|
'version': '12.0.1.0.0',
|
||||||
'author': 'Hibou Corp. <hello@hibou.io>',
|
'author': 'Hibou Corp. <hello@hibou.io>',
|
||||||
'category': 'Accounting',
|
'category': 'Accounting',
|
||||||
'summary': 'Pay multiple invoices with one Payment',
|
'summary': 'Pay multiple invoices with one Payment',
|
||||||
|
|||||||
@@ -18,50 +18,51 @@ class AccountPayment(models.Model):
|
|||||||
return super(AccountPayment, self)._create_payment_entry(amount)
|
return super(AccountPayment, self)._create_payment_entry(amount)
|
||||||
|
|
||||||
def _create_payment_entry_manual_disperse(self, amount, wizard):
|
def _create_payment_entry_manual_disperse(self, amount, wizard):
|
||||||
|
# When registering payments for multiple partners at the same time, without setting
|
||||||
|
# the amount again, then the payment will not match the accounting.
|
||||||
self.amount = abs(amount)
|
self.amount = abs(amount)
|
||||||
if hasattr(self, 'check_amount_in_words'):
|
if hasattr(self, 'check_amount_in_words'):
|
||||||
self.check_amount_in_words = self.currency_id.amount_to_text(self.amount)
|
self.check_amount_in_words = self.currency_id.amount_to_text(self.amount)
|
||||||
|
|
||||||
aml_obj = self.env['account.move.line'].with_context(check_move_validity=False)
|
aml_obj = self.env['account.move.line'].with_context(check_move_validity=False)
|
||||||
invoice_currency = False
|
debit, credit, amount_currency, currency_id = aml_obj.with_context(date=self.payment_date)._compute_amount_fields(amount, self.currency_id, self.company_id.currency_id)
|
||||||
if self.invoice_ids and all([x.currency_id == self.invoice_ids[0].currency_id for x in self.invoice_ids]):
|
|
||||||
# if all the invoices selected share the same currency, record the paiement in that currency too
|
|
||||||
invoice_currency = self.invoice_ids[0].currency_id
|
|
||||||
debit, credit, amount_currency, currency_id = aml_obj.with_context(date=self.payment_date)\
|
|
||||||
.compute_amount_fields(amount, self.currency_id, self.company_id.currency_id, invoice_currency)
|
|
||||||
|
|
||||||
move = self.env['account.move'].create(self._get_move_vals())
|
move = self.env['account.move'].create(self._get_move_vals())
|
||||||
|
|
||||||
inv_lines = []
|
inv_lines = []
|
||||||
for partial_invoice in wizard.invoice_line_ids.filtered(lambda p: p.amount and p.partner_id == self.partner_id):
|
for partial_invoice in wizard.invoice_line_ids.filtered(lambda p: p.amount and p.partner_id == self.partner_id):
|
||||||
|
# Note that for customer payments, the amount will be reversed.
|
||||||
inv_amount = partial_invoice.amount if amount > 0 else -partial_invoice.amount
|
inv_amount = partial_invoice.amount if amount > 0 else -partial_invoice.amount
|
||||||
i_debit, i_credit, i_amount_currency, i_currency_id = aml_obj.with_context(
|
i_debit, i_credit, i_amount_currency, i_currency_id = aml_obj.with_context(date=self.payment_date)._compute_amount_fields(inv_amount, self.currency_id, self.company_id.currency_id)
|
||||||
date=self.payment_date).compute_amount_fields(inv_amount, self.currency_id, self.company_id.currency_id,
|
|
||||||
invoice_currency)
|
|
||||||
counterpart_aml_dict = self._get_shared_move_line_vals(i_debit, i_credit, i_amount_currency, move.id, False)
|
counterpart_aml_dict = self._get_shared_move_line_vals(i_debit, i_credit, i_amount_currency, move.id, False)
|
||||||
counterpart_aml_dict.update(self._get_counterpart_move_line_vals(partial_invoice.invoice_id))
|
counterpart_aml_dict.update(self._get_counterpart_move_line_vals(partial_invoice.invoice_id))
|
||||||
counterpart_aml_dict.update({'currency_id': currency_id})
|
counterpart_aml_dict.update({'currency_id': currency_id})
|
||||||
counterpart_aml = aml_obj.create(counterpart_aml_dict)
|
counterpart_aml = aml_obj.create(counterpart_aml_dict)
|
||||||
# capture writeoff account etc.
|
|
||||||
counterpart_aml |= partial_invoice.invoice_id.move_id.line_ids.filtered(
|
counterpart_aml |= partial_invoice.invoice_id.move_id.line_ids.filtered(
|
||||||
lambda r: not r.reconciled and r.account_id.internal_type in ('payable', 'receivable'))
|
lambda r: not r.reconciled and r.account_id.internal_type in ('payable', 'receivable'))
|
||||||
inv_lines.append((counterpart_aml, partial_invoice.writeoff_acc_id))
|
inv_lines.append((counterpart_aml, partial_invoice.writeoff_acc_id))
|
||||||
|
|
||||||
# Create Payment side (payment journal default accounts)
|
# Useful for debugging
|
||||||
|
# for aml_ids, writeoff_acc_id in inv_lines:
|
||||||
|
# _logger.warn('pair:' + (' writeoff: ' + str(writeoff_acc_id)) if writeoff_acc_id else '')
|
||||||
|
# for l in aml_ids:
|
||||||
|
# _logger.warn(' ' + str(l) + ' debit: ' + str(l.debit) + ' credit: ' + str(l.credit))
|
||||||
|
|
||||||
|
# Write counterpart lines
|
||||||
if not self.currency_id.is_zero(self.amount):
|
if not self.currency_id.is_zero(self.amount):
|
||||||
if not self.currency_id != self.company_id.currency_id:
|
if not self.currency_id != self.company_id.currency_id:
|
||||||
amount_currency = 0
|
amount_currency = 0
|
||||||
liquidity_aml_dict = self._get_shared_move_line_vals(credit, debit, -amount_currency, move.id, False)
|
liquidity_aml_dict = self._get_shared_move_line_vals(credit, debit, -amount_currency, move.id, False)
|
||||||
liquidity_aml_dict.update(self._get_liquidity_move_line_vals(-amount))
|
liquidity_aml_dict.update(self._get_liquidity_move_line_vals(-amount))
|
||||||
aml_obj.create(liquidity_aml_dict)
|
other = aml_obj.create(liquidity_aml_dict)
|
||||||
|
#_logger.warn('other line -- debit: ' + str(other.debit) + ' credit: ' + str(other.credit))
|
||||||
|
|
||||||
# validate the payment
|
# validate the payment
|
||||||
move.post()
|
if not self.journal_id.post_at_bank_rec:
|
||||||
|
move.post()
|
||||||
|
|
||||||
# reconcile the invoice receivable/payable line(s) with the payment
|
# reconcile the invoice receivable/payable line(s) with the payment
|
||||||
for inv_lines, writeoff_acc_id in inv_lines:
|
for aml_ids, writeoff_acc_id in inv_lines:
|
||||||
# _logger.warn('pair: ')
|
aml_ids.reconcile(writeoff_acc_id, wizard.writeoff_journal_id)
|
||||||
# for l in inv_lines:
|
|
||||||
# _logger.warn(' ' + str(l) + ' credit: ' + str(l.credit) + ' debit: ' + str(l.debit))
|
|
||||||
inv_lines.reconcile(writeoff_acc_id, wizard.writeoff_journal_id)
|
|
||||||
|
|
||||||
return move
|
return move
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ class PaymentMultiTest(TestPayment):
|
|||||||
|
|
||||||
payment_ids = self.payment_model.search([('invoice_ids', 'in', ids)], order="id desc")
|
payment_ids = self.payment_model.search([('invoice_ids', 'in', ids)], order="id desc")
|
||||||
self.assertEqual(len(payment_ids), 2, 'Need two payments.')
|
self.assertEqual(len(payment_ids), 2, 'Need two payments.')
|
||||||
|
# Useful for logging amounts of payments and their accounting
|
||||||
# for pay in payment_ids:
|
# for pay in payment_ids:
|
||||||
# _logger.warn(str(pay) + ' amount: ' + str(pay.amount))
|
# _logger.warn(str(pay) + ' amount: ' + str(pay.amount))
|
||||||
# for line in pay.move_line_ids:
|
# for line in pay.move_line_ids:
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ class AccountRegisterPayments(models.TransientModel):
|
|||||||
@api.model
|
@api.model
|
||||||
def default_get(self, fields):
|
def default_get(self, fields):
|
||||||
rec = super(AccountRegisterPayments, self).default_get(fields)
|
rec = super(AccountRegisterPayments, self).default_get(fields)
|
||||||
invoice_ids = rec['invoice_ids'][0][2]
|
if 'invoice_ids' in rec:
|
||||||
rec['invoice_line_ids'] = [(0, 0, {'invoice_id': i, 'amount': 0.0}) for i in invoice_ids]
|
invoice_ids = rec['invoice_ids'][0][2]
|
||||||
|
rec['invoice_line_ids'] = [(0, 0, {'invoice_id': i, 'amount': 0.0}) for i in invoice_ids]
|
||||||
return rec
|
return rec
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
@@ -63,12 +64,15 @@ class AccountRegisterPaymentsInvoiceLine(models.TransientModel):
|
|||||||
@api.depends('invoice_id', 'wizard_id.due_date_cutoff', 'invoice_id.partner_id')
|
@api.depends('invoice_id', 'wizard_id.due_date_cutoff', 'invoice_id.partner_id')
|
||||||
def _compute_balances(self):
|
def _compute_balances(self):
|
||||||
for line in self:
|
for line in self:
|
||||||
residual = line.invoice_id.residual
|
# Bug in the ORM 12.0? The invoice is set, but there is no residual
|
||||||
|
# on anything other than the first invoice/line processed.
|
||||||
|
invoice = line.invoice_id.browse(line.invoice_id.id)
|
||||||
|
residual = invoice.residual
|
||||||
|
|
||||||
cutoff_date = line.wizard_id.due_date_cutoff
|
cutoff_date = line.wizard_id.due_date_cutoff
|
||||||
total_amount = 0.0
|
total_amount = 0.0
|
||||||
total_reconciled = 0.0
|
total_reconciled = 0.0
|
||||||
for move_line in line.invoice_id.move_id.line_ids.filtered(lambda r: (
|
for move_line in invoice.move_id.line_ids.filtered(lambda r: (
|
||||||
not r.reconciled
|
not r.reconciled
|
||||||
and r.account_id.internal_type in ('payable', 'receivable')
|
and r.account_id.internal_type in ('payable', 'receivable')
|
||||||
and r.date_maturity <= cutoff_date
|
and r.date_maturity <= cutoff_date
|
||||||
@@ -79,11 +83,13 @@ class AccountRegisterPaymentsInvoiceLine(models.TransientModel):
|
|||||||
total_reconciled += partial_line.amount
|
total_reconciled += partial_line.amount
|
||||||
for partial_line in move_line.matched_credit_ids:
|
for partial_line in move_line.matched_credit_ids:
|
||||||
total_reconciled += partial_line.amount
|
total_reconciled += partial_line.amount
|
||||||
|
values = {
|
||||||
line.residual = residual
|
'residual': residual,
|
||||||
line.residual_due = total_amount - total_reconciled
|
'residual_due': total_amount - total_reconciled,
|
||||||
line.difference = residual - (line.amount or 0.0)
|
'difference': residual - (line.amount or 0.0),
|
||||||
line.partner_id = line.invoice_id.partner_id
|
'partner_id': invoice.partner_id.id,
|
||||||
|
}
|
||||||
|
line.update(values)
|
||||||
|
|
||||||
@api.onchange('amount')
|
@api.onchange('amount')
|
||||||
def _onchange_amount(self):
|
def _onchange_amount(self):
|
||||||
|
|||||||
@@ -8,9 +8,12 @@
|
|||||||
<xpath expr="//field[@name='amount']" position="attributes">
|
<xpath expr="//field[@name='amount']" position="attributes">
|
||||||
<attribute name="attrs">{'readonly': [('multi', '=', True), ('is_manual_disperse', '!=', True)]}</attribute>
|
<attribute name="attrs">{'readonly': [('multi', '=', True), ('is_manual_disperse', '!=', True)]}</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='amount']" position="after">
|
<xpath expr="//field[@name='payment_method_code']" position="after">
|
||||||
<field name="is_manual_disperse"/>
|
<field name="is_manual_disperse"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//group[3]" position="attributes">
|
||||||
|
<attribute name="attrs">{'invisible': ['|', ('payment_difference', '=', 0.0), ('is_manual_disperse', '=', True)]}</attribute>
|
||||||
|
</xpath>
|
||||||
<xpath expr="//form/group[1]" position="after">
|
<xpath expr="//form/group[1]" position="after">
|
||||||
<group name="invoice_lines" attrs="{'invisible': [('is_manual_disperse', '=', False)]}">
|
<group name="invoice_lines" attrs="{'invisible': [('is_manual_disperse', '=', False)]}">
|
||||||
<group>
|
<group>
|
||||||
|
|||||||
Reference in New Issue
Block a user