Phoe2004 commited on
Commit
e5d22f7
·
verified ·
1 Parent(s): eeee5d6

Rename payment.html to payment.py

Browse files
Files changed (2) hide show
  1. payment.html +0 -74
  2. payment.py +64 -0
payment.html DELETED
@@ -1,74 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width,initial-scale=1.0">
6
- <title>Buy Coins - Recap Studio</title>
7
- <link rel="preconnect" href="https://fonts.googleapis.com">
8
- <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
9
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
10
- <style>
11
- *{margin:0;padding:0;box-sizing:border-box}
12
- body{font-family:'Plus Jakarta Sans',sans-serif;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);min-height:100vh;padding:20px}
13
- .container{max-width:500px;margin:0 auto}
14
- .header{text-align:center;margin-bottom:24px}
15
- .header h1{color:white;font-size:1.8rem}
16
- .packages{display:grid;gap:12px;margin-bottom:24px}
17
- .package{background:white;border-radius:16px;padding:16px;display:flex;align-items:center;justify-content:space-between;cursor:pointer;border:2px solid transparent;transition:all .2s}
18
- .package.selected{border-color:#5b4cf5;background:#f5f3ff}
19
- .package-info h3{font-size:1rem;margin-bottom:4px}
20
- .package-info .coins{font-size:1.3rem;font-weight:800;color:#5b4cf5}
21
- .package-info .price{font-size:.75rem;color:#666}
22
- .radio{width:22px;height:22px;border-radius:50%;border:2px solid #ddd;background:white}
23
- .package.selected .radio{border-color:#5b4cf5;background:#5b4cf5;box-shadow:inset 0 0 0 4px white}
24
- .payment-info{background:white;border-radius:16px;padding:20px;margin-bottom:20px}
25
- .payment-info h3{margin-bottom:12px;font-size:1rem}
26
- .bank-details{background:#f8f9fa;border-radius:12px;padding:16px;margin-bottom:16px}
27
- .bank-row{display:flex;justify-content:space-between;margin-bottom:8px;font-size:.85rem}
28
- .bank-label{color:#666}
29
- .bank-value{font-weight:600;color:#333}
30
- .copy-btn{background:#e9ecef;border:none;padding:4px 10px;border-radius:6px;font-size:.7rem;cursor:pointer;margin-left:8px}
31
- .slip-area{margin-top:16px}
32
- .slip-label{font-size:.8rem;font-weight:600;margin-bottom:8px;display:block}
33
- .slip-input{width:100%;padding:12px;border:1.5px solid #e2e4ee;border-radius:10px;font-family:inherit;cursor:pointer}
34
- .slip-preview{margin-top:12px;max-width:100%;max-height:200px;display:none;border-radius:8px}
35
- .submit-btn{width:100%;padding:14px;background:linear-gradient(135deg,#5b4cf5,#8b5cf6);border:none;border-radius:12px;color:white;font-weight:700;font-size:1rem;cursor:pointer;transition:.2s;margin-top:16px}
36
- .submit-btn:disabled{opacity:.5;cursor:not-allowed}
37
- .back-btn{background:transparent;border:1px solid white;color:white;padding:10px;border-radius:10px;width:100%;font-size:.85rem;cursor:pointer;margin-top:12px}
38
- .toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:#333;color:white;padding:10px 20px;border-radius:30px;font-size:.8rem;opacity:0;transition:.2s;pointer-events:none}
39
- .toast.show{opacity:1}
40
- </style>
41
- </head>
42
- <body>
43
- <div class="container">
44
- <div class="header"><h1>💰 Buy Coins</h1></div>
45
- <div class="packages" id="packages">
46
- <div class="package" data-coins="10" data-price="10,000 MMK" onclick="selectPackage(this)"><div class="package-info"><h3>🥉 Starter</h3><div class="coins">10 Coins</div><div class="price">10,000 MMK</div></div><div class="radio"></div></div>
47
- <div class="package" data-coins="30" data-price="28,000 MMK" onclick="selectPackage(this)"><div class="package-info"><h3>⭐ Basic</h3><div class="coins">30 Coins</div><div class="price">28,000 MMK</div></div><div class="radio"></div></div>
48
- <div class="package" data-coins="60" data-price="58,000 MMK" onclick="selectPackage(this)"><div class="package-info"><h3>🔥 Pro</h3><div class="coins">60 Coins</div><div class="price">58,000 MMK</div></div><div class="radio"></div></div>
49
- <div class="package" data-coins="100" data-price="95,000 MMK" onclick="selectPackage(this)"><div class="package-info"><h3>💎 Unlimited</h3><div class="coins">100 Coins</div><div class="price">95,000 MMK</div></div><div class="radio"></div></div>
50
- </div>
51
- <div class="payment-info">
52
- <h3>💸 Payment Method</h3>
53
- <div class="bank-details">
54
- <div class="bank-row"><span class="bank-label">KBZ Pay</span><span class="bank-value">PHOE SHAN<button class="copy-btn" onclick="copyText('PHOE SHAN')">Copy</button></span></div>
55
- <div class="bank-row"><span class="bank-label">Phone Number</span><span class="bank-value">09679871352<button class="copy-btn" onclick="copyText('09679871352')">Copy</button></span></div>
56
- </div>
57
- <div class="slip-area"><label class="slip-label">📸 Upload Payment Slip (Screenshot)</label><input type="file" id="slipImage" class="slip-input" accept="image/*"><img id="slipPreview" class="slip-preview"></div>
58
- <button class="submit-btn" id="submitBtn" onclick="submitPayment()">📤 Submit Payment</button>
59
- <button class="back-btn" onclick="window.location.href='/app'">← Back to App</button>
60
- </div>
61
- </div>
62
- <div id="toast" class="toast"></div>
63
-
64
- <script>
65
- let selectedPackage=null,selectedCoins=null,selectedPrice=null;
66
- function selectPackage(el){document.querySelectorAll('.package').forEach(p=>p.classList.remove('selected'));el.classList.add('selected');selectedPackage=el;selectedCoins=el.dataset.coins;selectedPrice=el.dataset.price;}
67
- function copyText(t){navigator.clipboard.writeText(t);showToast('✅ Copied: '+t);}
68
- function showToast(m){const t=document.getElementById('toast');t.textContent=m;t.classList.add('show');setTimeout(()=>t.classList.remove('show'),2000);}
69
- document.getElementById('slipImage').addEventListener('change',function(e){const f=e.target.files[0];if(f){const r=new FileReader();r.onload=function(ev){const p=document.getElementById('slipPreview');p.src=ev.target.result;p.style.display='block';};r.readAsDataURL(f);}});
70
- async function submitPayment(){if(!selectedPackage){showToast('❌ Please select a package');return;}const slipFile=document.getElementById('slipImage').files[0];if(!slipFile){showToast('❌ Please upload payment slip');return;}const user=sessionStorage.getItem('recap_user');if(!user){showToast('❌ Please login first');window.location.href='/login';return;}const username=JSON.parse(user).u;const btn=document.getElementById('submitBtn');btn.disabled=true;btn.textContent='⏳ Submitting...';const reader=new FileReader();reader.onload=async function(ev){try{const res=await fetch('/api/payment/submit',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:username,coins:parseInt(selectedCoins),price:selectedPrice,slip_image:ev.target.result})});const data=await res.json();if(data.ok){showToast('✅ Payment submitted! Waiting for admin approval.');setTimeout(()=>{window.location.href='/payment-history';},1500);}else{showToast('❌ '+data.msg);btn.disabled=false;btn.textContent='📤 Submit Payment';}}catch(err){showToast('❌ Network error');btn.disabled=false;btn.textContent='📤 Submit Payment';}};reader.readAsDataURL(slipFile);}
71
- setTimeout(()=>{const fp=document.querySelector('.package');if(fp)selectPackage(fp);},100);
72
- </script>
73
- </body>
74
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
payment.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # payment.py
2
+ import os, json, uuid
3
+ from datetime import datetime
4
+ from pathlib import Path
5
+
6
+ PAYMENT_DB_FILE = str(Path(__file__).parent / 'payments_db.json')
7
+
8
+ def load_payments():
9
+ if not os.path.exists(PAYMENT_DB_FILE):
10
+ return {'payments': []}
11
+ try:
12
+ with open(PAYMENT_DB_FILE, encoding='utf-8') as f:
13
+ return json.load(f)
14
+ except:
15
+ return {'payments': []}
16
+
17
+ def save_payments(db):
18
+ with open(PAYMENT_DB_FILE, 'w', encoding='utf-8') as f:
19
+ json.dump(db, f, ensure_ascii=False, indent=2)
20
+
21
+ def create_payment(username, coins, price, slip_image_data=None):
22
+ db = load_payments()
23
+ payment_id = str(uuid.uuid4())[:8]
24
+ payment = {
25
+ 'id': payment_id,
26
+ 'username': username,
27
+ 'coins': coins,
28
+ 'price': price,
29
+ 'status': 'pending',
30
+ 'created_at': datetime.now().isoformat(),
31
+ 'updated_at': datetime.now().isoformat(),
32
+ 'slip_image': slip_image_data,
33
+ 'admin_note': ''
34
+ }
35
+ db['payments'].insert(0, payment)
36
+ save_payments(db)
37
+ return payment_id
38
+
39
+ def update_payment_status(payment_id, status, admin_note=''):
40
+ db = load_payments()
41
+ for p in db['payments']:
42
+ if p['id'] == payment_id:
43
+ p['status'] = status
44
+ p['updated_at'] = datetime.now().isoformat()
45
+ if admin_note:
46
+ p['admin_note'] = admin_note
47
+ save_payments(db)
48
+ return p
49
+ return None
50
+
51
+ def get_user_payments(username, limit=50):
52
+ db = load_payments()
53
+ return [p for p in db['payments'] if p['username'] == username][:limit]
54
+
55
+ def get_pending_payments():
56
+ db = load_payments()
57
+ return [p for p in db['payments'] if p['status'] == 'pending']
58
+
59
+ def get_payment_by_id(payment_id):
60
+ db = load_payments()
61
+ for p in db['payments']:
62
+ if p['id'] == payment_id:
63
+ return p
64
+ return None