Mr-Help commited on
Commit
ff24891
·
verified ·
1 Parent(s): fa969c2

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +29 -163
main.py CHANGED
@@ -1,172 +1,38 @@
 
1
  from fastapi import FastAPI, Request
2
- import logging
3
- import json
4
- from datetime import datetime, timedelta
5
- from typing import Any, Dict, List, Tuple
6
 
7
  app = FastAPI()
8
 
9
- logging.basicConfig(
10
- level=logging.INFO,
11
- format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
 
 
 
 
12
  )
13
 
14
- log = logging.getLogger("supabase-receiver")
15
-
16
-
17
- def extract_records(payload: Any) -> List[Dict]:
18
- """
19
- نحاول نطلع records من البودي بأي شكل محتمل:
20
- - { "record": {...} }
21
- - { "records": [ {...}, {...} ] }
22
- - [ {...}, {...} ]
23
- - أو dict واحد نعتبره row واحد.
24
- """
25
- if isinstance(payload, dict):
26
- if "record" in payload and isinstance(payload["record"], dict):
27
- return [payload["record"]]
28
- if "records" in payload and isinstance(payload["records"], list):
29
- return [r for r in payload["records"] if isinstance(r, dict)]
30
- return [payload]
31
- elif isinstance(payload, list):
32
- return [r for r in payload if isinstance(r, dict)]
33
- else:
34
- return []
35
-
36
-
37
- def parse_lead_timestamp(raw_ts: str) -> Tuple[str, str]:
38
- """
39
- يحوّل lead_timestamp إلى:
40
- - deadline: تاريخ ووقت +24 ساعة (string)
41
- - due_date: تاريخ فقط (string)
42
- لو مفيش timestamp هنستخدم الوقت الحالي.
43
- """
44
- if not raw_ts:
45
- now = datetime.utcnow()
46
- deadline = now + timedelta(hours=24)
47
- else:
48
- ts = raw_ts.replace("Z", "+00:00")
49
- dt = datetime.fromisoformat(ts)
50
- deadline = dt + timedelta(hours=24)
51
-
52
- deadline_str = deadline.strftime("%Y-%m-%d %H:%M:%S")
53
- due_date = deadline.date().isoformat()
54
- return deadline_str, due_date
55
-
56
-
57
- def build_odoo_payload_from_lead(lead: Dict) -> Dict:
58
- """
59
- نفس المابّينج تقريبًا اللي هنعمله في السيرفر الحقيقي،
60
- بس هنا عشان نطبع كود جاهز للتست لوكال.
61
- """
62
- full_name = lead.get("full_name") or lead.get("name") or "Lead"
63
- email = lead.get("email") or ""
64
- phone = lead.get("phone") or ""
65
- city_from_lead = lead.get("city") or False
66
- platform = lead.get("platform") or ""
67
-
68
- lead_ts = lead.get("lead_timestamp")
69
- deadline_str, due_date = parse_lead_timestamp(lead_ts)
70
-
71
- body = {
72
- "name": full_name,
73
- "date_deadline": deadline_str,
74
- "user_id": lead.get("lead_id"), # زي ما اتفقنا
75
- "active": True,
76
- "kanban_state": "grey",
77
- "type": "opportunity",
78
- "stage_id": 18,
79
- "tag_ids": [],
80
- "color": 0,
81
- "adgroup_name": lead.get("campaign_name"),
82
- "adset_name": lead.get("adset_name"),
83
- "ad_name": lead.get("ad_name", ""),
84
- "lead_timestamp": lead_ts,
85
- "source_id": None,
86
- "source_company": "Jizan",
87
- "due_date": due_date,
88
- "call_logs": "",
89
- "call_log_result": "",
90
- "age": None,
91
- "specialty_id": False,
92
- "gender_id": False,
93
- "city_ar": city_from_lead or "غير محدد",
94
- "email_from": email,
95
- "city": False,
96
- "phone": phone,
97
- "platform": platform,
98
- }
99
- return body
100
-
101
-
102
- def build_python_snippet_for_odoo(payload: Dict) -> str:
103
- """
104
- يبني كود Python جاهز تقدر تاخده كوبي-بيست،
105
- وتستعمله لوكال عشان يبعته لـ Odoo.
106
- """
107
- payload_json = json.dumps(payload, ensure_ascii=False, indent=4)
108
 
109
- snippet = f'''import requests
 
 
 
 
 
 
110
 
111
- ODOO_LEAD_URL = "https://odoo.binrushd.care/api/crm.lead"
112
- token = "PASTE_TOKEN_HERE" # حط التوكن اللي جالك من /api/auth/token
113
-
114
- payload = {payload_json}
115
-
116
- headers = {{
117
- "Authorization": f"Bearer {{token}}",
118
- "Content-Type": "application/json",
119
- }}
120
-
121
- resp = requests.post(ODOO_LEAD_URL, json=payload, headers=headers, timeout=30)
122
- print(resp.status_code)
123
- print(resp.text)
124
- '''
125
- return snippet
126
-
127
-
128
- @app.post("/")
129
- async def receive_from_supabase(request: Request):
130
- """
131
- Endpoint رئيسي تستقبله Supabase Webhook.
132
- - يطبع البودي بالكامل في اللوج
133
- - يطلع أول record
134
- - يبني منه payload لـ Odoo
135
- - يطبع كود Python في اللوج تقدر تاخده كوبي-بيست وتجرّبه لوكال.
136
- """
137
  try:
138
- body = await request.json()
139
- except Exception as e:
140
- log.error("Failed to parse JSON body: %s", e)
141
- return {"status": "error", "detail": f"Invalid JSON: {e}"}
142
-
143
- # 1) طباعة البودي الخام
144
- log.info("=== RAW WEBHOOK BODY FROM SUPABASE ===")
145
- log.info(json.dumps(body, ensure_ascii=False, indent=2))
146
-
147
- # 2) استخراج records
148
- records = extract_records(body)
149
- if not records:
150
- log.warning("No records found in webhook payload.")
151
- return {"status": "ok", "note": "no records in payload"}
152
-
153
- first = records[0]
154
- log.info("=== FIRST RECORD (lead) ===")
155
- log.info(json.dumps(first, ensure_ascii=False, indent=2))
156
-
157
- # 3) بناء payload لـ Odoo
158
- odoo_payload = build_odoo_payload_from_lead(first)
159
- log.info("=== ODOO PAYLOAD (dict) ===")
160
- log.info(json.dumps(odoo_payload, ensure_ascii=False, indent=2))
161
-
162
- # 4) توليد كود Python جاهز
163
- python_snippet = build_python_snippet_for_odoo(odoo_payload)
164
- log.info("=== PYTHON SNIPPET TO SEND THIS LEAD TO ODOO ===")
165
- log.info("\n%s", python_snippet)
166
-
167
- # 5) نرجّع response بسيط
168
- return {
169
- "status": "ok",
170
- "records_received": len(records),
171
- "preview_odoo_payload": odoo_payload,
172
- }
 
1
+ import requests
2
  from fastapi import FastAPI, Request
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+
5
+ GAS_WEBAPP_URL = "https://script.google.com/macros/s/AKfycb......../exec"
 
6
 
7
  app = FastAPI()
8
 
9
+ # ✅ CORS مفتوح للديمو
10
+ app.add_middleware(
11
+ CORSMiddleware,
12
+ allow_origins=["*"],
13
+ allow_credentials=False,
14
+ allow_methods=["POST", "OPTIONS"],
15
+ allow_headers=["*"],
16
  )
17
 
18
+ @app.post("/complaints")
19
+ async def complaints_proxy(req: Request):
20
+ payload = await req.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ # forward to GAS (server-to-server)
23
+ gas_resp = requests.post(
24
+ GAS_WEBAPP_URL,
25
+ json=payload,
26
+ headers={"Content-Type": "application/json"},
27
+ timeout=30
28
+ )
29
 
30
+ # GAS ممكن يرجع JSON أو Text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  try:
32
+ return gas_resp.json()
33
+ except Exception:
34
+ return {
35
+ "ok": False,
36
+ "error": "GAS returned non-JSON",
37
+ "raw": gas_resp.text
38
+ }