Refactor: Komplet omskrivning af kontakt sync med simpel logik
This commit is contained in:
parent
0fb404dff5
commit
6d949d7060
@ -163,166 +163,162 @@ async def sync_from_vtiger() -> Dict[str, Any]:
|
|||||||
@router.post("/sync/vtiger-contacts")
|
@router.post("/sync/vtiger-contacts")
|
||||||
async def sync_vtiger_contacts() -> Dict[str, Any]:
|
async def sync_vtiger_contacts() -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Sync contacts from vTiger Contacts module
|
SIMPEL TILGANG - Sync contacts from vTiger and link to customers
|
||||||
Links to existing Hub customers by Account ID
|
Step 1: Fetch all contacts from vTiger
|
||||||
|
Step 2: Create/update contact in Hub
|
||||||
|
Step 3: Link to customer IF account_id matches customer.vtiger_id
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logger.info("🔄 Starting vTiger contacts sync...")
|
logger.info("🔄 Starting vTiger contacts sync (SIMPEL VERSION)...")
|
||||||
|
|
||||||
vtiger = get_vtiger_service()
|
vtiger = get_vtiger_service()
|
||||||
|
|
||||||
# Fetch ALL contacts with pagination (same as accounts)
|
# ===== STEP 1: FETCH ALL CONTACTS =====
|
||||||
|
logger.info("📥 STEP 1: Fetching contacts from vTiger...")
|
||||||
all_contacts = []
|
all_contacts = []
|
||||||
last_id = None
|
last_id = None
|
||||||
batch_size = 100
|
batch_size = 100
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# Build query with ID filter to paginate
|
|
||||||
if last_id is None:
|
if last_id is None:
|
||||||
query = f"SELECT id, firstname, lastname, email, phone, mobile, title, department, account_id FROM Contacts ORDER BY id LIMIT {batch_size};"
|
query = f"SELECT id, firstname, lastname, email, phone, mobile, title, department, account_id FROM Contacts ORDER BY id LIMIT {batch_size};"
|
||||||
else:
|
else:
|
||||||
query = f"SELECT id, firstname, lastname, email, phone, mobile, title, department, account_id FROM Contacts WHERE id > '{last_id}' ORDER BY id LIMIT {batch_size};"
|
query = f"SELECT id, firstname, lastname, email, phone, mobile, title, department, account_id FROM Contacts WHERE id > '{last_id}' ORDER BY id LIMIT {batch_size};"
|
||||||
|
|
||||||
batch = await vtiger.query(query)
|
batch = await vtiger.query(query)
|
||||||
|
|
||||||
if not batch or len(batch) == 0:
|
if not batch or len(batch) == 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
all_contacts.extend(batch)
|
all_contacts.extend(batch)
|
||||||
last_id = batch[-1].get('id')
|
last_id = batch[-1].get('id')
|
||||||
logger.info(f"📥 Fetched batch: {len(batch)} contacts (last ID: {last_id}, total: {len(all_contacts)})")
|
logger.info(f" → Batch: {len(batch)} contacts (ID: {last_id}, total: {len(all_contacts)})")
|
||||||
|
|
||||||
if len(batch) < batch_size:
|
if len(batch) < batch_size:
|
||||||
break
|
break
|
||||||
|
|
||||||
logger.info(f"📥 Fetched total of {len(all_contacts)} contacts from vTiger")
|
logger.info(f"✅ STEP 1 DONE: {len(all_contacts)} contacts fetched")
|
||||||
contacts = all_contacts
|
|
||||||
|
# ===== STEP 2 & 3: PROCESS EACH CONTACT =====
|
||||||
|
logger.info("🔄 STEP 2 & 3: Creating/updating contacts and linking to customers...")
|
||||||
|
|
||||||
created_count = 0
|
created_count = 0
|
||||||
updated_count = 0
|
updated_count = 0
|
||||||
skipped_count = 0
|
skipped_count = 0
|
||||||
linked_count = 0
|
linked_count = 0
|
||||||
debug_counter = 0 # Track how many we've logged
|
debug_count = 0
|
||||||
|
|
||||||
for contact in contacts:
|
for i, contact in enumerate(all_contacts, 1):
|
||||||
vtiger_contact_id = contact.get('id')
|
vtiger_id = contact.get('id')
|
||||||
first_name = contact.get('firstname', '').strip()
|
first_name = (contact.get('firstname') or '').strip()
|
||||||
last_name = contact.get('lastname', '').strip()
|
last_name = (contact.get('lastname') or '').strip()
|
||||||
|
email = contact.get('email')
|
||||||
|
account_id = contact.get('account_id') # This is the vTiger Account ID
|
||||||
|
|
||||||
if not (first_name or last_name):
|
# Show progress every 100 contacts
|
||||||
|
if i % 100 == 0:
|
||||||
|
logger.info(f" → Progress: {i}/{len(all_contacts)} contacts processed...")
|
||||||
|
|
||||||
|
# Must have name
|
||||||
|
if not first_name and not last_name:
|
||||||
skipped_count += 1
|
skipped_count += 1
|
||||||
logger.debug(f"⏭️ Sprunget over: Intet navn (ID: {vtiger_contact_id})")
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Find existing contact by vTiger ID
|
# --- STEP 2A: Check if contact exists ---
|
||||||
existing = None
|
|
||||||
if vtiger_contact_id:
|
|
||||||
existing = execute_query(
|
existing = execute_query(
|
||||||
"SELECT id FROM contacts WHERE vtiger_id = %s",
|
"SELECT id FROM contacts WHERE vtiger_id = %s",
|
||||||
(vtiger_contact_id,)
|
(vtiger_id,)
|
||||||
)
|
) if vtiger_id else None
|
||||||
|
|
||||||
contact_data = {
|
# --- STEP 2B: Create or update contact ---
|
||||||
'first_name': first_name,
|
contact_id = None
|
||||||
'last_name': last_name,
|
|
||||||
'email': contact.get('email'),
|
|
||||||
'phone': contact.get('phone'),
|
|
||||||
'mobile': contact.get('mobile'),
|
|
||||||
'title': contact.get('title'),
|
|
||||||
'department': contact.get('department'),
|
|
||||||
'vtiger_id': vtiger_contact_id
|
|
||||||
}
|
|
||||||
|
|
||||||
if existing:
|
if existing:
|
||||||
# Update existing contact
|
# UPDATE existing
|
||||||
update_query = """
|
execute_query("""
|
||||||
UPDATE contacts
|
UPDATE contacts
|
||||||
SET first_name = %s, last_name = %s, email = %s, phone = %s,
|
SET first_name = %s, last_name = %s, email = %s,
|
||||||
mobile = %s, title = %s, department = %s, updated_at = NOW()
|
phone = %s, mobile = %s, title = %s, department = %s,
|
||||||
|
updated_at = NOW()
|
||||||
WHERE id = %s
|
WHERE id = %s
|
||||||
"""
|
""", (
|
||||||
execute_query(update_query, (
|
first_name, last_name, email,
|
||||||
contact_data['first_name'],
|
contact.get('phone'), contact.get('mobile'),
|
||||||
contact_data['last_name'],
|
contact.get('title'), contact.get('department'),
|
||||||
contact_data['email'],
|
|
||||||
contact_data['phone'],
|
|
||||||
contact_data['mobile'],
|
|
||||||
contact_data['title'],
|
|
||||||
contact_data['department'],
|
|
||||||
existing[0]['id']
|
existing[0]['id']
|
||||||
))
|
))
|
||||||
updated_count += 1
|
|
||||||
contact_id = existing[0]['id']
|
contact_id = existing[0]['id']
|
||||||
logger.info(f"✏️ Opdateret kontakt: {first_name} {last_name} (Email: {contact_data['email'] or 'ingen'})")
|
updated_count += 1
|
||||||
else:
|
else:
|
||||||
# Create new contact
|
# CREATE new
|
||||||
insert_query = """
|
result = execute_query("""
|
||||||
INSERT INTO contacts
|
INSERT INTO contacts
|
||||||
(first_name, last_name, email, phone, mobile, title, department, vtiger_id)
|
(first_name, last_name, email, phone, mobile, title, department, vtiger_id)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
"""
|
""", (
|
||||||
result = execute_query(insert_query, (
|
first_name, last_name, email,
|
||||||
contact_data['first_name'],
|
contact.get('phone'), contact.get('mobile'),
|
||||||
contact_data['last_name'],
|
contact.get('title'), contact.get('department'),
|
||||||
contact_data['email'],
|
vtiger_id
|
||||||
contact_data['phone'],
|
|
||||||
contact_data['mobile'],
|
|
||||||
contact_data['title'],
|
|
||||||
contact_data['department'],
|
|
||||||
contact_data['vtiger_id']
|
|
||||||
))
|
))
|
||||||
|
|
||||||
if result:
|
if result and len(result) > 0:
|
||||||
created_count += 1
|
|
||||||
contact_id = result[0]['id']
|
contact_id = result[0]['id']
|
||||||
logger.info(f"✨ Oprettet kontakt: {first_name} {last_name} (Email: {contact_data['email'] or 'ingen'})")
|
created_count += 1
|
||||||
else:
|
else:
|
||||||
skipped_count += 1
|
skipped_count += 1
|
||||||
logger.warning(f"⚠️ Kunne ikke oprette kontakt: {first_name} {last_name}")
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Link contact to customer if account_id exists
|
# --- DEBUG LOGGING FOR FIRST 20 CONTACTS ---
|
||||||
account_id = contact.get('account_id')
|
if debug_count < 20:
|
||||||
|
logger.warning(f"🔍 DEBUG {debug_count+1}: Contact '{first_name} {last_name}' (vtiger_id={vtiger_id}, contact_id={contact_id}, account_id={account_id})")
|
||||||
# ALWAYS log first 20 for debugging
|
debug_count += 1
|
||||||
if debug_counter < 20:
|
|
||||||
logger.warning(f"🔍 DEBUG #{debug_counter+1}: name={first_name} {last_name}, account_id='{account_id}', has_contact_id={contact_id is not None if 'contact_id' in locals() else False}")
|
|
||||||
debug_counter += 1
|
|
||||||
|
|
||||||
|
# --- STEP 3: LINK TO CUSTOMER ---
|
||||||
if not account_id:
|
if not account_id:
|
||||||
continue # Skip if no account_id
|
# No account_id means contact is not linked to any account in vTiger
|
||||||
|
if debug_count <= 20:
|
||||||
if not contact_id:
|
logger.warning(f" ↳ No account_id - cannot link")
|
||||||
logger.warning(f"⚠️ Mangler contact_id for {first_name} {last_name}")
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Find customer by vTiger account ID
|
# Find Hub customer with matching vtiger_id
|
||||||
customer = execute_query(
|
customer_result = execute_query(
|
||||||
"SELECT id, name FROM customers WHERE vtiger_id = %s",
|
"SELECT id, name FROM customers WHERE vtiger_id = %s",
|
||||||
(account_id,)
|
(account_id,)
|
||||||
)
|
)
|
||||||
|
|
||||||
if customer:
|
if not customer_result or len(customer_result) == 0:
|
||||||
customer_name = customer[0]['name']
|
# No matching customer found
|
||||||
# Check if relationship exists
|
if debug_count <= 20:
|
||||||
existing_rel = execute_query(
|
logger.warning(f" ↳ No customer found with vtiger_id={account_id}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
customer_id = customer_result[0]['id']
|
||||||
|
customer_name = customer_result[0]['name']
|
||||||
|
|
||||||
|
# Check if link already exists
|
||||||
|
existing_link = execute_query(
|
||||||
"SELECT id FROM contact_companies WHERE contact_id = %s AND customer_id = %s",
|
"SELECT id FROM contact_companies WHERE contact_id = %s AND customer_id = %s",
|
||||||
(contact_id, customer[0]['id'])
|
(contact_id, customer_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not existing_rel:
|
if existing_link:
|
||||||
# Create relationship
|
# Already linked
|
||||||
|
if debug_count <= 20:
|
||||||
|
logger.warning(f" ↳ Already linked to '{customer_name}'")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# CREATE LINK
|
||||||
execute_query(
|
execute_query(
|
||||||
"INSERT INTO contact_companies (contact_id, customer_id, is_primary) VALUES (%s, %s, false)",
|
"INSERT INTO contact_companies (contact_id, customer_id, is_primary) VALUES (%s, %s, false)",
|
||||||
(contact_id, customer[0]['id'])
|
(contact_id, customer_id)
|
||||||
)
|
)
|
||||||
linked_count += 1
|
linked_count += 1
|
||||||
logger.info(f"🔗 Linket kontakt {first_name} {last_name} til firma: {customer_name}")
|
|
||||||
else:
|
|
||||||
logger.info(f"⚠️ Kunde ikke fundet for account_id={account_id} (kontakt: {first_name} {last_name})")
|
|
||||||
|
|
||||||
logger.info(f"✅ vTiger kontakt sync fuldført: {created_count} oprettet, {updated_count} opdateret, {linked_count} linket, {skipped_count} sprunget over af {len(contacts)} totalt")
|
if linked_count <= 10: # Log first 10 successful links
|
||||||
|
logger.info(f"🔗 LINKED: {first_name} {last_name} → {customer_name}")
|
||||||
|
|
||||||
|
logger.info(f"✅ SYNC COMPLETE: created={created_count}, updated={updated_count}, linked={linked_count}, skipped={skipped_count}, total={len(all_contacts)}")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"status": "success",
|
"status": "success",
|
||||||
@ -330,11 +326,11 @@ async def sync_vtiger_contacts() -> Dict[str, Any]:
|
|||||||
"updated": updated_count,
|
"updated": updated_count,
|
||||||
"linked": linked_count,
|
"linked": linked_count,
|
||||||
"skipped": skipped_count,
|
"skipped": skipped_count,
|
||||||
"total_processed": len(contacts)
|
"total_processed": len(all_contacts)
|
||||||
}
|
}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"❌ vTiger contacts sync error: {e}")
|
logger.error(f"❌ vTiger contacts sync error: {e}", exc_info=True)
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user