This commit is contained in:
gsinghpal
2026-04-24 21:04:38 -04:00
parent 0eab4b4efb
commit 41d0908ade
4083 changed files with 1230780 additions and 287 deletions

View File

@@ -904,11 +904,24 @@ class PaymentTransaction(models.Model):
self.poynt_receipt_data = json.dumps(receipt)
def _poynt_attach_receipt_pdf(self):
"""Render the QWeb receipt report and attach the PDF to the invoice."""
"""Render the QWeb receipt report and attach the PDF to the invoice.
Idempotent: if a PDF for this transaction is already attached,
skip. Poynt fires multiple webhooks per payment; without this
guard the same invoice would get N duplicate receipt PDFs."""
invoice = self.invoice_ids[:1]
if not invoice:
return
filename = f"Payment_Receipt_{self.reference}.pdf"
existing = self.env['ir.attachment'].sudo().search([
('res_model', '=', 'account.move'),
('res_id', '=', invoice.id),
('name', '=', filename),
], limit=1)
if existing:
return
try:
report = self.env.ref('fusion_poynt.action_report_poynt_receipt')
pdf_content, _report_type = report._render_qweb_pdf(report.report_name, [self.id])
@@ -916,7 +929,6 @@ class PaymentTransaction(models.Model):
_logger.debug("Could not render Poynt receipt PDF for %s", self.reference)
return
filename = f"Payment_Receipt_{self.reference}.pdf"
attachment = self.env['ir.attachment'].sudo().create({
'name': filename,
'type': 'binary',
@@ -935,18 +947,33 @@ class PaymentTransaction(models.Model):
)
def _poynt_attach_poynt_receipt(self):
"""Try the Poynt renderReceipt endpoint and attach the result."""
"""Try the Poynt renderReceipt endpoint and attach the result.
Idempotent: if a Poynt HTML receipt for this transaction is already
attached to the invoice, we skip the remote call. Poynt sends
several state-change webhooks per transaction (AUTHORIZED, CAPTURED,
UPDATED...) and each one lands here; without this guard every
webhook would re-fetch the receipt and hammer Poynt.
"""
invoice = self.invoice_ids[:1]
if not invoice:
return
filename = f"Poynt_Receipt_{self.reference}.html"
existing = self.env['ir.attachment'].sudo().search([
('res_model', '=', 'account.move'),
('res_id', '=', invoice.id),
('name', '=', filename),
], limit=1)
if existing:
return
receipt_content = self._get_provider_sudo()._poynt_fetch_receipt(
self.poynt_transaction_id,
)
if not receipt_content:
return
filename = f"Poynt_Receipt_{self.reference}.html"
self.env['ir.attachment'].sudo().create({
'name': filename,
'type': 'binary',
@@ -963,6 +990,11 @@ class PaymentTransaction(models.Model):
1. Sends the invoice via the standard Odoo invoice email template.
2. Sends the Poynt payment receipt email with the PDF attached.
Idempotent: Poynt fires several state-change webhooks per payment
(AUTHORIZED, CAPTURED, UPDATED...). We use `invoice.is_move_sent`
as the "we've already done this" flag so duplicate webhooks don't
re-email the customer.
Best-effort: failures are logged but never block the payment flow.
"""
self.ensure_one()
@@ -976,6 +1008,13 @@ class PaymentTransaction(models.Model):
)
return
if invoice and invoice.is_move_sent:
_logger.debug(
"Skipping auto-send for %s: invoice %s already sent.",
self.reference, invoice.name,
)
return
# 1. Send the invoice PDF
if invoice and invoice.state == 'posted':
try: