Seth commited on
Commit ·
f1bcbcc
1
Parent(s): a941701
update
Browse files- backend/app/main.py +63 -16
- backend/app/smartlead_client.py +7 -10
backend/app/main.py
CHANGED
|
@@ -480,7 +480,7 @@ async def push_to_smartlead(request: SmartleadPushRequest, db: Session = Depends
|
|
| 480 |
|
| 481 |
# Step 1: Add leads without custom variables (chunk in batches of 50)
|
| 482 |
batch_size = 50
|
| 483 |
-
|
| 484 |
|
| 485 |
for i in range(0, len(leads), batch_size):
|
| 486 |
batch = leads[i:i + batch_size]
|
|
@@ -488,9 +488,45 @@ async def push_to_smartlead(request: SmartleadPushRequest, db: Session = Depends
|
|
| 488 |
lead_batch = [item["lead_data"] for item in batch]
|
| 489 |
try:
|
| 490 |
response = client.add_leads_to_campaign(campaign_id, lead_batch)
|
| 491 |
-
# Store successfully added leads with their custom vars for update
|
| 492 |
-
successfully_added_leads.extend(batch)
|
| 493 |
added_count += len(lead_batch)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 494 |
except Exception as e:
|
| 495 |
# Mark batch as failed
|
| 496 |
for item in batch:
|
|
@@ -501,19 +537,30 @@ async def push_to_smartlead(request: SmartleadPushRequest, db: Session = Depends
|
|
| 501 |
failed_count += 1
|
| 502 |
|
| 503 |
# Step 2: Try to update each successfully added lead with custom variables
|
| 504 |
-
#
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 517 |
|
| 518 |
# Update run record
|
| 519 |
run.status = 'completed'
|
|
|
|
| 480 |
|
| 481 |
# Step 1: Add leads without custom variables (chunk in batches of 50)
|
| 482 |
batch_size = 50
|
| 483 |
+
leads_to_update = [] # Store leads with their lead_ids for updating custom vars
|
| 484 |
|
| 485 |
for i in range(0, len(leads), batch_size):
|
| 486 |
batch = leads[i:i + batch_size]
|
|
|
|
| 488 |
lead_batch = [item["lead_data"] for item in batch]
|
| 489 |
try:
|
| 490 |
response = client.add_leads_to_campaign(campaign_id, lead_batch)
|
|
|
|
|
|
|
| 491 |
added_count += len(lead_batch)
|
| 492 |
+
|
| 493 |
+
# Parse response to extract lead_ids
|
| 494 |
+
# Smartlead API response structure may vary - try common patterns
|
| 495 |
+
if isinstance(response, dict):
|
| 496 |
+
# Check for different response structures
|
| 497 |
+
added_leads = response.get('added_leads') or response.get('leads') or response.get('data') or []
|
| 498 |
+
|
| 499 |
+
# Map emails to lead_ids from response
|
| 500 |
+
email_to_lead_id = {}
|
| 501 |
+
if isinstance(added_leads, list):
|
| 502 |
+
for lead_info in added_leads:
|
| 503 |
+
if isinstance(lead_info, dict):
|
| 504 |
+
lead_id = lead_info.get('lead_id') or lead_info.get('id') or lead_info.get('leadId')
|
| 505 |
+
lead_email = lead_info.get('email') or lead_info.get('email_address')
|
| 506 |
+
if lead_id and lead_email:
|
| 507 |
+
email_to_lead_id[lead_email] = lead_id
|
| 508 |
+
|
| 509 |
+
# Store leads with their lead_ids for updating
|
| 510 |
+
for item in batch:
|
| 511 |
+
lead_email = item.get('email')
|
| 512 |
+
lead_id = email_to_lead_id.get(lead_email)
|
| 513 |
+
if lead_id and item.get('custom_vars'):
|
| 514 |
+
leads_to_update.append({
|
| 515 |
+
'lead_id': lead_id,
|
| 516 |
+
'email': lead_email,
|
| 517 |
+
'custom_vars': item['custom_vars']
|
| 518 |
+
})
|
| 519 |
+
# If response doesn't have lead_ids, try to match by email order
|
| 520 |
+
if not email_to_lead_id and len(batch) == len(lead_batch):
|
| 521 |
+
# Store with email for now - we'll try to get lead_id another way
|
| 522 |
+
for item in batch:
|
| 523 |
+
if item.get('custom_vars'):
|
| 524 |
+
leads_to_update.append({
|
| 525 |
+
'lead_id': None, # Will try to get from email lookup
|
| 526 |
+
'email': item.get('email'),
|
| 527 |
+
'custom_vars': item['custom_vars']
|
| 528 |
+
})
|
| 529 |
+
|
| 530 |
except Exception as e:
|
| 531 |
# Mark batch as failed
|
| 532 |
for item in batch:
|
|
|
|
| 537 |
failed_count += 1
|
| 538 |
|
| 539 |
# Step 2: Try to update each successfully added lead with custom variables
|
| 540 |
+
# Use lead_id from the response
|
| 541 |
+
for item in leads_to_update:
|
| 542 |
+
if item.get('lead_id'):
|
| 543 |
+
try:
|
| 544 |
+
# Convert lead_id to int if it's a string
|
| 545 |
+
lead_id = int(item['lead_id'])
|
| 546 |
+
client.update_lead(campaign_id, lead_id, item['custom_vars'])
|
| 547 |
+
except (ValueError, TypeError) as e:
|
| 548 |
+
errors.append({
|
| 549 |
+
"email": item.get('email', 'unknown'),
|
| 550 |
+
"error": f"Lead added but invalid lead_id: {str(e)}"
|
| 551 |
+
})
|
| 552 |
+
except Exception as e:
|
| 553 |
+
# If update fails, log but don't fail the entire operation
|
| 554 |
+
errors.append({
|
| 555 |
+
"email": item.get('email', 'unknown'),
|
| 556 |
+
"error": f"Lead added but custom variables could not be set: {str(e)}"
|
| 557 |
+
})
|
| 558 |
+
else:
|
| 559 |
+
# If we don't have lead_id, log an error
|
| 560 |
+
errors.append({
|
| 561 |
+
"email": item.get('email', 'unknown'),
|
| 562 |
+
"error": "Lead added but lead_id not found in response - cannot update custom variables"
|
| 563 |
+
})
|
| 564 |
|
| 565 |
# Update run record
|
| 566 |
run.status = 'completed'
|
backend/app/smartlead_client.py
CHANGED
|
@@ -165,18 +165,15 @@ class SmartleadClient:
|
|
| 165 |
"""Update campaign settings"""
|
| 166 |
return self._make_request("POST", f"/campaigns/{campaign_id}/settings", settings)
|
| 167 |
|
| 168 |
-
def update_lead(self, campaign_id: str,
|
| 169 |
"""Update a lead's custom variables after adding to campaign
|
| 170 |
|
| 171 |
-
|
| 172 |
-
- PUT /campaigns/{campaign_id}/leads/{email}
|
| 173 |
-
- POST /campaigns/{campaign_id}/leads/{email}/update
|
| 174 |
-
- POST /campaigns/{campaign_id}/leads/update
|
| 175 |
"""
|
| 176 |
-
# Try different endpoint patterns
|
| 177 |
endpoints = [
|
| 178 |
-
f"/campaigns/{campaign_id}/leads/{
|
| 179 |
-
f"/campaigns/{campaign_id}/leads/{
|
| 180 |
f"/campaigns/{campaign_id}/leads/update"
|
| 181 |
]
|
| 182 |
|
|
@@ -186,7 +183,7 @@ class SmartleadClient:
|
|
| 186 |
{"custom_variables": custom_variables},
|
| 187 |
{"variables": custom_variables},
|
| 188 |
{"customFields": custom_variables},
|
| 189 |
-
{"
|
| 190 |
]
|
| 191 |
|
| 192 |
last_error = None
|
|
@@ -206,7 +203,7 @@ class SmartleadClient:
|
|
| 206 |
raise
|
| 207 |
|
| 208 |
# If all variations failed, raise the last error
|
| 209 |
-
raise last_error if last_error else Exception(f"Failed to update lead {
|
| 210 |
|
| 211 |
def build_sequences(self, steps_count: int) -> List[Dict]:
|
| 212 |
"""Build sequence templates for campaign
|
|
|
|
| 165 |
"""Update campaign settings"""
|
| 166 |
return self._make_request("POST", f"/campaigns/{campaign_id}/settings", settings)
|
| 167 |
|
| 168 |
+
def update_lead(self, campaign_id: str, lead_id: int, custom_variables: Dict) -> Dict:
|
| 169 |
"""Update a lead's custom variables after adding to campaign
|
| 170 |
|
| 171 |
+
Smartlead API requires lead_id (number) to update leads.
|
|
|
|
|
|
|
|
|
|
| 172 |
"""
|
| 173 |
+
# Try different endpoint patterns with lead_id
|
| 174 |
endpoints = [
|
| 175 |
+
f"/campaigns/{campaign_id}/leads/{lead_id}",
|
| 176 |
+
f"/campaigns/{campaign_id}/leads/{lead_id}/update",
|
| 177 |
f"/campaigns/{campaign_id}/leads/update"
|
| 178 |
]
|
| 179 |
|
|
|
|
| 183 |
{"custom_variables": custom_variables},
|
| 184 |
{"variables": custom_variables},
|
| 185 |
{"customFields": custom_variables},
|
| 186 |
+
{"lead_id": lead_id, **custom_variables}, # Include lead_id with custom vars
|
| 187 |
]
|
| 188 |
|
| 189 |
last_error = None
|
|
|
|
| 203 |
raise
|
| 204 |
|
| 205 |
# If all variations failed, raise the last error
|
| 206 |
+
raise last_error if last_error else Exception(f"Failed to update lead {lead_id}: All endpoint variations failed")
|
| 207 |
|
| 208 |
def build_sequences(self, steps_count: int) -> List[Dict]:
|
| 209 |
"""Build sequence templates for campaign
|