generated from vignesh/searchengine
feat: create core payment service microservice with Cashfree gateway integration and operations portal
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 36s
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 36s
This commit is contained in:
parent
369f9c0383
commit
493b204d32
5 changed files with 204 additions and 58 deletions
|
|
@ -150,13 +150,32 @@ MAILERS = {
|
|||
}
|
||||
|
||||
# Cashfree Payment Gateway Configuration
|
||||
CASHFREE_APP_ID = os.environ.get('CASHFREE_APP_ID', 'TEST1118017027fc875a9485063df8b007108111')
|
||||
CASHFREE_SECRET_KEY = os.environ.get('CASHFREE_SECRET_KEY', 'cfsk_ma_test_3701af3af410228b8e707765dbb68c32_1cf9fb86')
|
||||
# Production API credentials (for requests originating from beta.tradhox.com & tradhox.com)
|
||||
CASHFREE_PROD_APP_ID = os.environ.get('CASHFREE_PROD_APP_ID', '1370798f950e30514fa051e93868970731')
|
||||
CASHFREE_PROD_SECRET_KEY = os.environ.get('CASHFREE_PROD_SECRET_KEY', 'cfsk_ma_prod_d441689923a71877068fee6b6e2e0d05_a626ee00')
|
||||
|
||||
# Sandbox / Test API credentials (for local testing and sandbox simulation)
|
||||
CASHFREE_TEST_APP_ID = os.environ.get('CASHFREE_TEST_APP_ID', 'TEST1118017027fc875a9485063df8b007108111')
|
||||
CASHFREE_TEST_SECRET_KEY = os.environ.get('CASHFREE_TEST_SECRET_KEY', 'cfsk_ma_test_3701af3af410228b8e707765dbb68c32_1cf9fb86')
|
||||
|
||||
# Default active fallback
|
||||
CASHFREE_APP_ID = os.environ.get('CASHFREE_APP_ID', CASHFREE_PROD_APP_ID)
|
||||
CASHFREE_SECRET_KEY = os.environ.get('CASHFREE_SECRET_KEY', CASHFREE_PROD_SECRET_KEY)
|
||||
CASHFREE_ENVIRONMENT = os.environ.get('CASHFREE_ENVIRONMENT', 'sandbox') # 'sandbox' or 'production'
|
||||
CASHFREE_API_VERSION = os.environ.get('CASHFREE_API_VERSION', '2023-08-01')
|
||||
|
||||
# Domains that trigger automatic Cashfree production API routing
|
||||
TRADHOX_PRODUCTION_DOMAINS = [
|
||||
'beta.tradhox.com',
|
||||
'tradhox.com',
|
||||
'www.tradhox.com',
|
||||
'betapayments.tradhox.com',
|
||||
'payments.tradhox.com',
|
||||
]
|
||||
|
||||
if CASHFREE_ENVIRONMENT == 'production':
|
||||
CASHFREE_BASE_URL = 'https://api.cashfree.com/pg'
|
||||
else:
|
||||
CASHFREE_BASE_URL = 'https://sandbox.cashfree.com/pg'
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,9 +26,11 @@ class PaymentEngine:
|
|||
"""Allows dynamic registration of gateway adapters (e.g. Razorpay)."""
|
||||
self.gateway_registry[name.upper()] = gateway_class
|
||||
|
||||
def get_adapter(self, config: PaymentGatewayConfig) -> Optional[BasePaymentGateway]:
|
||||
def get_adapter(self, config: PaymentGatewayConfig, request=None, environment=None) -> Optional[BasePaymentGateway]:
|
||||
gateway_class = self.gateway_registry.get(config.name.upper())
|
||||
if gateway_class:
|
||||
if config.name.upper() == 'CASHFREE':
|
||||
return gateway_class(config=config, request=request, environment=environment)
|
||||
return gateway_class(config=config)
|
||||
logger.warning(f"No adapter registered for gateway: {config.name}")
|
||||
return None
|
||||
|
|
@ -77,6 +79,8 @@ class PaymentEngine:
|
|||
notify_url: str,
|
||||
order_note: Optional[str] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
request=None,
|
||||
environment=None,
|
||||
) -> Tuple[bool, PaymentOrder, Optional[PaymentAttempt], Optional[str]]:
|
||||
"""
|
||||
Creates an order with automatic failover across registered gateways.
|
||||
|
|
@ -103,12 +107,13 @@ class PaymentEngine:
|
|||
last_error = "No active gateways available"
|
||||
|
||||
for config in candidates:
|
||||
adapter = self.get_adapter(config)
|
||||
adapter = self.get_adapter(config, request=request, environment=environment)
|
||||
if not adapter:
|
||||
continue
|
||||
|
||||
logger.info(f"Attempting order {order_id} via {adapter.gateway_name} (Priority {config.priority})")
|
||||
|
||||
|
||||
# Execute order creation with gateway
|
||||
resp: GatewayOrderResponse = adapter.create_order(
|
||||
order_id=order_id,
|
||||
|
|
|
|||
|
|
@ -17,27 +17,54 @@ class CashfreeGateway(BasePaymentGateway):
|
|||
|
||||
GATEWAY_NAME = 'CASHFREE'
|
||||
|
||||
def __init__(self, config=None):
|
||||
def __init__(self, config=None, environment: Optional[str] = None, request=None):
|
||||
super().__init__(config)
|
||||
# Use database config if provided, else fall back to django settings
|
||||
if config:
|
||||
self.app_id = config.app_id or getattr(settings, 'CASHFREE_APP_ID', '')
|
||||
self.secret_key = config.secret_key or getattr(settings, 'CASHFREE_SECRET_KEY', '')
|
||||
self.environment = config.environment or getattr(settings, 'CASHFREE_ENVIRONMENT', 'sandbox')
|
||||
self.api_version = config.api_version or getattr(settings, 'CASHFREE_API_VERSION', '2023-08-01')
|
||||
else:
|
||||
self.app_id = getattr(settings, 'CASHFREE_APP_ID', '')
|
||||
self.secret_key = getattr(settings, 'CASHFREE_SECRET_KEY', '')
|
||||
self.environment = getattr(settings, 'CASHFREE_ENVIRONMENT', 'sandbox')
|
||||
self.api_version = getattr(settings, 'CASHFREE_API_VERSION', '2023-08-01')
|
||||
|
||||
# 1. Determine target environment (production vs sandbox)
|
||||
resolved_env = None
|
||||
if environment:
|
||||
resolved_env = environment
|
||||
elif request:
|
||||
req_data = getattr(request, 'data', {}) or {}
|
||||
if isinstance(req_data, dict) and req_data.get('environment') in ('production', 'sandbox'):
|
||||
resolved_env = req_data.get('environment')
|
||||
else:
|
||||
# Inspect Origin, Referer, Host headers for Tradhox production domains
|
||||
origin = request.META.get('HTTP_ORIGIN', '').lower()
|
||||
referer = request.META.get('HTTP_REFERER', '').lower()
|
||||
host = request.META.get('HTTP_HOST', '').lower()
|
||||
prod_domains = getattr(settings, 'TRADHOX_PRODUCTION_DOMAINS', [
|
||||
'beta.tradhox.com', 'tradhox.com', 'www.tradhox.com', 'betapayments.tradhox.com'
|
||||
])
|
||||
for domain in prod_domains:
|
||||
if domain in origin or domain in referer or domain in host:
|
||||
resolved_env = 'production'
|
||||
break
|
||||
|
||||
if not resolved_env:
|
||||
if config and config.environment:
|
||||
resolved_env = config.environment
|
||||
else:
|
||||
resolved_env = getattr(settings, 'CASHFREE_ENVIRONMENT', 'sandbox')
|
||||
|
||||
self.environment = resolved_env
|
||||
self.api_version = (config.api_version if config else None) or getattr(settings, 'CASHFREE_API_VERSION', '2023-08-01')
|
||||
|
||||
# 2. Select credentials according to resolved environment
|
||||
if self.environment == 'production':
|
||||
self.app_id = (config.app_id if config and config.environment == 'production' and config.app_id else getattr(settings, 'CASHFREE_PROD_APP_ID', '1370798f950e30514fa051e93868970731'))
|
||||
self.secret_key = (config.secret_key if config and config.environment == 'production' and config.secret_key else getattr(settings, 'CASHFREE_PROD_SECRET_KEY', 'cfsk_ma_prod_d441689923a71877068fee6b6e2e0d05_a626ee00'))
|
||||
self.base_url = 'https://api.cashfree.com/pg'
|
||||
self.checkout_base = 'https://payments.cashfree.com/order/#'
|
||||
else:
|
||||
self.app_id = (config.app_id if config and config.environment == 'sandbox' and config.app_id else getattr(settings, 'CASHFREE_TEST_APP_ID', 'TEST1118017027fc875a9485063df8b007108111'))
|
||||
self.secret_key = (config.secret_key if config and config.environment == 'sandbox' and config.secret_key else getattr(settings, 'CASHFREE_TEST_SECRET_KEY', 'cfsk_ma_test_3701af3af410228b8e707765dbb68c32_1cf9fb86'))
|
||||
self.base_url = 'https://sandbox.cashfree.com/pg'
|
||||
self.checkout_base = 'https://payments-test.cashfree.com/order/#'
|
||||
|
||||
logger.info(f"CashfreeGateway initialized in [{self.environment.upper()}] mode (App ID: {self.app_id[:8]}...)")
|
||||
|
||||
|
||||
@property
|
||||
def gateway_name(self) -> str:
|
||||
return self.GATEWAY_NAME
|
||||
|
|
@ -183,13 +210,28 @@ class CashfreeGateway(BasePaymentGateway):
|
|||
).digest()
|
||||
computed_signature = base64.b64encode(computed_hmac).decode('utf-8')
|
||||
|
||||
if not hmac.compare_digest(computed_signature, signature):
|
||||
is_matched = hmac.compare_digest(computed_signature, signature)
|
||||
if not is_matched:
|
||||
# Try alternate key (production vs test) in case order was placed under different environment
|
||||
alt_key = getattr(settings, 'CASHFREE_PROD_SECRET_KEY', '') if self.environment != 'production' else getattr(settings, 'CASHFREE_TEST_SECRET_KEY', '')
|
||||
if alt_key and alt_key != self.secret_key:
|
||||
alt_hmac = hmac.new(
|
||||
key=alt_key.encode('utf-8'),
|
||||
msg=payload_to_sign,
|
||||
digestmod=hashlib.sha256
|
||||
).digest()
|
||||
alt_sig = base64.b64encode(alt_hmac).decode('utf-8')
|
||||
if hmac.compare_digest(alt_sig, signature):
|
||||
is_matched = True
|
||||
|
||||
if not is_matched:
|
||||
return GatewayVerifyResult(
|
||||
is_valid=False,
|
||||
event_type="SIGNATURE_MISMATCH",
|
||||
error_message="Computed signature does not match header signature"
|
||||
)
|
||||
|
||||
|
||||
# Parse JSON
|
||||
try:
|
||||
body_json = json.loads(raw_body.decode('utf-8'))
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class CreatePaymentOrderView(APIView):
|
|||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
data = serializer.validated_data
|
||||
requested_env = request.data.get('environment')
|
||||
success, order, attempt, error_msg = payment_engine.initiate_payment_order(
|
||||
order_id=data['order_id'],
|
||||
amount=float(data['amount']),
|
||||
|
|
@ -49,6 +50,8 @@ class CreatePaymentOrderView(APIView):
|
|||
notify_url=data.get('notify_url', ''),
|
||||
order_note=data.get('order_note', ''),
|
||||
metadata=data.get('metadata', {}),
|
||||
request=request,
|
||||
environment=requested_env,
|
||||
)
|
||||
|
||||
if not success:
|
||||
|
|
@ -64,8 +67,12 @@ class CreatePaymentOrderView(APIView):
|
|||
if attempt and attempt.raw_response:
|
||||
checkout_url = attempt.raw_response.get("payment_session_id")
|
||||
if checkout_url and attempt.gateway_name == 'CASHFREE':
|
||||
config = PaymentGatewayConfig.objects.filter(name='CASHFREE').first()
|
||||
base = 'https://payments.cashfree.com/order/#' if (config and config.environment == 'production') else 'https://payments-test.cashfree.com/order/#'
|
||||
origin = request.META.get('HTTP_ORIGIN', '').lower()
|
||||
referer = request.META.get('HTTP_REFERER', '').lower()
|
||||
host = request.META.get('HTTP_HOST', '').lower()
|
||||
prod_domains = getattr(settings, 'TRADHOX_PRODUCTION_DOMAINS', ['beta.tradhox.com', 'tradhox.com'])
|
||||
is_prod = (requested_env == 'production') or any(d in origin or d in referer or d in host for d in prod_domains)
|
||||
base = 'https://payments.cashfree.com/order/#' if is_prod else 'https://payments-test.cashfree.com/order/#'
|
||||
checkout_url = f"{base}{attempt.payment_session_id}"
|
||||
|
||||
return Response({
|
||||
|
|
@ -441,7 +448,7 @@ class CashfreeDirectPaySessionView(APIView):
|
|||
return Response({"error": "payment_session_id is required"}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
config = PaymentGatewayConfig.objects.filter(name='CASHFREE').first()
|
||||
gateway = CashfreeGateway(config=config)
|
||||
gateway = CashfreeGateway(config=config, request=request, environment=request.data.get('environment'))
|
||||
|
||||
url = f"{gateway.base_url}/orders/sessions"
|
||||
method_payload = {"channel": channel}
|
||||
|
|
@ -473,7 +480,7 @@ class CashfreeDirectPaymentsListView(APIView):
|
|||
|
||||
def get(self, request, order_id):
|
||||
config = PaymentGatewayConfig.objects.filter(name='CASHFREE').first()
|
||||
gateway = CashfreeGateway(config=config)
|
||||
gateway = CashfreeGateway(config=config, request=request, environment=request.query_params.get('environment'))
|
||||
|
||||
url = f"{gateway.base_url}/orders/{order_id}/payments"
|
||||
import requests
|
||||
|
|
@ -494,7 +501,7 @@ class CashfreeDirectSettlementsView(APIView):
|
|||
|
||||
def get(self, request, order_id):
|
||||
config = PaymentGatewayConfig.objects.filter(name='CASHFREE').first()
|
||||
gateway = CashfreeGateway(config=config)
|
||||
gateway = CashfreeGateway(config=config, request=request, environment=request.query_params.get('environment'))
|
||||
|
||||
url = f"{gateway.base_url}/orders/{order_id}/settlements"
|
||||
import requests
|
||||
|
|
@ -509,7 +516,7 @@ class CashfreeDirectSettlementsView(APIView):
|
|||
class CashfreeDirectCreateOrderView(APIView):
|
||||
"""
|
||||
POST /api/payments/cashfree/orders/create/
|
||||
Creates an order directly against Cashfree Sandbox, bypassing orchestrator routing.
|
||||
Creates an order directly against Cashfree, bypassing orchestrator routing.
|
||||
Records the order and attempt in the database for tracking and refunds.
|
||||
"""
|
||||
permission_classes = [permissions.AllowAny]
|
||||
|
|
@ -529,7 +536,7 @@ class CashfreeDirectCreateOrderView(APIView):
|
|||
return Response({"error": "order_id and amount are required"}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
config = PaymentGatewayConfig.objects.filter(name='CASHFREE').first()
|
||||
gateway = CashfreeGateway(config=config)
|
||||
gateway = CashfreeGateway(config=config, request=request, environment=request.data.get('environment'))
|
||||
|
||||
# Call Cashfree API directly
|
||||
resp = gateway.create_order(
|
||||
|
|
@ -598,7 +605,7 @@ class CashfreeDirectRawOrderView(APIView):
|
|||
|
||||
def get(self, request, order_id):
|
||||
config = PaymentGatewayConfig.objects.filter(name='CASHFREE').first()
|
||||
gateway = CashfreeGateway(config=config)
|
||||
gateway = CashfreeGateway(config=config, request=request, environment=request.query_params.get('environment'))
|
||||
raw_order = gateway.get_order(order_id)
|
||||
return Response(raw_order, status=status.HTTP_200_OK)
|
||||
|
||||
|
|
@ -606,7 +613,7 @@ class CashfreeDirectRawOrderView(APIView):
|
|||
class CashfreeQuickSessionView(APIView):
|
||||
"""
|
||||
POST /api/payments/cashfree/quick-session/
|
||||
Automatically generates a live Cashfree Sandbox order and returns the payment_session_id.
|
||||
Automatically generates a live Cashfree order and returns the payment_session_id.
|
||||
Requires zero manual parameters, enabling 1-click dynamic session creation.
|
||||
"""
|
||||
permission_classes = [permissions.AllowAny]
|
||||
|
|
@ -615,7 +622,7 @@ class CashfreeQuickSessionView(APIView):
|
|||
amount = float(request.data.get('amount') or 100.00)
|
||||
rand_id = f"CF-UPI-{int(timezone.now().timestamp())}"
|
||||
config = PaymentGatewayConfig.objects.filter(name='CASHFREE').first()
|
||||
gateway = CashfreeGateway(config=config)
|
||||
gateway = CashfreeGateway(config=config, request=request, environment=request.data.get('environment'))
|
||||
|
||||
resp = gateway.create_order(
|
||||
order_id=rand_id,
|
||||
|
|
|
|||
|
|
@ -985,20 +985,43 @@
|
|||
<div class="section-header">
|
||||
<h2 class="section-title" style="color: var(--cashfree-color);">
|
||||
<svg width="22" height="22" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/></svg>
|
||||
Cashfree Dedicated Vendor Studio (Direct Sandbox)
|
||||
Cashfree Dedicated Vendor Studio
|
||||
</h2>
|
||||
<span class="badge" style="background: var(--cashfree-glow); color: #F472B6; border: 1px solid var(--border-cashfree);">Isolated Gateway Engine</span>
|
||||
<div style="display: flex; gap: 10px; align-items: center;">
|
||||
<span class="badge" id="cf-env-badge" style="background: var(--cashfree-glow); color: #F472B6; border: 1px solid var(--border-cashfree);">Mode: Sandbox</span>
|
||||
<span class="badge" style="background: rgba(16, 185, 129, 0.15); color: #34D399; border: 1px solid rgba(16, 185, 129, 0.3);">
|
||||
🌐 Auto-Routing: beta.tradhox.com & tradhox.com ➔ Production
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cashfree Direct Live Config & Connectivity -->
|
||||
<div style="background: rgba(236, 72, 153, 0.08); border: 1px solid var(--border-cashfree); border-radius: var(--radius-md); padding: 18px 24px; margin-bottom: 24px; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 16px;">
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 13px;">
|
||||
<div><span style="color: var(--text-muted); font-size: 11px; text-transform: uppercase; font-weight: 600;">App ID:</span> <code style="color: #F472B6; font-family: var(--font-mono);">TEST1118017027fc875a9485063df8b007108111</code></div>
|
||||
<div><span style="color: var(--text-muted); font-size: 11px; text-transform: uppercase; font-weight: 600;">Secret:</span> <code style="color: #F472B6; font-family: var(--font-mono);">cfsk_ma_test_3701...1cf9fb86</code></div>
|
||||
<div><span style="color: var(--text-muted); font-size: 11px; text-transform: uppercase; font-weight: 600;">API Base:</span> <code style="color: #F472B6; font-family: var(--font-mono);">https://sandbox.cashfree.com/pg</code></div>
|
||||
<div><span style="color: var(--text-muted); font-size: 11px; text-transform: uppercase; font-weight: 600;">Version:</span> <code style="color: #F472B6; font-family: var(--font-mono);">2023-08-01</code></div>
|
||||
<!-- Cashfree Direct Live Config & Environment Switcher -->
|
||||
<div style="background: rgba(236, 72, 153, 0.08); border: 1px solid var(--border-cashfree); border-radius: var(--radius-md); padding: 18px 24px; margin-bottom: 24px; display: flex; flex-direction: column; gap: 14px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 14px;">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<label style="font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0;">Target Environment:</label>
|
||||
<select id="cf-studio-env-select" onchange="onCfStudioEnvChange()" class="form-control" style="width: auto; padding: 6px 14px; font-size: 13px; font-weight: 600; background: #0A0D14; border-color: var(--border-cashfree); color: #F472B6; border-radius: var(--radius-sm); cursor: pointer;">
|
||||
<option value="sandbox" selected>Sandbox Mode (Test Simulator)</option>
|
||||
<option value="production">Production Mode (api.cashfree.com/pg)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="display: flex; gap: 10px; align-items: center;">
|
||||
<button onclick="pingCashfreeDirectApi()" class="btn btn-cashfree btn-sm" id="btn-ping-cf">⚡ Ping Active Gateway</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 20px; font-size: 12px; background: rgba(0,0,0,0.3); padding: 12px 16px; border-radius: var(--radius-sm); border: 1px solid rgba(255,255,255,0.05);">
|
||||
<div><span style="color: var(--text-muted); font-size: 11px; text-transform: uppercase; font-weight: 600;">Active App ID:</span> <code id="cf-disp-appid" style="color: #F472B6; font-family: var(--font-mono); font-weight: 600;">TEST1118017027fc875a9485063df8b007108111</code></div>
|
||||
<div><span style="color: var(--text-muted); font-size: 11px; text-transform: uppercase; font-weight: 600;">Secret Key:</span> <code id="cf-disp-secret" style="color: #F472B6; font-family: var(--font-mono);">cfsk_ma_test_3701...1cf9fb86</code></div>
|
||||
<div><span style="color: var(--text-muted); font-size: 11px; text-transform: uppercase; font-weight: 600;">API Base URL:</span> <code id="cf-disp-baseurl" style="color: #A5B4FC; font-family: var(--font-mono);">https://sandbox.cashfree.com/pg</code></div>
|
||||
<div><span style="color: var(--text-muted); font-size: 11px; text-transform: uppercase; font-weight: 600;">Checkout Base:</span> <code id="cf-disp-checkout" style="color: #34D399; font-family: var(--font-mono);">https://payments-test.cashfree.com/order/#</code></div>
|
||||
<div><span style="color: var(--text-muted); font-size: 11px; text-transform: uppercase; font-weight: 600;">API Version:</span> <code style="color: #F472B6; font-family: var(--font-mono);">2023-08-01</code></div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; font-size: 11px; color: var(--text-dim);">
|
||||
<span>🔒 <strong>Credentials in Memory:</strong> Prod: <code>1370798f...970731</code> (api.cashfree.com) | Sandbox: <code>TEST1118...8111</code> (sandbox.cashfree.com)</span>
|
||||
<span style="color: #34D399;">✓ Automatic origin-based routing active for beta.tradhox.com & tradhox.com</span>
|
||||
</div>
|
||||
<button onclick="pingCashfreeDirectApi()" class="btn btn-cashfree btn-sm" id="btn-ping-cf">⚡ Ping Cashfree Direct API</button>
|
||||
</div>
|
||||
|
||||
<div class="sandbox-container" style="border-color: var(--border-cashfree);">
|
||||
|
|
@ -1653,15 +1676,57 @@
|
|||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// ==========================================
|
||||
// CASHFREE DEDICATED VENDOR STUDIO HANDLERS
|
||||
// ==========================================
|
||||
|
||||
function getCfStudioEnv() {
|
||||
const el = document.getElementById('cf-studio-env-select');
|
||||
return el ? el.value : 'sandbox';
|
||||
}
|
||||
|
||||
function onCfStudioEnvChange() {
|
||||
const env = getCfStudioEnv();
|
||||
const badge = document.getElementById('cf-env-badge');
|
||||
const appIdEl = document.getElementById('cf-disp-appid');
|
||||
const secretEl = document.getElementById('cf-disp-secret');
|
||||
const baseEl = document.getElementById('cf-disp-baseurl');
|
||||
const checkoutEl = document.getElementById('cf-disp-checkout');
|
||||
|
||||
if (env === 'production') {
|
||||
if (badge) {
|
||||
badge.textContent = 'Mode: Production (Live)';
|
||||
badge.style.background = 'rgba(239, 68, 68, 0.15)';
|
||||
badge.style.color = '#F87171';
|
||||
badge.style.borderColor = 'rgba(239, 68, 68, 0.3)';
|
||||
}
|
||||
if (appIdEl) appIdEl.textContent = '1370798f950e30514fa051e93868970731';
|
||||
if (secretEl) secretEl.textContent = 'cfsk_ma_prod_d441...a626ee00';
|
||||
if (baseEl) baseEl.textContent = 'https://api.cashfree.com/pg';
|
||||
if (checkoutEl) checkoutEl.textContent = 'https://payments.cashfree.com/order/#';
|
||||
showToast('Switched Cashfree Studio to Production Mode (api.cashfree.com)', 'info');
|
||||
} else {
|
||||
if (badge) {
|
||||
badge.textContent = 'Mode: Sandbox';
|
||||
badge.style.background = 'var(--cashfree-glow)';
|
||||
badge.style.color = '#F472B6';
|
||||
badge.style.borderColor = 'var(--border-cashfree)';
|
||||
}
|
||||
if (appIdEl) appIdEl.textContent = 'TEST1118017027fc875a9485063df8b007108111';
|
||||
if (secretEl) secretEl.textContent = 'cfsk_ma_test_3701...1cf9fb86';
|
||||
if (baseEl) baseEl.textContent = 'https://sandbox.cashfree.com/pg';
|
||||
if (checkoutEl) checkoutEl.textContent = 'https://payments-test.cashfree.com/order/#';
|
||||
showToast('Switched Cashfree Studio to Sandbox Mode', 'info');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDirectCashfreeOrder(e) {
|
||||
e.preventDefault();
|
||||
const btn = document.getElementById('btn-cf-direct-create');
|
||||
btn.disabled = true;
|
||||
|
||||
const env = getCfStudioEnv();
|
||||
const payload = {
|
||||
order_id: document.getElementById('cf-direct-order-id').value,
|
||||
amount: document.getElementById('cf-direct-amount').value,
|
||||
|
|
@ -1670,12 +1735,13 @@
|
|||
customer_name: document.getElementById('cf-direct-cust-name').value,
|
||||
customer_email: document.getElementById('cf-direct-email').value,
|
||||
customer_phone: document.getElementById('cf-direct-phone').value,
|
||||
order_note: 'Direct Cashfree Vendor Sandbox Order',
|
||||
return_url: window.location.origin + '/portal/?order_id={order_id}'
|
||||
order_note: `Direct Cashfree Vendor Order [${env.toUpperCase()}]`,
|
||||
return_url: window.location.origin + '/portal/?order_id={order_id}',
|
||||
environment: env
|
||||
};
|
||||
|
||||
try {
|
||||
logConsole('Sending Direct Order to Cashfree API...', payload);
|
||||
logConsole(`Sending Direct Order to Cashfree API [${env.toUpperCase()}]...`, payload);
|
||||
const res = await fetch('/api/payments/cashfree/orders/create/', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
|
|
@ -1688,12 +1754,12 @@
|
|||
currentOrderId = data.order_id;
|
||||
currentSessionId = data.payment_session_id;
|
||||
|
||||
showToast(`Cashfree order ${data.order_id} created successfully!`, 'success');
|
||||
showToast(`Cashfree order ${data.order_id} created successfully [${env.toUpperCase()}]!`, 'success');
|
||||
|
||||
const drawer = document.getElementById('cf-direct-drawer');
|
||||
drawer.style.display = 'block';
|
||||
document.getElementById('cf-drawer-info').textContent =
|
||||
`Cashfree Order ID: ${data.gateway_order_id} | Session ID: ${data.payment_session_id}`;
|
||||
`Order: ${data.gateway_order_id || data.order_id} | Session: ${data.payment_session_id} [${env}]`;
|
||||
|
||||
document.getElementById('btn-cf-direct-hosted').href = data.checkout_url || '#';
|
||||
document.getElementById('upi-session-id').value = data.payment_session_id;
|
||||
|
|
@ -1799,11 +1865,12 @@
|
|||
}
|
||||
|
||||
try {
|
||||
logConsole(`Auto-generating live Cashfree Payment Session for ₹${amount}...`);
|
||||
const env = getCfStudioEnv();
|
||||
logConsole(`Auto-generating live Cashfree Payment Session for ₹${amount} [${env}]...`);
|
||||
const res = await fetch('/api/payments/cashfree/quick-session/', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ amount: amount })
|
||||
body: JSON.stringify({ amount: amount, environment: env })
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
|
|
@ -1816,9 +1883,9 @@
|
|||
|
||||
if (statusEl) {
|
||||
statusEl.style.color = 'var(--success)';
|
||||
statusEl.textContent = `✓ Generated Session for ${data.order_id} (₹${amount})`;
|
||||
statusEl.textContent = `✓ Generated Session for ${data.order_id} (₹${amount}) [${env}]`;
|
||||
}
|
||||
showToast(`Live Session ID generated for order ${data.order_id}!`, 'success');
|
||||
showToast(`Live Session ID generated for order ${data.order_id} [${env}]!`, 'success');
|
||||
logConsole('Cashfree Quick Session Generated:', data);
|
||||
refreshDashboard();
|
||||
return data.payment_session_id;
|
||||
|
|
@ -1871,13 +1938,15 @@
|
|||
out.textContent = 'Calling Cashfree /orders/sessions endpoint...';
|
||||
|
||||
try {
|
||||
const env = getCfStudioEnv();
|
||||
const res = await fetch('/api/payments/cashfree/pay/', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
payment_session_id: sessionId,
|
||||
channel: channel,
|
||||
upi_id: upiId
|
||||
upi_id: upiId,
|
||||
environment: env
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
|
|
@ -1916,15 +1985,16 @@
|
|||
if (statusEl) {
|
||||
statusEl.style.display = 'inline';
|
||||
statusEl.style.color = '#FBBF24';
|
||||
statusEl.textContent = 'Creating sandbox order on Cashfree...';
|
||||
statusEl.textContent = 'Creating order on Cashfree...';
|
||||
}
|
||||
|
||||
try {
|
||||
logConsole('Auto-generating Cashfree test order for inspection...');
|
||||
const env = getCfStudioEnv();
|
||||
logConsole(`Auto-generating Cashfree test order for inspection [${env}]...`);
|
||||
const res = await fetch('/api/payments/cashfree/quick-session/', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ amount: 150 })
|
||||
body: JSON.stringify({ amount: 150, environment: env })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok && data.success) {
|
||||
|
|
@ -1937,9 +2007,9 @@
|
|||
|
||||
if (statusEl) {
|
||||
statusEl.style.color = 'var(--success)';
|
||||
statusEl.textContent = `✓ Generated ${data.order_id}`;
|
||||
statusEl.textContent = `✓ Generated ${data.order_id} [${env}]`;
|
||||
}
|
||||
showToast(`Generated order ${data.order_id} on Cashfree!`, 'success');
|
||||
showToast(`Generated order ${data.order_id} on Cashfree [${env}]!`, 'success');
|
||||
refreshDashboard();
|
||||
|
||||
if (target === 'inspector') {
|
||||
|
|
@ -2007,11 +2077,12 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const env = getCfStudioEnv();
|
||||
const out = document.getElementById('cf-inspector-output');
|
||||
out.textContent = `Querying Cashfree API for raw order ${orderId}...`;
|
||||
out.textContent = `Querying Cashfree API for raw order ${orderId} [${env}]...`;
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/payments/cashfree/orders/${orderId}/raw/`);
|
||||
const res = await fetch(`/api/payments/cashfree/orders/${orderId}/raw/?environment=${env}`);
|
||||
const data = await res.json();
|
||||
out.textContent = JSON.stringify(data, null, 2);
|
||||
logConsole('Raw Cashfree Server Order Object:', data);
|
||||
|
|
@ -2027,11 +2098,12 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const env = getCfStudioEnv();
|
||||
const out = document.getElementById('cf-inspector-output');
|
||||
out.textContent = `Querying Cashfree /orders/${orderId}/payments directly...`;
|
||||
out.textContent = `Querying Cashfree /orders/${orderId}/payments directly [${env}]...`;
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/payments/cashfree/orders/${orderId}/payments/`);
|
||||
const res = await fetch(`/api/payments/cashfree/orders/${orderId}/payments/?environment=${env}`);
|
||||
const data = await res.json();
|
||||
out.textContent = JSON.stringify(data, null, 2);
|
||||
logConsole('Direct Cashfree Payments Array:', data);
|
||||
|
|
@ -2048,11 +2120,12 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const env = getCfStudioEnv();
|
||||
const out = document.getElementById('cf-inspector-output');
|
||||
out.textContent = `Querying Cashfree /orders/${orderId}/settlements directly...`;
|
||||
out.textContent = `Querying Cashfree /orders/${orderId}/settlements directly [${env}]...`;
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/payments/cashfree/orders/${orderId}/settlements/`);
|
||||
const res = await fetch(`/api/payments/cashfree/orders/${orderId}/settlements/?environment=${env}`);
|
||||
const data = await res.json();
|
||||
out.textContent = JSON.stringify(data, null, 2);
|
||||
logConsole('Direct Cashfree Settlement Details:', data);
|
||||
|
|
|
|||
Loading…
Reference in a new issue