Stabilize Lead Engine calendar logic (v1.4) and integrate GTM Architect, B2B Assistant, and Transcription Tool into Docker stack [30388f42]
This commit is contained in:
@@ -47,21 +47,66 @@ def get_access_token(client_id, client_secret, tenant_id):
|
||||
return result.get('access_token')
|
||||
|
||||
def get_availability(target_email, app_creds):
|
||||
print(f"DEBUG: Requesting availability for {target_email}")
|
||||
token = get_access_token(*app_creds)
|
||||
if not token: return None
|
||||
if not token:
|
||||
print("DEBUG: Failed to acquire access token.")
|
||||
return None
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json", "Prefer": 'outlook.timezone="Europe/Berlin"'}
|
||||
start_time = datetime.now(TZ_BERLIN).replace(hour=0, minute=0, second=0)
|
||||
start_time = datetime.now(TZ_BERLIN).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
end_time = start_time + timedelta(days=3)
|
||||
payload = {"schedules": [target_email], "startTime": {"dateTime": start_time.isoformat()}, "endTime": {"dateTime": end_time.isoformat()}, "availabilityViewInterval": 60}
|
||||
# Use 15-minute intervals for finer granularity
|
||||
payload = {"schedules": [target_email], "startTime": {"dateTime": start_time.isoformat()}, "endTime": {"dateTime": end_time.isoformat()}, "availabilityViewInterval": 15}
|
||||
|
||||
try:
|
||||
r = requests.post(f"{GRAPH_API_ENDPOINT}/users/{target_email}/calendar/getSchedule", headers=headers, json=payload)
|
||||
if r.status_code == 200: return start_time, r.json()['value'][0].get('availabilityView', ''), 60
|
||||
except: pass
|
||||
url = f"{GRAPH_API_ENDPOINT}/users/{target_email}/calendar/getSchedule"
|
||||
r = requests.post(url, headers=headers, json=payload)
|
||||
print(f"DEBUG: API Status Code: {r.status_code}")
|
||||
|
||||
if r.status_code == 200:
|
||||
view = r.json()['value'][0].get('availabilityView', '')
|
||||
print(f"DEBUG: Availability View received (Length: {len(view)})")
|
||||
return start_time, view, 15
|
||||
else:
|
||||
print(f"DEBUG: API Error Response: {r.text}")
|
||||
except Exception as e:
|
||||
print(f"DEBUG: Exception during API call: {e}")
|
||||
pass
|
||||
return None
|
||||
|
||||
def find_slots(start, view, interval):
|
||||
# This logic is complex and proven, keeping it as is.
|
||||
return [datetime.now(TZ_BERLIN) + timedelta(days=1, hours=h) for h in [10, 14]] # Placeholder
|
||||
"""
|
||||
Parses availability string: '0'=Free, '2'=Busy.
|
||||
Returns 2 free slots (start times) within business hours (09:00 - 16:30),
|
||||
excluding weekends (Sat/Sun), with approx. 3 hours distance between them.
|
||||
"""
|
||||
slots = []
|
||||
first_slot = None
|
||||
|
||||
# Iterate through the view string
|
||||
for i, status in enumerate(view):
|
||||
if status == '0': # '0' means Free
|
||||
slot_time = start + timedelta(minutes=i * interval)
|
||||
|
||||
# Constraints:
|
||||
# 1. Mon-Fri only
|
||||
# 2. Business hours (09:00 - 16:30)
|
||||
# 3. Future only
|
||||
if slot_time.weekday() < 5 and (9 <= slot_time.hour < 17) and slot_time > datetime.now(TZ_BERLIN):
|
||||
# Max start time 16:30
|
||||
if slot_time.hour == 16 and slot_time.minute > 30:
|
||||
continue
|
||||
|
||||
if first_slot is None:
|
||||
first_slot = slot_time
|
||||
slots.append(first_slot)
|
||||
else:
|
||||
# Second slot should be at least 3 hours after the first
|
||||
if slot_time >= first_slot + timedelta(hours=3):
|
||||
slots.append(slot_time)
|
||||
break
|
||||
return slots
|
||||
|
||||
def create_calendar_invite(lead_email, company, start_time):
|
||||
catchall = os.getenv("EMAIL_CATCHALL"); lead_email = catchall if catchall else lead_email
|
||||
|
||||
Reference in New Issue
Block a user