import logging import requests import json from odoo import http _logger = logging.getLogger(__name__) class PaydunyaController(http.Controller): @http.route('/payment/paydunya/return', type='http', auth='public', methods=['GET'], csrf=False) def paydunya_return(self, **kwargs): """Handle return from PayDunya after payment attempt.""" token = kwargs.get('token') or http.request.params.get('token') tx_id = kwargs.get('tx_id') or http.request.params.get('tx_id') sale_order_id = kwargs.get('sale_order_id') or http.request.params.get('sale_order_id') tx_model = http.request.env['payment.transaction'].sudo() tx = False if tx_id: try: tx = tx_model.search([('id', '=', int(tx_id))], limit=1) except (TypeError, ValueError): tx = False provider = http.request.env['payment.provider'].sudo().search([('code', '=', 'paydunya')], limit=1) if not provider and token: _logger.warning('PayDunya return called but no provider found') return http.request.redirect('/') data = {} if token and provider: # Build check URL using the confirm endpoint base = provider._get_paydunya_api_base() confirm_url = base + '/checkout-invoice/confirm/{}'.format(token) headers = { 'Content-Type': 'application/json', 'PAYDUNYA-MASTER-KEY': provider.paydunya_master_key or '', 'PAYDUNYA-PRIVATE-KEY': provider.paydunya_private_key or '', 'PAYDUNYA-TOKEN': provider.paydunya_token or '' } try: # GET request to verify status resp = requests.get(confirm_url, headers=headers, timeout=15) data = resp.json() _logger.info('PayDunya confirm response: %s', data) except Exception as e: _logger.exception('Error verifying PayDunya invoice: %s', e) data = {'token': token, 'status': 'failed', 'sale_order_id': sale_order_id, 'tx_id': tx_id} elif tx: # Fallback when PayDunya did not return token: rely on tx current state. data = {'tx_id': tx.id, 'sale_order_id': sale_order_id} else: return http.request.redirect('/') # Trigger transaction handling with the confirmed data try: handled = tx_model._handle_notification_data(data) tx = tx or tx_model._get_tx_from_notification(data) if tx and tx.state == 'done': order = tx._paydunya_get_related_sale_order(sale_order_id=sale_order_id) if order: http.request.session['sale_last_order_id'] = order.id http.request.session['sale_transaction_id'] = tx.id return http.request.redirect('/shop/confirmation') if handled: return http.request.redirect('/shop/cart') except Exception: _logger.exception('Error handling PayDunya notification data') return http.request.redirect('/') @http.route('/payment/paydunya/cancel', type='http', auth='public', methods=['GET'], csrf=False) def paydunya_cancel(self, **kwargs): """Handle cancellation from PayDunya.""" token = kwargs.get('token') or http.request.params.get('token') _logger.info('PayDunya payment cancelled: token=%s', token) return http.request.redirect('/shop/cart') @http.route('/payment/paydunya/callback', type='http', auth='public', methods=['GET', 'POST'], csrf=False) def paydunya_callback(self, **kwargs): """Handle IPN callback from PayDunya. PayDunya sends data as application/x-www-form-urlencoded with 'data' key containing JSON. """ try: payload = {} data_str = http.request.params.get('data') if data_str: payload = {'data': data_str} elif http.request.params: payload = dict(http.request.params) else: raw_body = http.request.httprequest.get_data(as_text=True) if raw_body: try: payload = json.loads(raw_body) except Exception: payload = {'data': raw_body} _logger.info('PayDunya IPN callback received: %s', payload) tx_model = http.request.env['payment.transaction'].sudo() tx_model._handle_notification_data(payload) except Exception: _logger.exception('Error handling PayDunya callback') # Always return 200 OK to PayDunya return 'OK'