# 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' poynt_refunded = fields.Boolean( string="Refunded via Poynt", readonly=True, copy=False, default=False, ) poynt_refund_count = fields.Integer( string="Poynt Refund Count", compute='_compute_poynt_refund_count', ) has_poynt_receipt = fields.Boolean( string="Has Poynt Receipt", compute='_compute_has_poynt_receipt', ) @api.depends('reversal_move_ids') def _compute_poynt_refund_count(self): for move in self: if move.move_type == 'out_invoice': move.poynt_refund_count = len(move.reversal_move_ids.filtered( lambda r: r.poynt_refunded )) else: move.poynt_refund_count = 0 def _compute_has_poynt_receipt(self): for move in self: move.has_poynt_receipt = bool(move._get_poynt_transaction_for_receipt()) def action_view_poynt_refunds(self): """Open the credit notes linked to this invoice that were refunded via Poynt.""" self.ensure_one() refund_moves = self.reversal_move_ids.filtered(lambda r: r.poynt_refunded) action = { 'name': _("Poynt 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_poynt_transaction_for_receipt(self): """Find the Poynt transaction linked to this invoice or credit note.""" self.ensure_one() domain = [ ('provider_id.code', '=', 'poynt'), ('poynt_transaction_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_poynt_receipt(self): """Resend the Poynt payment/refund receipt email to the customer.""" self.ensure_one() tx = self._get_poynt_transaction_for_receipt() if not tx: raise UserError(_( "No completed Poynt transaction found for this document." )) template = self.env.ref( 'fusion_poynt.mail_template_poynt_receipt', raise_if_not_found=False, ) if not template: raise UserError(_("Receipt email template not found.")) report = self.env.ref( 'fusion_poynt.action_report_poynt_receipt', raise_if_not_found=False, ) attachment_ids = [] if report: pdf_content, _content_type = report.sudo()._render_qweb_pdf( report_ref='fusion_poynt.action_report_poynt_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_poynt_payment_wizard(self): """Open the Poynt payment collection wizard for this invoice.""" self.ensure_one() return { 'name': _("Collect Poynt Payment"), 'type': 'ir.actions.act_window', 'res_model': 'poynt.payment.wizard', 'view_mode': 'form', 'target': 'new', 'context': { 'active_model': 'account.move', 'active_id': self.id, }, } def action_open_poynt_refund_wizard(self): """Open the Poynt refund wizard for this credit note.""" self.ensure_one() return { 'name': _("Refund via Poynt"), 'type': 'ir.actions.act_window', 'res_model': 'poynt.refund.wizard', 'view_mode': 'form', 'target': 'new', 'context': { 'active_model': 'account.move', 'active_id': self.id, }, } def _get_original_poynt_transaction(self): """Find the Poynt payment transaction from the reversed invoice. For credit notes created via the "Reverse" action, the ``reversed_entry_id`` links back to the original invoice. We look for a confirmed Poynt transaction on that invoice. """ self.ensure_one() origin_invoice = self.reversed_entry_id if not origin_invoice: return self.env['payment.transaction'] tx = self.env['payment.transaction'].sudo().search([ ('invoice_ids', 'in', origin_invoice.ids), ('state', '=', 'done'), ('provider_id.code', '=', 'poynt'), ('poynt_transaction_id', '!=', False), ('poynt_voided', '=', False), ], order='id desc', limit=1) if not tx: tx = self.env['payment.transaction'].sudo().search([ ('invoice_ids', 'in', origin_invoice.ids), ('state', 'in', ('done', 'cancel')), ('provider_id.code', '=', 'poynt'), ('poynt_transaction_id', '!=', False), ], order='id desc', limit=1) return tx