# Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import _, api, fields, models from odoo.exceptions import ValidationError class PaymentRefundWizard(models.TransientModel): _name = 'payment.refund.wizard' _description = "Payment Refund Wizard" payment_id = fields.Many2one( string="Payment", comodel_name='account.payment', readonly=True, default=lambda self: self.env.context.get('active_id'), ) transaction_id = fields.Many2one( string="Payment Transaction", related='payment_id.payment_transaction_id' ) payment_amount = fields.Monetary(string="Payment Amount", related='payment_id.amount') refunded_amount = fields.Monetary(string="Refunded Amount", compute='_compute_refunded_amount') amount_available_for_refund = fields.Monetary( string="Maximum Refund Allowed", related='payment_id.amount_available_for_refund' ) amount_to_refund = fields.Monetary( string="Refund Amount", compute='_compute_amount_to_refund', store=True, readonly=False ) currency_id = fields.Many2one(string="Currency", related='transaction_id.currency_id') support_refund = fields.Selection( string="Type of Refund Supported", selection=[('full_only', "Full Only"), ('partial', "Partial")], compute='_compute_support_refund', ) has_pending_refund = fields.Boolean( string="Has a pending refund", compute='_compute_has_pending_refund' ) @api.constrains('amount_to_refund') def _check_amount_to_refund_within_boundaries(self): for wizard in self: if not 0 < wizard.amount_to_refund <= wizard.amount_available_for_refund: raise ValidationError(_( "The amount to be refunded must be positive and cannot be superior to %s.", wizard.amount_available_for_refund )) @api.depends('amount_available_for_refund') def _compute_refunded_amount(self): for wizard in self: wizard.refunded_amount = wizard.payment_amount - wizard.amount_available_for_refund @api.depends('amount_available_for_refund') def _compute_amount_to_refund(self): """ Set the default amount to refund to the amount available for refund. """ for wizard in self: wizard.amount_to_refund = wizard.amount_available_for_refund @api.depends('transaction_id.provider_id', 'transaction_id.payment_method_id') def _compute_support_refund(self): for wizard in self: p_support_refund = wizard.transaction_id.provider_id.support_refund pm_support_refund = wizard.transaction_id.payment_method_id.support_refund if not p_support_refund or not pm_support_refund: wizard.support_refund = False elif p_support_refund == 'full_only' or pm_support_refund == 'full_only': wizard.support_refund = 'full_only' else: # Both support partial refunds. wizard.support_refund = 'partial' @api.depends('payment_id') # To always trigger the compute def _compute_has_pending_refund(self): for wizard in self: pending_refunds_count = self.env['payment.transaction'].search_count([ ('source_transaction_id', '=', wizard.payment_id.payment_transaction_id.id), ('operation', '=', 'refund'), ('state', 'in', ['draft', 'pending', 'authorized']), ]) wizard.has_pending_refund = pending_refunds_count > 0 def action_refund(self): for wizard in self: wizard.transaction_id.action_refund(amount_to_refund=wizard.amount_to_refund)