This commit changes the way transactions linked to a document (sales order, invoice...) are created in a payment flow. Rather than receiving and trusting the transaction values from the controller, they are now read from the linked document, and the payment flow is rerouted to use the document's module's controllers instead of that of `payment`. This ensures that no unexpected value can be passed to the `create` method of a transaction, and simplifies the implementation of the payment flows of linked documents. task-3136240 closes odoo/odoo#126425 Related: odoo/enterprise#43212 Related: odoo/upgrade#5124 Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
105 lines
3.9 KiB
Python
105 lines
3.9 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, fields, models
|
|
from odoo.tools import str2bool
|
|
|
|
from odoo.addons.payment import utils as payment_utils
|
|
|
|
|
|
class AccountMove(models.Model):
|
|
_inherit = 'account.move'
|
|
|
|
transaction_ids = fields.Many2many(
|
|
string="Transactions", comodel_name='payment.transaction',
|
|
relation='account_invoice_transaction_rel', column1='invoice_id', column2='transaction_id',
|
|
readonly=True, copy=False)
|
|
authorized_transaction_ids = fields.Many2many(
|
|
string="Authorized Transactions", comodel_name='payment.transaction',
|
|
compute='_compute_authorized_transaction_ids', readonly=True, copy=False,
|
|
compute_sudo=True)
|
|
amount_paid = fields.Monetary(
|
|
string="Amount paid",
|
|
compute='_compute_amount_paid'
|
|
)
|
|
|
|
@api.depends('transaction_ids')
|
|
def _compute_authorized_transaction_ids(self):
|
|
for invoice in self:
|
|
invoice.authorized_transaction_ids = invoice.transaction_ids.filtered(
|
|
lambda tx: tx.state == 'authorized'
|
|
)
|
|
|
|
@api.depends('transaction_ids')
|
|
def _compute_amount_paid(self):
|
|
""" Sum all the transaction amount for which state is in 'authorized' or 'done'
|
|
"""
|
|
for invoice in self:
|
|
invoice.amount_paid = sum(
|
|
invoice.transaction_ids.filtered(
|
|
lambda tx: tx.state in ('authorized', 'done')
|
|
).mapped('amount')
|
|
)
|
|
|
|
def _has_to_be_paid(self):
|
|
self.ensure_one()
|
|
transactions = self.transaction_ids.filtered(lambda tx: tx.state in ('authorized', 'done'))
|
|
pending_transactions = self.transaction_ids.filtered(
|
|
lambda tx: tx.state == 'pending' and tx.provider_code not in ('none', 'custom'))
|
|
enabled_feature = str2bool(
|
|
self.env['ir.config_parameter'].sudo().get_param(
|
|
'account_payment.enable_portal_payment'
|
|
)
|
|
)
|
|
return enabled_feature and bool(
|
|
(
|
|
self.amount_residual
|
|
# FIXME someplace we check amount_residual and some other amount_paid < amount_total
|
|
# what is the correct heuristic to check ?
|
|
or not (transactions or pending_transactions)
|
|
)
|
|
and self.state == 'posted'
|
|
and self.payment_state in ('not_paid', 'partial')
|
|
and self.amount_total
|
|
and self.move_type == 'out_invoice'
|
|
)
|
|
|
|
def get_portal_last_transaction(self):
|
|
self.ensure_one()
|
|
return self.with_context(active_test=False).transaction_ids.sudo()._get_last()
|
|
|
|
def payment_action_capture(self):
|
|
""" Capture all transactions linked to this invoice. """
|
|
self.ensure_one()
|
|
payment_utils.check_rights_on_recordset(self)
|
|
|
|
# In sudo mode to bypass the checks on the rights on the transactions.
|
|
return self.transaction_ids.sudo().action_capture()
|
|
|
|
def payment_action_void(self):
|
|
""" Void all transactions linked to this invoice. """
|
|
payment_utils.check_rights_on_recordset(self)
|
|
|
|
# In sudo mode to bypass the checks on the rights on the transactions.
|
|
self.authorized_transaction_ids.sudo().action_void()
|
|
|
|
def action_view_payment_transactions(self):
|
|
action = self.env['ir.actions.act_window']._for_xml_id('payment.action_payment_transaction')
|
|
|
|
if len(self.transaction_ids) == 1:
|
|
action['view_mode'] = 'form'
|
|
action['res_id'] = self.transaction_ids.id
|
|
action['views'] = []
|
|
else:
|
|
action['domain'] = [('id', 'in', self.transaction_ids.ids)]
|
|
|
|
return action
|
|
|
|
def _get_default_payment_link_values(self):
|
|
self.ensure_one()
|
|
return {
|
|
'amount': self.amount_residual,
|
|
'currency_id': self.currency_id.id,
|
|
'partner_id': self.partner_id.id,
|
|
'amount_max': self.amount_residual,
|
|
}
|