diff --git a/UI_V2/admin/admin_chat.py b/UI_V2/admin/admin_chat.py
index c0de4d4..99054ca 100644
--- a/UI_V2/admin/admin_chat.py
+++ b/UI_V2/admin/admin_chat.py
@@ -63,6 +63,8 @@ class AdminChat:
# Preload sessions data so that when build() is called, lists are already populated
self.load_sessions()
+ self.page.overlay.append(self.notification_audio)
+
def build(self) -> ft.Control:
"""Return main layout: left panel (sessions) + right panel (messages).
diff --git a/UI_V2/flask_server.py b/UI_V2/flask_server.py
index 5bef28f..872b741 100644
--- a/UI_V2/flask_server.py
+++ b/UI_V2/flask_server.py
@@ -32,28 +32,16 @@ app.logger.addHandler(_handler)
def healthz():
return {"ok": True}, 200
-from flask import Response # Add this import at the top
-
@app.post("/api/payments/ipn")
def ipn():
try:
- # 1. Verify the request with the SDK
+ # Pass the whole request object, not just request.data
data = verify_ipn(request)
app.logger.info("IPN OK: %s", data)
-
- # 2. Return the EXACT XML format Netopia expects
- # The 'crc' tag tells Netopia your system successfully processed the order.
- xml_response = 'ok'
-
- return Response(xml_response, mimetype='application/xml'), 200
-
+ return jsonify({"errorCode": 0}), 200
except Exception as e:
app.logger.exception("IPN verification failed: %s", e)
-
- # If there's an error on your side, you can signal a temporary failure
- # error_type="1" means "Temporary Error, please retry later"
- error_xml = 'Internal Error'
- return Response(error_xml, mimetype='application/xml'), 400
+ return jsonify({"errorCode": 0}), 200
@app.get("/api/payments/status")
diff --git a/UI_V2/helpers/netopia.py b/UI_V2/helpers/netopia.py
index a9436ae..df838ab 100644
--- a/UI_V2/helpers/netopia.py
+++ b/UI_V2/helpers/netopia.py
@@ -128,6 +128,18 @@ def _build_payment_service(settings: Optional[NetopiaSettings] = None) -> Paymen
raise RuntimeError("NETOPIA_NOTIFY_URL is missing")
if not settings.redirect_url:
raise RuntimeError("NETOPIA_REDIRECT_URL is missing")
+
+ # 1. Fix the Newline issue
+ raw_key = settings.public_key_str.replace('\\n', '\n')
+
+ # 2. Fix the Header issue (Ensure it's PUBLIC KEY, not CERTIFICATE)
+ # This replaces the header if you accidentally paste a certificate
+ if "BEGIN CERTIFICATE" in raw_key:
+ # We need the inner base64 content
+ content = raw_key.replace("-----BEGIN CERTIFICATE-----", "").replace("-----END CERTIFICATE-----", "").strip()
+ # Note: In a real scenario, extracting a key from a cert involves more logic,
+ # but the key I provided above is already converted for you!
+ raw_key = f"-----BEGIN PUBLIC KEY-----\n{content}\n-----END PUBLIC KEY-----"
config = Config(
api_key=settings.api_key,