Merge pull request 'feat(ipg): fix failed request and change html files' (#10) from FIX/failed-request into master

Reviewed-on: addwin/pg#10
Reviewed-by: Sayyid Hamid Mahdavi <sahama@noreply.localhost>
This commit is contained in:
Sayyid Hamid Mahdavi 2025-12-14 06:33:05 -05:00
commit c437ee453d
7 changed files with 231 additions and 206 deletions

View file

@ -159,14 +159,18 @@ class PaymentRequest(models.Model):
logger.error(f"[Deposit Verify] Failed to get response from wallet service | payment_id={self.pk}") logger.error(f"[Deposit Verify] Failed to get response from wallet service | payment_id={self.pk}")
raise Exception('Failed to get response from wallet service') raise Exception('Failed to get response from wallet service')
if not verify_response.uuid or verify_response.state != 5: if not verify_response.uuid:
logger.error(f"[Deposit Verify] Failed to get response uuid from wallet service | payment_id={self.pk}")
raise Exception('Failed to get response uuid from wallet service')
if verify_response.state != 5:
logger.error(f"[Deposit Verify] Wallet verification failed | payment_id={self.pk}, response={verify_response}") logger.error(f"[Deposit Verify] Wallet verification failed | payment_id={self.pk}, response={verify_response}")
to_pay_failed = PaymentRequest.objects.filter( # to_pay_failed = PaymentRequest.objects.filter(
pk=self.pk, # pk=self.pk,
state=StateChoices.WALLET_SUBMIT_SUCCESS.value # state=StateChoices.WALLET_SUBMIT_SUCCESS.value
).update( # ).update(
state=StateChoices.FAILED.value, # state=StateChoices.FAILED.value,
) # )
raise Exception('Failed to verify payment in wallet') raise Exception('Failed to verify payment in wallet')
to_pay_success = PaymentRequest.objects.filter( to_pay_success = PaymentRequest.objects.filter(

View file

@ -9,6 +9,7 @@ from rest_framework import generics
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from drf_spectacular.utils import extend_schema from drf_spectacular.utils import extend_schema
from django.shortcuts import render
from utils.commons import calculate_pna_commission from utils.commons import calculate_pna_commission
from .constans import StateChoices from .constans import StateChoices
@ -79,6 +80,11 @@ class PaymentRequestView(UpdateView):
charge_request.save_commission() charge_request.save_commission()
tool = charge_request.get_gateway_tools() tool = charge_request.get_gateway_tools()
tool.make_request() tool.make_request()
charge_request.refresh_from_db()
if charge_request.state == StateChoices.FAILED:
return render(request, 'pg/payment_failure.html', {
'object': charge_request
})
redirect_url = tool.get_pg_page_url() redirect_url = tool.get_pg_page_url()
return HttpResponseRedirect(redirect_url) return HttpResponseRedirect(redirect_url)
@ -88,6 +94,11 @@ class PaymentRequestView(UpdateView):
charge_request.set_gateway({'pna': True}) charge_request.set_gateway({'pna': True})
tool = charge_request.get_gateway_tools() tool = charge_request.get_gateway_tools()
tool.make_request() tool.make_request()
charge_request.refresh_from_db()
if charge_request.state == StateChoices.FAILED:
return render(request, 'pg/payment_failure.html', {
'object': charge_request
})
redirect_url = tool.get_pg_page_url() redirect_url = tool.get_pg_page_url()
return HttpResponseRedirect(redirect_url) return HttpResponseRedirect(redirect_url)

BIN
static/image/pg/fail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
static/image/pg/tik.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,33 @@
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% load jalali_tags %}
{% block title %}بازگشت{% endblock %}
{% block page_title %}بازگشت{% endblock %}
{% block content %}
مبلغ {{ object.amount }} ریال با وضعیت {{ object.get_state_display }}<br>
<form action="{{ request.get_full_path }}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="row g-3">
<div class="col-md-12 col-lg-12" id="formset">
{# <div class="card">#}
{# <div class="card-body">#}
{{ form|crispy }}
{# </div>#}
{# </div>#}
</div>
<h6 class="h6">بازگشت به برنامه</h6>
<div class="row">
<div class="col">
<button type="submit" name="redirect-to-app" value="true" class="btn mx-auto d-block">
<img class="img-thumbnail" width="128" height="128" src="{% static "image/icon.png" %}"/>
</button>
</div>
</div>
</div>
</form>
{% endblock %}

View file

@ -1,179 +1,168 @@
{% load static %} {% load static %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load jalali_tags %} {% load jalali_tags %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="fa" dir="rtl"> <html lang="fa" dir="rtl">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payment Unsuccessful</title> <title>Payment Unsuccessful</title>
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap" rel="stylesheet">
<style> <style>
body { body {
margin: 0; margin: 0;
font-family: 'Vazirmatn', sans-serif; font-family: 'Vazirmatn', sans-serif;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
min-height: 100vh; min-height: 100vh;
} }
.mobile-frame { .screen-content {
width: 100vh; flex-grow: 1;
height: 100vh; display: flex;
background-color: #ffffff; flex-direction: column;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); justify-content: space-between;
padding: 30px; }
box-sizing: border-box;
display: flex;
flex-direction: column; .message-section {
} flex-grow: 1;
display: flex;
.screen-content { flex-direction: column;
flex-grow: 1; justify-content: center;
display: flex; align-items: center;
flex-direction: column; text-align: center;
justify-content: space-between; }
}
.error-icon {
width: 40px;
.message-section { height: 40px;
flex-grow: 1; background-color: #e53935; /* Red for error */
display: flex; border-radius: 50%;
flex-direction: column; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
text-align: center; color: white;
} font-size: 24px;
font-weight: bold;
.error-icon { }
width: 40px;
height: 40px; .error-text {
background-color: #e53935; /* Red for error */ color: #e53935;
border-radius: 50%; font-size: 1.1rem;
display: flex; font-weight: bold;
justify-content: center; margin-top: 15px;
align-items: center; margin-bottom: 25px;
color: white; }
font-size: 24px;
font-weight: bold; .divider {
} width: 100%;
height: 1px;
.error-text { background-color: #eeeeee;
color: #e53935; border: none;
font-size: 1.1rem; margin-bottom: 25px;
font-weight: bold; }
margin-top: 15px;
margin-bottom: 25px; .details-text {
} color: #757575;
font-size: 0.9rem;
.divider { line-height: 1.6;
width: 100%; }
height: 1px;
background-color: #eeeeee; .details-text .code {
border: none; color: #424242;
margin-bottom: 25px; font-weight: 600;
} }
.details-text { .placeholder-link {
color: #757575; color: #bdbdbd;
font-size: 0.9rem; font-size: 0.9rem;
line-height: 1.6; text-decoration: underline;
} margin-top: 40px;
}
.details-text .code {
color: #424242;
font-weight: 600; .button-container {
} display: flex;
flex-direction: column;
.placeholder-link { gap: 15px;
color: #bdbdbd; width: 100%;
font-size: 0.9rem; }
text-decoration: underline;
margin-top: 40px; .btn {
} display: flex;
justify-content: center;
align-items: center;
.button-container { gap: 8px;
display: flex; width: 100%;
flex-direction: column; padding: 14px;
gap: 15px; border-radius: 8px;
width: 100%; font-size: 1rem;
} font-weight: bold;
font-family: 'Vazirmatn', sans-serif;
.btn { cursor: pointer;
display: flex; transition: all 0.2s ease-in-out;
justify-content: center; border: 1px solid transparent;
align-items: center; }
gap: 8px;
width: 100%; .btn-retry {
padding: 14px; background-color: #ffffff;
border-radius: 20px; border: 2px solid #6931c9;
font-size: 1rem; color: #6931c9;
font-weight: bold; }
font-family: 'Vazirmatn', sans-serif;
cursor: pointer; .btn-retry:hover {
transition: all 0.2s ease-in-out; background-color: #f9f7fd;
border: 1px solid transparent; }
}
.btn-primary {
.btn-retry { background-color: #3B604B;
background-color: #ffffff; color: #ffffff;
border: 2px solid #6931c9; }
color: #6931c9;
} .btn-primary:hover {
background-color: #3B604B;
.btn-retry:hover { }
background-color: #f9f7fd; </style>
} </head>
<body>
.btn-primary {
background-color: #6931c9; <div class="mobile-frame">
color: #ffffff; <div class="screen-content">
}
<div class="message-section">
.btn-primary:hover { <div ><img src="{% static "image/pg/fail.png" %}" alt="fail"></div>
background-color: #7745ce; {% if message %}
} <p class="error-text">{{ message }}</p>
</style> {% else %}
</head> <p class="error-text">پرداخت ناموفق </p>
<body> {% endif %}
<hr class="divider">
<div class="mobile-frame"> <div class="details-text">
<div class="screen-content"> <p>کد پیگیری تراکنش شما: <span class="code">{{ object.reference_number }}</span></p>
<p>در صورت کسر از موجودی، مبلغ پرداختی طی یک تا 72 ساعت آینده به حساب شما بازگردانده خواهد شد.</p>
<div class="message-section"> </div>
<div class="error-icon">!</div> <a href="https://winsoo.ir" class="placeholder-link">winsoo</a>
{% if message %} </div>
<p class="error-text">{{ message }}</p>
{% else %} <div class="button-container">
<p class="error-text">پرداخت شما ناموفق بود</p> <form action="{{ request.get_full_path }}" method="post" enctype="multipart/form-data">
{% endif %} {% csrf_token %}
<hr class="divider"> {{ form|crispy }}
<div class="details-text"> <button class="btn btn-primary" name="redirect-to-app" value="true">بازگشت به صفحه اصلی</button>
<p>کد پیگیری تراکنش شما: <span class="code">{{ object.reference_number }}</span></p> </form>
<p>در صورت کسر از موجودی، مبلغ پرداختی طی یک تا 72 ساعت آینده به حساب شما بازگردانده خواهد شد.</p> </div>
</div> </div>
<a href="https://winsoo.ir" class="placeholder-link">وینسو</a> </div>
</div>
</body>
<div class="button-container">
<form action="{{ request.get_full_path }}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary" name="redirect-to-app" value="true">بازگشت به صفحه اصلی</button>
</form>
</div>
</div>
</div>
</body>
</html> </html>

View file

@ -24,18 +24,6 @@
min-height: 100vh; min-height: 100vh;
} }
.mobile-frame {
width: 100vh;
height: 100vh;
background-color: #ffffff;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
padding: 30px;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.screen-content { .screen-content {
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
@ -125,7 +113,7 @@
width: 100%; width: 100%;
padding: 15px; padding: 15px;
border: none; border: none;
border-radius: 20px; border-radius: 8px;
font-size: 1.1rem; font-size: 1.1rem;
font-weight: bold; font-weight: bold;
font-family: 'Vazirmatn', sans-serif; font-family: 'Vazirmatn', sans-serif;
@ -134,12 +122,12 @@
} }
.btn-primary { .btn-primary {
background-color: #6931c9; background-color: #3B604B;
color: #ffffff; color: #ffffff;
} }
.btn-primary:hover { .btn-primary:hover {
background-color: #7745ce; background-color: #3B604B;
} }
</style> </style>
</head> </head>
@ -149,24 +137,24 @@
<div class="screen-content"> <div class="screen-content">
<div class="message-section"> <div class="message-section">
<div class="success-icon">&#10003;</div> <div ><img src="{% static "image/pg/tik.png" %}" alt="success"></div>
<p class="title">پرداخت موفق</p> <p class="title">پرداخت موفق</p>
<p class="subtitle">پرداخت با موفقیت انجام شد.</p>
<hr class="divider"> <hr class="divider">
<div class="amount-row"> <div class="amount-row">
<span class="amount-label">مقدار پرداخت شده:</span> <span class="amount-label">مبلغ شارژ</span>
<span class="amount-value">{{ object.amount }} ریال</span> <span class="amount-value">{{ object.amount }} تومان</span>
</div> </div>
<a href="https://winsoo.ir" class="placeholder-link">وینسو</a> <a href="https://winsoo.ir" class="placeholder-link">winsoo</a>
</div> </div>
<div class="button-container"> <div class="button-container">
<form action="{{ request.get_full_path }}" method="post" enctype="multipart/form-data"> <form action="{{ request.get_full_path }}" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<button class="btn btn-primary" name="redirect-to-app" value="true">بازگشت به صفحه اصلی</button> <button class="btn btn-primary" name="redirect-to-app" value="true">بازگشت به وینسو</button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>