Spaces:
Sleeping
Sleeping
verify
Browse files- core/models.py +1 -0
- routers/blink.py +1 -0
- routers/payments.py +12 -0
- templates/index.html +15 -2
core/models.py
CHANGED
|
@@ -178,6 +178,7 @@ class PaymentTransaction(Base):
|
|
| 178 |
|
| 179 |
# Status tracking
|
| 180 |
status = Column(String(20), default="created", index=True) # created, paid, failed, refunded
|
|
|
|
| 181 |
|
| 182 |
# Timestamps
|
| 183 |
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
| 178 |
|
| 179 |
# Status tracking
|
| 180 |
status = Column(String(20), default="created", index=True) # created, paid, failed, refunded
|
| 181 |
+
verified_by = Column(String(20), nullable=True) # client, webhook, or both
|
| 182 |
|
| 183 |
# Timestamps
|
| 184 |
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
routers/blink.py
CHANGED
|
@@ -258,6 +258,7 @@ async def get_payment_transactions(
|
|
| 258 |
"amount_rupees": item.amount_paise / 100,
|
| 259 |
"currency": item.currency,
|
| 260 |
"status": item.status,
|
|
|
|
| 261 |
"error_message": item.error_message,
|
| 262 |
"created_at": item.created_at.isoformat() if item.created_at else None,
|
| 263 |
"paid_at": item.paid_at.isoformat() if item.paid_at else None
|
|
|
|
| 258 |
"amount_rupees": item.amount_paise / 100,
|
| 259 |
"currency": item.currency,
|
| 260 |
"status": item.status,
|
| 261 |
+
"verified_by": item.verified_by,
|
| 262 |
"error_message": item.error_message,
|
| 263 |
"created_at": item.created_at.isoformat() if item.created_at else None,
|
| 264 |
"paid_at": item.paid_at.isoformat() if item.paid_at else None
|
routers/payments.py
CHANGED
|
@@ -298,6 +298,12 @@ async def verify_payment(
|
|
| 298 |
transaction.razorpay_signature = request.razorpay_signature
|
| 299 |
transaction.paid_at = datetime.utcnow()
|
| 300 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
# Add credits to user
|
| 302 |
user.credits += transaction.credits_amount
|
| 303 |
|
|
@@ -389,6 +395,12 @@ async def razorpay_webhook(
|
|
| 389 |
transaction.gateway_payment_id = payment_id
|
| 390 |
transaction.paid_at = datetime.utcnow()
|
| 391 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
# Find user and add credits
|
| 393 |
user_result = await db.execute(
|
| 394 |
select(User).where(User.user_id == transaction.user_id)
|
|
|
|
| 298 |
transaction.razorpay_signature = request.razorpay_signature
|
| 299 |
transaction.paid_at = datetime.utcnow()
|
| 300 |
|
| 301 |
+
# Track who verified - if webhook already set it, mark as "both"
|
| 302 |
+
if transaction.verified_by == "webhook":
|
| 303 |
+
transaction.verified_by = "both"
|
| 304 |
+
else:
|
| 305 |
+
transaction.verified_by = "client"
|
| 306 |
+
|
| 307 |
# Add credits to user
|
| 308 |
user.credits += transaction.credits_amount
|
| 309 |
|
|
|
|
| 395 |
transaction.gateway_payment_id = payment_id
|
| 396 |
transaction.paid_at = datetime.utcnow()
|
| 397 |
|
| 398 |
+
# Track who verified - if client already set it, mark as "both"
|
| 399 |
+
if transaction.verified_by == "client":
|
| 400 |
+
transaction.verified_by = "both"
|
| 401 |
+
else:
|
| 402 |
+
transaction.verified_by = "webhook"
|
| 403 |
+
|
| 404 |
# Find user and add credits
|
| 405 |
user_result = await db.execute(
|
| 406 |
select(User).where(User.user_id == transaction.user_id)
|
templates/index.html
CHANGED
|
@@ -470,13 +470,14 @@
|
|
| 470 |
<th>Credits</th>
|
| 471 |
<th>Amount</th>
|
| 472 |
<th>Status</th>
|
|
|
|
| 473 |
<th>Created At</th>
|
| 474 |
<th>Paid At</th>
|
| 475 |
</tr>
|
| 476 |
</thead>
|
| 477 |
<tbody id="paymentsBody">
|
| 478 |
<tr>
|
| 479 |
-
<td colspan="
|
| 480 |
<div class="loading">
|
| 481 |
<div class="spinner"></div>Loading...
|
| 482 |
</div>
|
|
@@ -699,9 +700,20 @@
|
|
| 699 |
function renderPaymentsTable(items) {
|
| 700 |
const tbody = document.getElementById('paymentsBody');
|
| 701 |
if (items.length === 0) {
|
| 702 |
-
tbody.innerHTML = '<tr><td colspan="
|
| 703 |
return;
|
| 704 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 705 |
tbody.innerHTML = items.map(item => `
|
| 706 |
<tr>
|
| 707 |
<td>${item.id}</td>
|
|
@@ -714,6 +726,7 @@
|
|
| 714 |
<td><span class="credits-badge">${item.credits_amount}</span></td>
|
| 715 |
<td>₹${item.amount_rupees}</td>
|
| 716 |
<td><span class="status-badge status-${item.status === 'paid' ? 'success' : item.status === 'failed' ? 'failed' : 'queued'}">${item.status}</span></td>
|
|
|
|
| 717 |
<td class="timestamp">${item.created_at ? new Date(item.created_at).toLocaleString() : '-'}</td>
|
| 718 |
<td class="timestamp">${item.paid_at ? new Date(item.paid_at).toLocaleString() : '-'}</td>
|
| 719 |
</tr>
|
|
|
|
| 470 |
<th>Credits</th>
|
| 471 |
<th>Amount</th>
|
| 472 |
<th>Status</th>
|
| 473 |
+
<th>Verified By</th>
|
| 474 |
<th>Created At</th>
|
| 475 |
<th>Paid At</th>
|
| 476 |
</tr>
|
| 477 |
</thead>
|
| 478 |
<tbody id="paymentsBody">
|
| 479 |
<tr>
|
| 480 |
+
<td colspan="13">
|
| 481 |
<div class="loading">
|
| 482 |
<div class="spinner"></div>Loading...
|
| 483 |
</div>
|
|
|
|
| 700 |
function renderPaymentsTable(items) {
|
| 701 |
const tbody = document.getElementById('paymentsBody');
|
| 702 |
if (items.length === 0) {
|
| 703 |
+
tbody.innerHTML = '<tr><td colspan="13"><div class="empty-state">No payment transactions found</div></td></tr>';
|
| 704 |
return;
|
| 705 |
}
|
| 706 |
+
|
| 707 |
+
const getVerifiedByBadge = (value) => {
|
| 708 |
+
if (!value) return '-';
|
| 709 |
+
const colors = {
|
| 710 |
+
'client': 'background: rgba(59, 130, 246, 0.2); color: #3b82f6;',
|
| 711 |
+
'webhook': 'background: rgba(234, 179, 8, 0.2); color: #eab308;',
|
| 712 |
+
'both': 'background: rgba(34, 197, 94, 0.2); color: #22c55e;'
|
| 713 |
+
};
|
| 714 |
+
return `<span class="status-badge" style="${colors[value] || ''}">${value}</span>`;
|
| 715 |
+
};
|
| 716 |
+
|
| 717 |
tbody.innerHTML = items.map(item => `
|
| 718 |
<tr>
|
| 719 |
<td>${item.id}</td>
|
|
|
|
| 726 |
<td><span class="credits-badge">${item.credits_amount}</span></td>
|
| 727 |
<td>₹${item.amount_rupees}</td>
|
| 728 |
<td><span class="status-badge status-${item.status === 'paid' ? 'success' : item.status === 'failed' ? 'failed' : 'queued'}">${item.status}</span></td>
|
| 729 |
+
<td>${getVerifiedByBadge(item.verified_by)}</td>
|
| 730 |
<td class="timestamp">${item.created_at ? new Date(item.created_at).toLocaleString() : '-'}</td>
|
| 731 |
<td class="timestamp">${item.paid_at ? new Date(item.paid_at).toLocaleString() : '-'}</td>
|
| 732 |
</tr>
|