changes
This commit is contained in:
@@ -23,6 +23,10 @@ class AccountMove(models.Model):
|
||||
string="Has Poynt Receipt",
|
||||
compute='_compute_has_poynt_receipt',
|
||||
)
|
||||
poynt_transaction_count = fields.Integer(
|
||||
string="Poynt Transactions",
|
||||
compute='_compute_poynt_transaction_count',
|
||||
)
|
||||
|
||||
@api.depends('reversal_move_ids')
|
||||
def _compute_poynt_refund_count(self):
|
||||
@@ -38,6 +42,33 @@ class AccountMove(models.Model):
|
||||
for move in self:
|
||||
move.has_poynt_receipt = bool(move._get_poynt_transaction_for_receipt())
|
||||
|
||||
def _compute_poynt_transaction_count(self):
|
||||
for move in self:
|
||||
move.poynt_transaction_count = self.env['payment.transaction'].sudo().search_count([
|
||||
('invoice_ids', 'in', move.id),
|
||||
('provider_code', '=', 'poynt'),
|
||||
])
|
||||
|
||||
def action_view_poynt_transactions(self):
|
||||
"""Open payment transactions linked to this invoice/credit note."""
|
||||
self.ensure_one()
|
||||
transactions = self.env['payment.transaction'].sudo().search([
|
||||
('invoice_ids', 'in', self.id),
|
||||
('provider_code', '=', 'poynt'),
|
||||
])
|
||||
action = {
|
||||
'name': _("Poynt Transactions"),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'payment.transaction',
|
||||
'domain': [('id', 'in', transactions.ids)],
|
||||
}
|
||||
if len(transactions) == 1:
|
||||
action['view_mode'] = 'form'
|
||||
action['res_id'] = transactions.id
|
||||
else:
|
||||
action['view_mode'] = 'list,form'
|
||||
return action
|
||||
|
||||
def action_view_poynt_refunds(self):
|
||||
"""Open the credit notes linked to this invoice that were refunded via Poynt."""
|
||||
self.ensure_one()
|
||||
|
||||
@@ -58,6 +58,8 @@ class PaymentTransaction(models.Model):
|
||||
|
||||
For direct (online) payments we create a Poynt order upfront and return
|
||||
identifiers plus the return URL so the frontend JS can complete the flow.
|
||||
The actual transaction is created later when the frontend sends card
|
||||
details via the /payment/poynt/process_card route.
|
||||
"""
|
||||
if self.provider_code != 'poynt':
|
||||
return super()._get_specific_processing_values(processing_values)
|
||||
@@ -65,7 +67,7 @@ class PaymentTransaction(models.Model):
|
||||
if self.operation == 'online_token':
|
||||
return {}
|
||||
|
||||
poynt_data = self._poynt_create_order_and_authorize()
|
||||
order_data = self._poynt_create_order()
|
||||
|
||||
provider = self._get_provider_sudo()
|
||||
base_url = provider.get_base_url()
|
||||
@@ -75,8 +77,7 @@ class PaymentTransaction(models.Model):
|
||||
)
|
||||
|
||||
return {
|
||||
'poynt_order_id': poynt_data.get('order_id', ''),
|
||||
'poynt_transaction_id': poynt_data.get('transaction_id', ''),
|
||||
'poynt_order_id': order_data.get('order_id', ''),
|
||||
'return_url': return_url,
|
||||
'business_id': provider.poynt_business_id,
|
||||
'is_test': provider.state == 'test',
|
||||
@@ -108,6 +109,33 @@ class PaymentTransaction(models.Model):
|
||||
return
|
||||
self._process('poynt', payment_data)
|
||||
|
||||
def _poynt_create_order(self):
|
||||
"""Create a Poynt order without a transaction.
|
||||
|
||||
Used by the portal payment flow where card details are collected
|
||||
on the frontend and the transaction is created separately via
|
||||
the /payment/poynt/process_card route.
|
||||
|
||||
:return: Dict with order_id.
|
||||
:rtype: dict
|
||||
"""
|
||||
try:
|
||||
provider = self._get_provider_sudo()
|
||||
order_payload = poynt_utils.build_order_payload(
|
||||
self.reference, self.amount, self.currency_id,
|
||||
business_id=provider.poynt_business_id,
|
||||
store_id=provider.poynt_store_id or '',
|
||||
)
|
||||
order_result = provider._poynt_make_request(
|
||||
'POST', 'orders', payload=order_payload,
|
||||
)
|
||||
order_id = order_result.get('id', '')
|
||||
self.poynt_order_id = order_id
|
||||
return {'order_id': order_id}
|
||||
except ValidationError as e:
|
||||
self._set_error(str(e))
|
||||
return {}
|
||||
|
||||
def _poynt_create_order_and_authorize(self):
|
||||
"""Create a Poynt order and authorize the transaction.
|
||||
|
||||
@@ -383,6 +411,7 @@ class PaymentTransaction(models.Model):
|
||||
try:
|
||||
refund_payload = {
|
||||
'action': 'REFUND',
|
||||
'fundingSourceType': 'CREDIT_DEBIT',
|
||||
'parentId': parent_txn_id,
|
||||
'fundingSource': {
|
||||
'type': 'CREDIT_DEBIT',
|
||||
@@ -426,6 +455,7 @@ class PaymentTransaction(models.Model):
|
||||
try:
|
||||
capture_payload = {
|
||||
'action': 'CAPTURE',
|
||||
'fundingSourceType': 'CREDIT_DEBIT',
|
||||
'parentId': source_tx.provider_reference,
|
||||
'amounts': {
|
||||
'transactionAmount': minor_amount,
|
||||
@@ -817,6 +847,7 @@ class PaymentTransaction(models.Model):
|
||||
self._poynt_store_receipt_data(payment_data)
|
||||
self._poynt_attach_receipt_pdf()
|
||||
self._poynt_attach_poynt_receipt()
|
||||
self._poynt_auto_send_invoice_and_receipt()
|
||||
except Exception:
|
||||
_logger.exception(
|
||||
"Receipt generation failed for transaction %s", self.reference,
|
||||
@@ -925,6 +956,64 @@ class PaymentTransaction(models.Model):
|
||||
'mimetype': 'text/html',
|
||||
})
|
||||
|
||||
def _poynt_auto_send_invoice_and_receipt(self):
|
||||
"""Automatically email the invoice and payment receipt to the customer
|
||||
after a successful payment.
|
||||
|
||||
1. Sends the invoice via the standard Odoo invoice email template.
|
||||
2. Sends the Poynt payment receipt email with the PDF attached.
|
||||
|
||||
Best-effort: failures are logged but never block the payment flow.
|
||||
"""
|
||||
self.ensure_one()
|
||||
invoice = self.invoice_ids[:1]
|
||||
partner = self.partner_id
|
||||
|
||||
if not partner.email:
|
||||
_logger.info(
|
||||
"Skipping auto-send for %s: partner %s has no email.",
|
||||
self.reference, partner.display_name,
|
||||
)
|
||||
return
|
||||
|
||||
# 1. Send the invoice PDF
|
||||
if invoice and invoice.state == 'posted':
|
||||
try:
|
||||
inv_template = self.env.ref(
|
||||
'account.email_template_edi_invoice',
|
||||
raise_if_not_found=False,
|
||||
)
|
||||
if inv_template:
|
||||
inv_template.sudo().send_mail(
|
||||
invoice.id, force_send=True,
|
||||
)
|
||||
invoice.sudo().write({'is_move_sent': True})
|
||||
_logger.info(
|
||||
"Auto-sent invoice %s to %s",
|
||||
invoice.name, partner.email,
|
||||
)
|
||||
except Exception:
|
||||
_logger.exception(
|
||||
"Failed to auto-send invoice %s", invoice.name,
|
||||
)
|
||||
|
||||
# 2. Send the payment receipt
|
||||
try:
|
||||
receipt_template = self.env.ref(
|
||||
'fusion_poynt.mail_template_poynt_receipt',
|
||||
raise_if_not_found=False,
|
||||
)
|
||||
if receipt_template:
|
||||
receipt_template.sudo().send_mail(self.id, force_send=True)
|
||||
_logger.info(
|
||||
"Auto-sent payment receipt for %s to %s",
|
||||
self.reference, partner.email,
|
||||
)
|
||||
except Exception:
|
||||
_logger.exception(
|
||||
"Failed to auto-send receipt for %s", self.reference,
|
||||
)
|
||||
|
||||
def _get_poynt_receipt_values(self):
|
||||
"""Parse the stored receipt JSON for use in QWeb templates.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import logging
|
||||
|
||||
from odoo import _, models
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -11,6 +11,37 @@ _logger = logging.getLogger(__name__)
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
poynt_transaction_count = fields.Integer(
|
||||
string="Poynt Transactions",
|
||||
compute='_compute_poynt_transaction_count',
|
||||
)
|
||||
|
||||
def _compute_poynt_transaction_count(self):
|
||||
for order in self:
|
||||
order.poynt_transaction_count = self.env['payment.transaction'].sudo().search_count([
|
||||
('sale_order_ids', 'in', order.id),
|
||||
('provider_code', '=', 'poynt'),
|
||||
])
|
||||
|
||||
def action_view_poynt_transactions(self):
|
||||
self.ensure_one()
|
||||
transactions = self.env['payment.transaction'].sudo().search([
|
||||
('sale_order_ids', 'in', self.id),
|
||||
('provider_code', '=', 'poynt'),
|
||||
])
|
||||
action = {
|
||||
'name': _("Poynt Transactions"),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'payment.transaction',
|
||||
'domain': [('id', 'in', transactions.ids)],
|
||||
}
|
||||
if len(transactions) == 1:
|
||||
action['view_mode'] = 'form'
|
||||
action['res_id'] = transactions.id
|
||||
else:
|
||||
action['view_mode'] = 'list,form'
|
||||
return action
|
||||
|
||||
def action_poynt_collect_payment(self):
|
||||
"""Create an invoice (if needed) and open the Poynt payment wizard.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user