Skip to content

Commit 24e9d4c

Browse files
authored
Create Online-Payment-Gateway-Simulator.py
1 parent 9431694 commit 24e9d4c

1 file changed

Lines changed: 263 additions & 0 deletions

File tree

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
import threading
2+
import webbrowser
3+
import tkinter as tk
4+
from dataclasses import dataclass
5+
from typing import List
6+
import time
7+
import random
8+
9+
import ttkbootstrap as tb
10+
from ttkbootstrap.constants import *
11+
from ttkbootstrap.widgets.scrolled import ScrolledText
12+
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
13+
import matplotlib.pyplot as plt
14+
15+
# ---------------- CONFIG ---------------- #
16+
UPDATE_INTERVAL = 2 # seconds between auto transactions
17+
PROCESSING_DELAY = 1 # seconds to simulate network processing
18+
19+
# Payment methods with success probabilities
20+
PAYMENT_METHODS = {
21+
"Credit Card": 0.85,
22+
"UPI": 0.95,
23+
"Wallet": 0.9
24+
}
25+
26+
FAILURE_REASONS = [
27+
"Insufficient Funds",
28+
"Network Error",
29+
"Card Expired",
30+
"Payment Gateway Timeout",
31+
"Invalid Credentials"
32+
]
33+
34+
# ---------------- GLOBAL STATE ---------------- #
35+
payment_active = False
36+
transaction_history: List["Transaction"] = []
37+
38+
# ---------------- DATA STRUCTURE ---------------- #
39+
@dataclass(frozen=True)
40+
class Transaction:
41+
timestamp: str
42+
method: str
43+
amount: float
44+
status: str
45+
reference_id: str
46+
failure_reason: str = "" # Optional
47+
48+
# ---------------- PAYMENT SIMULATION ---------------- #
49+
def generate_transaction(method=None, amount=None) -> Transaction:
50+
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
51+
if method is None:
52+
method = random.choice(list(PAYMENT_METHODS.keys()))
53+
if amount is None:
54+
amount = round(random.uniform(5, 500), 2)
55+
status = "⏳ Pending"
56+
reference_id = f"{method[:2].upper()}{random.randint(100000,999999)}"
57+
return Transaction(timestamp, method, amount, status, reference_id)
58+
59+
def finalize_transaction(txn: Transaction):
60+
success_prob = PAYMENT_METHODS[txn.method]
61+
if random.random() < success_prob:
62+
return Transaction(txn.timestamp, txn.method, txn.amount, "✅ Success", txn.reference_id)
63+
else:
64+
reason = random.choice(FAILURE_REASONS)
65+
return Transaction(txn.timestamp, txn.method, txn.amount, "❌ Failed", txn.reference_id, failure_reason=reason)
66+
67+
# ---------------- PROCESSING THREAD ---------------- #
68+
def processing_loop():
69+
global payment_active
70+
while payment_active:
71+
txn = generate_transaction()
72+
transaction_history.append(txn)
73+
app.after(0, lambda t=txn: display_transaction(t))
74+
time.sleep(PROCESSING_DELAY)
75+
76+
# Finalize the pending transaction
77+
finalized_txn = finalize_transaction(txn)
78+
transaction_history[-1] = finalized_txn
79+
app.after(0, lambda t=finalized_txn: update_transaction_display(t))
80+
time.sleep(UPDATE_INTERVAL - PROCESSING_DELAY)
81+
82+
# ---------------- UI HELPERS ---------------- #
83+
def format_transaction_text(txn: Transaction) -> str:
84+
base = f"💰 {txn.timestamp}\nMethod: {txn.method}\nAmount: ${txn.amount}\nStatus: {txn.status}\nRef: {txn.reference_id}"
85+
if txn.status == "❌ Failed" and txn.failure_reason:
86+
base += f"\nReason: {txn.failure_reason}"
87+
return base + "\n\n"
88+
89+
def display_transaction(txn: Transaction):
90+
text.configure(state="normal")
91+
text.insert("end", format_transaction_text(txn))
92+
text.see("end")
93+
text.configure(state="disabled")
94+
update_stats()
95+
96+
def update_transaction_display(txn: Transaction):
97+
# Update last transaction to finalized status
98+
text.configure(state="normal")
99+
text.delete("end-8l", "end")
100+
text.insert("end", format_transaction_text(txn))
101+
text.see("end")
102+
text.configure(state="disabled")
103+
update_stats()
104+
105+
def open_gateway_docs():
106+
webbrowser.open_new_tab("https://www.example-payment-gateway.com/docs")
107+
108+
# ---------------- STATS & CHART ---------------- #
109+
def update_stats():
110+
success = sum(1 for t in transaction_history if t.status == "✅ Success")
111+
failed = sum(1 for t in transaction_history if t.status == "❌ Failed")
112+
pending = sum(1 for t in transaction_history if t.status == "⏳ Pending")
113+
stats_label.config(text=f"✅ {success}{failed}{pending}")
114+
115+
# Update pie chart safely
116+
ax.clear()
117+
labels = ["Success", "Failed", "Pending"]
118+
sizes = [success, failed, pending]
119+
colors = ["green", "red", "orange"]
120+
121+
if sum(sizes) == 0:
122+
# Draw a blank circle instead of pie chart
123+
ax.text(0.5, 0.5, "No Transactions", ha="center", va="center", fontsize=12)
124+
ax.axis("off")
125+
else:
126+
ax.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90)
127+
128+
canvas.draw()
129+
130+
# ---------------- CONTROL FUNCTIONS ---------------- #
131+
def start_processing():
132+
global payment_active
133+
if payment_active:
134+
return
135+
payment_active = True
136+
status_label.config(text="🟢 Payment Processing Active", bootstyle="success")
137+
threading.Thread(target=processing_loop, daemon=True).start()
138+
139+
def stop_processing():
140+
global payment_active
141+
payment_active = False
142+
status_label.config(text="🔴 Payment Processing Stopped", bootstyle="danger")
143+
144+
def clear_history():
145+
transaction_history.clear()
146+
text.configure(state="normal")
147+
text.delete("1.0", "end")
148+
text.configure(state="disabled")
149+
update_stats()
150+
151+
# ---------------- MANUAL PAYMENT SUBMISSION ---------------- #
152+
def submit_payment():
153+
method = method_var.get()
154+
try:
155+
amount = float(amount_entry.get())
156+
if amount <= 0:
157+
raise ValueError
158+
except ValueError:
159+
tb.messagebox.showerror("Invalid Amount", "Please enter a valid positive number for amount.")
160+
return
161+
162+
txn = generate_transaction(method, amount)
163+
transaction_history.append(txn)
164+
display_transaction(txn)
165+
166+
# Simulate processing delay in background
167+
def finalize():
168+
time.sleep(PROCESSING_DELAY)
169+
finalized_txn = finalize_transaction(txn)
170+
transaction_history[-1] = finalized_txn
171+
app.after(0, lambda t=finalized_txn: update_transaction_display(t))
172+
threading.Thread(target=finalize, daemon=True).start()
173+
174+
# ---------------- TRANSACTION SEARCH/FILTER ---------------- #
175+
def filter_transactions():
176+
query_method = filter_method_var.get()
177+
query_status = filter_status_var.get().lower()
178+
query_ref = filter_ref_entry.get().strip().lower()
179+
180+
text.configure(state="normal")
181+
text.delete("1.0", "end")
182+
for txn in transaction_history:
183+
if query_method != "All" and txn.method != query_method:
184+
continue
185+
if query_status != "all" and txn.status.lower() != query_status:
186+
continue
187+
if query_ref and query_ref not in txn.reference_id.lower():
188+
continue
189+
text.insert("end", format_transaction_text(txn))
190+
text.configure(state="disabled")
191+
192+
# ---------------- UI SETUP ---------------- #
193+
app = tb.Window(
194+
title="Online Payment Gateway Simulator",
195+
themename="darkly",
196+
size=(1000, 700),
197+
resizable=(True, True),
198+
)
199+
200+
# Top section
201+
top = tb.Frame(app, padding=15)
202+
top.pack(fill=tk.X)
203+
tb.Label(top, text="💳 Online Payment Gateway Simulator", font=("Segoe UI", 18, "bold")).pack(anchor=tk.W)
204+
status_label = tb.Label(top, text="🔴 Payment Processing Stopped", bootstyle="danger")
205+
status_label.pack(anchor=tk.W, pady=5)
206+
207+
# Auto transaction buttons
208+
btn_frame = tb.Frame(app)
209+
btn_frame.pack(fill=tk.X, pady=5)
210+
tb.Button(btn_frame, text="▶ Start Auto Transactions", bootstyle="success", command=start_processing).pack(side=tk.LEFT, padx=5)
211+
tb.Button(btn_frame, text="⏹ Stop Auto Transactions", bootstyle="danger", command=stop_processing).pack(side=tk.LEFT, padx=5)
212+
tb.Button(btn_frame, text="📄 Docs", bootstyle="info", command=open_gateway_docs).pack(side=tk.LEFT, padx=5)
213+
tb.Button(btn_frame, text="🧹 Clear", bootstyle="warning", command=clear_history).pack(side=tk.LEFT, padx=5)
214+
215+
# Manual payment section
216+
manual_frame = tb.Labelframe(app, text="Manual Payment Submission", padding=10)
217+
manual_frame.pack(fill=tk.X, pady=10)
218+
method_var = tk.StringVar(value="Credit Card")
219+
tb.Label(manual_frame, text="Payment Method:").pack(side=tk.LEFT, padx=5)
220+
tb.OptionMenu(manual_frame, method_var, *PAYMENT_METHODS.keys()).pack(side=tk.LEFT, padx=5)
221+
tb.Label(manual_frame, text="Amount:").pack(side=tk.LEFT, padx=5)
222+
amount_entry = tb.Entry(manual_frame, width=10)
223+
amount_entry.pack(side=tk.LEFT, padx=5)
224+
amount_entry.insert(0, "100")
225+
tb.Button(manual_frame, text="💳 Submit Payment", bootstyle="primary", command=submit_payment).pack(side=tk.LEFT, padx=10)
226+
227+
# Transaction filter/search section
228+
filter_frame = tb.Labelframe(app, text="Search / Filter Transactions", padding=10)
229+
filter_frame.pack(fill=tk.X, pady=10)
230+
filter_method_var = tk.StringVar(value="All")
231+
tb.Label(filter_frame, text="Method:").pack(side=tk.LEFT, padx=5)
232+
tb.OptionMenu(filter_frame, filter_method_var, "All", *PAYMENT_METHODS.keys()).pack(side=tk.LEFT, padx=5)
233+
filter_status_var = tk.StringVar(value="All")
234+
tb.Label(filter_frame, text="Status:").pack(side=tk.LEFT, padx=5)
235+
tb.OptionMenu(filter_frame, filter_status_var, "All", "✅ Success", "❌ Failed", "⏳ Pending").pack(side=tk.LEFT, padx=5)
236+
tb.Label(filter_frame, text="Reference ID:").pack(side=tk.LEFT, padx=5)
237+
filter_ref_entry = tb.Entry(filter_frame, width=15)
238+
filter_ref_entry.pack(side=tk.LEFT, padx=5)
239+
tb.Button(filter_frame, text="🔍 Filter", bootstyle="info", command=filter_transactions).pack(side=tk.LEFT, padx=10)
240+
241+
# Transaction log
242+
result_frame = tb.Frame(app)
243+
result_frame.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
244+
result_box = ScrolledText(result_frame)
245+
result_box.pack(fill=tk.BOTH, expand=True)
246+
text = result_box.text
247+
text.configure(state="disabled", wrap="word")
248+
249+
# Stats & Pie Chart
250+
stats_frame = tb.Frame(app, padding=10)
251+
stats_frame.pack(fill=tk.BOTH, side=tk.RIGHT, expand=False)
252+
stats_label = tb.Label(stats_frame, text="✅ 0 ❌ 0 ⏳ 0", font=("Segoe UI", 12, "bold"))
253+
stats_label.pack(pady=10)
254+
fig, ax = plt.subplots(figsize=(4,4))
255+
canvas = FigureCanvasTkAgg(fig, master=stats_frame)
256+
canvas.get_tk_widget().pack()
257+
ax.text(0.5, 0.5, "No Transactions", ha="center", va="center", fontsize=12)
258+
ax.axis("off")
259+
260+
canvas.draw()
261+
262+
# Run app
263+
app.mainloop()

0 commit comments

Comments
 (0)