forked from Mapan/odoo17e
90 lines
3.4 KiB
Python
90 lines
3.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class AccountMove(models.Model):
|
|
_inherit = 'account.move'
|
|
|
|
bacs_ddi_id = fields.Many2one(
|
|
comodel_name='bacs.ddi',
|
|
copy=False,
|
|
help="Once this invoice has been paid with BACS Direct Debit, contains the DDI that allowed the payment.")
|
|
bacs_has_usable_ddi = fields.Boolean(compute='_compute_bacs_has_usable_ddi', search='_search_bacs_has_usable_ddi')
|
|
|
|
def _post(self, soft=True):
|
|
# OVERRIDE
|
|
# Register BACS Direct Debit payments on DDIs or trigger an error if no DDI is available.
|
|
for pay in self.payment_id.filtered(lambda p: p.payment_method_code == 'bacs_dd'):
|
|
usable_ddi = pay.get_usable_ddi()
|
|
if not usable_ddi:
|
|
raise UserError(_(
|
|
"Unable to post payment %(payment)r due to no usable DDI being available at date %(date)s for partner %(partner)r. Please create one before encoding a BACS Direct Debit payment.",
|
|
payment=pay.name,
|
|
date=pay.date,
|
|
partner=pay.partner_id.name,
|
|
))
|
|
pay.bacs_ddi_id = usable_ddi
|
|
|
|
return super()._post(soft)
|
|
|
|
@api.model
|
|
def _search_bacs_has_usable_ddi(self, operator, value):
|
|
if (operator == '=' and value) or (operator == '!=' and not value):
|
|
domain_operator = 'in'
|
|
else:
|
|
domain_operator = 'not in'
|
|
|
|
query = '''
|
|
SELECT
|
|
move.id
|
|
FROM
|
|
bacs_ddi ddi
|
|
LEFT JOIN
|
|
account_move move ON move.company_id = ddi.company_id AND
|
|
move.commercial_partner_id = ddi.partner_id
|
|
WHERE
|
|
move.move_type IN ('out_invoice', 'in_refund') AND
|
|
ddi.state NOT IN ('draft', 'revoked') AND
|
|
ddi.start_date <= move.invoice_date
|
|
'''
|
|
|
|
self._cr.execute(query)
|
|
|
|
return [('id', domain_operator, [x['id'] for x in self._cr.dictfetchall()])]
|
|
|
|
@api.depends('company_id', 'commercial_partner_id', 'invoice_date')
|
|
def _compute_bacs_has_usable_ddi(self):
|
|
for rec in self:
|
|
rec.bacs_has_usable_ddi = bool(rec._bacs_get_usable_ddi())
|
|
|
|
def _bacs_get_usable_ddi(self):
|
|
""" returns the first DDI found that can be used to pay this invoice,
|
|
or none if there is no such DDI.
|
|
"""
|
|
if self.move_type in ('out_invoice', 'in_refund'):
|
|
return self.env['bacs.ddi']._bacs_get_usable_ddi(self.company_id.id, self.commercial_partner_id.id, self.invoice_date)
|
|
else:
|
|
return None
|
|
|
|
|
|
class AccountMoveLine(models.Model):
|
|
_inherit = 'account.move.line'
|
|
|
|
def reconcile(self):
|
|
"""
|
|
Override of account move line Post-hook method for the reconciliation process.
|
|
If the current account move line is linked to a payment that is associated with
|
|
a BACS DDI, it retrieves the reconciled invoices related to the payment's move
|
|
and assigns the BACS DDI to those invoices that do not have the same BACS DDI as the payment.
|
|
"""
|
|
res = super().reconcile()
|
|
|
|
for pay in self.payment_id:
|
|
if pay.bacs_ddi_id:
|
|
pay.move_id._get_reconciled_invoices().filtered(lambda m: m.bacs_ddi_id != pay.bacs_ddi_id).bacs_ddi_id = pay.bacs_ddi_id
|
|
|
|
return res
|