# Part of Odoo. See LICENSE file for full copyright and licensing details. import base64 from odoo import _, api, fields, models from odoo.exceptions import UserError class AccountMove(models.Model): _inherit = 'account.move' clover_refunded = fields.Boolean( string="Refunded via Clover", readonly=True, copy=False, default=False, ) clover_refund_count = fields.Integer( string="Clover Refund Count", compute='_compute_clover_refund_count', ) has_clover_receipt = fields.Boolean( string="Has Clover Receipt", compute='_compute_has_clover_receipt', ) clover_provider_enabled = fields.Boolean( string="Clover Provider Enabled", compute='_compute_clover_provider_enabled', ) @api.depends('reversal_move_ids') def _compute_clover_refund_count(self): for move in self: if move.move_type == 'out_invoice': move.clover_refund_count = len(move.reversal_move_ids.filtered( lambda r: r.clover_refunded )) else: move.clover_refund_count = 0 def _compute_has_clover_receipt(self): for move in self: move.has_clover_receipt = bool(move._get_clover_transaction_for_receipt()) def _compute_clover_provider_enabled(self): provider = self.env['payment.provider'].sudo().search([ ('code', '=', 'clover'), ('state', 'in', ('enabled', 'test')), ], limit=1) enabled = bool(provider) for move in self: move.clover_provider_enabled = enabled def action_view_clover_refunds(self): """Open the credit notes linked to this invoice that were refunded via Clover.""" self.ensure_one() refund_moves = self.reversal_move_ids.filtered(lambda r: r.clover_refunded) action = { 'name': _("Clover Refunds"), 'type': 'ir.actions.act_window', 'res_model': 'account.move', 'view_mode': 'list,form', 'domain': [('id', 'in', refund_moves.ids)], 'context': {'default_move_type': 'out_refund'}, } if len(refund_moves) == 1: action['view_mode'] = 'form' action['res_id'] = refund_moves.id return action def _get_clover_transaction_for_receipt(self): """Find the Clover transaction linked to this invoice or credit note.""" self.ensure_one() domain = [ ('provider_id.code', '=', 'clover'), ('clover_charge_id', '!=', False), ('state', '=', 'done'), ] if self.move_type == 'out_invoice': domain.append(('invoice_ids', 'in', self.ids)) elif self.move_type == 'out_refund': domain += [ ('operation', '=', 'refund'), ('invoice_ids', 'in', self.ids), ] else: return self.env['payment.transaction'] return self.env['payment.transaction'].sudo().search( domain, order='id desc', limit=1, ) def action_resend_clover_receipt(self): """Resend the Clover payment/refund receipt email to the customer.""" self.ensure_one() tx = self._get_clover_transaction_for_receipt() if not tx: raise UserError(_( "No completed Clover transaction found for this document." )) template = self.env.ref( 'fusion_clover.mail_template_clover_receipt', raise_if_not_found=False, ) if not template: raise UserError(_("Receipt email template not found.")) report = self.env.ref( 'fusion_clover.action_report_clover_receipt', raise_if_not_found=False, ) attachment_ids = [] if report: pdf_content, _content_type = report.sudo()._render_qweb_pdf( report_ref='fusion_clover.action_report_clover_receipt', res_ids=tx.ids, ) prefix = "Refund_Receipt" if self.move_type == 'out_refund' else "Payment_Receipt" filename = f"{prefix}_{tx.reference}.pdf" att = self.env['ir.attachment'].create({ 'name': filename, 'type': 'binary', 'datas': base64.b64encode(pdf_content), 'res_model': self._name, 'res_id': self.id, 'mimetype': 'application/pdf', }) attachment_ids = [att.id] template.send_mail(tx.id, force_send=True) is_refund = self.move_type == 'out_refund' label = _("Refund") if is_refund else _("Payment") self.message_post( body=_( "%(label)s receipt resent to %(email)s.", label=label, email=tx.partner_id.email, ), message_type='notification', subtype_xmlid='mail.mt_note', attachment_ids=attachment_ids, ) return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': _("Receipt Sent"), 'message': _("The receipt has been sent to %s.", tx.partner_id.email), 'type': 'success', 'sticky': False, }, } def action_open_clover_payment_wizard(self): """Open the Clover payment collection wizard for this invoice.""" self.ensure_one() return { 'name': _("Collect Clover Payment"), 'type': 'ir.actions.act_window', 'res_model': 'clover.payment.wizard', 'view_mode': 'form', 'target': 'new', 'context': { 'active_model': 'account.move', 'active_id': self.id, }, } def action_open_clover_refund_wizard(self): """Open the Clover refund wizard for this credit note.""" self.ensure_one() return { 'name': _("Refund via Clover"), 'type': 'ir.actions.act_window', 'res_model': 'clover.refund.wizard', 'view_mode': 'form', 'target': 'new', 'context': { 'active_model': 'account.move', 'active_id': self.id, }, } def _get_original_clover_transaction(self): """Find the Clover payment transaction from the reversed invoice.""" self.ensure_one() origin_invoice = self.reversed_entry_id if not origin_invoice: return self.env['payment.transaction'] return self.env['payment.transaction'].sudo().search([ ('invoice_ids', 'in', origin_invoice.ids), ('state', '=', 'done'), ('provider_id.code', '=', 'clover'), ('clover_charge_id', '!=', False), ], order='id desc', limit=1)