151 lines
6.0 KiB
Python
151 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Step 2: update Fuente de Prospecto from Canal de Origen."""
|
|
|
|
import argparse
|
|
|
|
from tag_canal_origen_workflow import (
|
|
MAIN_LOCATION_ID,
|
|
build_contact_match_index,
|
|
contact_display_name,
|
|
find_exact_main_contact,
|
|
get_all_contacts,
|
|
get_custom_field_value,
|
|
get_main_account,
|
|
get_schemas,
|
|
load_locations,
|
|
safe_update_contact_field,
|
|
script_audit,
|
|
select_locations,
|
|
)
|
|
from canal_origen_resolver import classify_source
|
|
|
|
SUCURSAL_VALUE = "SUCURSAL"
|
|
LEAD_DIGITAL_VALUE = "LEAD DIGITAL"
|
|
|
|
|
|
def process_location(account, dry_run=False, skip_correct=True, run_id=None, sync_main=False):
|
|
location_id = account["location_id"]
|
|
token = account["token"]
|
|
name = account["nombre"]
|
|
|
|
contact_schema = get_schemas(location_id, token, "contact")["contact"]
|
|
canal_field_id = contact_schema.get("Canal de Origen")
|
|
fuente_field_id = contact_schema.get("Fuente de Prospecto")
|
|
|
|
main_account = get_main_account() if sync_main and location_id != MAIN_LOCATION_ID else None
|
|
main_contact_schema = {}
|
|
main_index = None
|
|
if main_account:
|
|
main_contact_schema = get_schemas(main_account["location_id"], main_account["token"], "contact")["contact"]
|
|
main_contacts = get_all_contacts(main_account["location_id"], main_account["token"])
|
|
main_index = build_contact_match_index(main_contacts)
|
|
|
|
if not canal_field_id or not fuente_field_id:
|
|
print(
|
|
f"\n{name} - missing required fields "
|
|
f"(Canal: {bool(canal_field_id)}, Fuente: {bool(fuente_field_id)})"
|
|
)
|
|
return 0
|
|
|
|
updated = 0
|
|
skipped = 0
|
|
contacts = get_all_contacts(location_id, token)
|
|
|
|
inconsistencies = 0
|
|
for contact in contacts:
|
|
if not script_audit.wait_if_paused_or_stopped(run_id):
|
|
print("\nDetención segura solicitada. Saliendo antes del siguiente contacto.")
|
|
break
|
|
canal_value = get_custom_field_value(contact, canal_field_id)
|
|
current_fuente = get_custom_field_value(contact, fuente_field_id)
|
|
source_value = contact.get("source")
|
|
source_tag = classify_source(source_value)
|
|
if (canal_value == SUCURSAL_VALUE) and source_tag in ("facebook-ads", "formulario"):
|
|
inconsistencies += 1
|
|
print(
|
|
f" INCONGRUENTE {contact_display_name(contact)} | Canal=SUCURSAL pero "
|
|
f"source='{source_value}' sugiere '{source_tag}' (se respeta Canal actual; "
|
|
"revisar Step 1)"
|
|
)
|
|
target_fuente = SUCURSAL_VALUE if canal_value == SUCURSAL_VALUE else LEAD_DIGITAL_VALUE
|
|
|
|
branch_changed = False
|
|
if skip_correct and current_fuente == target_fuente:
|
|
skipped += 1
|
|
else:
|
|
branch_changed = safe_update_contact_field(
|
|
run_id,
|
|
location_id,
|
|
contact,
|
|
fuente_field_id,
|
|
"Fuente de Prospecto",
|
|
target_fuente,
|
|
token,
|
|
dry_run,
|
|
)
|
|
if branch_changed:
|
|
updated += 1
|
|
print(
|
|
f" OK {contact_display_name(contact)} | "
|
|
f"Canal: {canal_value or '(vacio)'} -> Fuente: {target_fuente}"
|
|
)
|
|
|
|
if main_account and main_index and main_contact_schema.get("Fuente de Prospecto"):
|
|
main_contact, match_type = find_exact_main_contact(contact, main_index)
|
|
if main_contact:
|
|
main_canal_id = main_contact_schema.get("Canal de Origen")
|
|
main_canal_value = get_custom_field_value(main_contact, main_canal_id) if main_canal_id else canal_value
|
|
main_target_fuente = SUCURSAL_VALUE if main_canal_value == SUCURSAL_VALUE else LEAD_DIGITAL_VALUE
|
|
if safe_update_contact_field(
|
|
run_id,
|
|
main_account["location_id"],
|
|
main_contact,
|
|
main_contact_schema["Fuente de Prospecto"],
|
|
"Fuente de Prospecto",
|
|
main_target_fuente,
|
|
main_account["token"],
|
|
dry_run,
|
|
):
|
|
print(f" OK marca principal ({match_type}) {contact_display_name(main_contact)} -> Fuente: {main_target_fuente}")
|
|
|
|
print(
|
|
f"\n{name}: {updated} contactos actualizados, {skipped} ya correctos, "
|
|
f"{inconsistencies} incongruencias canal/source"
|
|
)
|
|
return updated
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="GHL Step 2: Canal de Origen -> Fuente de Prospecto")
|
|
parser.add_argument("--location", help="Specific location ID to process")
|
|
parser.add_argument("--all", action="store_true", help="Process all branch locations from the CSV")
|
|
parser.add_argument("--include-main", action="store_true", help="Include the main brand account when using --all")
|
|
parser.add_argument("--dry-run", action="store_true", help="Preview changes without writing to GHL")
|
|
parser.add_argument("--no-skip", action="store_true", help="Update even if Fuente de Prospecto already matches")
|
|
parser.add_argument("--sync-main", action="store_true", help="Also sync exact matching contact in the main brand account")
|
|
parser.add_argument("--run-id", help="Audit run ID supplied by the dashboard")
|
|
args = parser.parse_args()
|
|
|
|
# Keep the imported helpers explicit so packaging/static checks see they are intentional.
|
|
_ = load_locations
|
|
|
|
print("\n" + "=" * 60)
|
|
print("GHL WORKFLOW STEP 2 - FUENTE DE PROSPECTO")
|
|
print("=" * 60)
|
|
if args.dry_run:
|
|
print("DRY RUN - no changes will be made\n")
|
|
|
|
total = 0
|
|
for account in select_locations(args):
|
|
try:
|
|
total += process_location(account, args.dry_run, not args.no_skip, args.run_id, args.sync_main)
|
|
except Exception as exc:
|
|
print(f"\nERROR {account['nombre']}: {exc}")
|
|
|
|
print(f"\n{'=' * 60}")
|
|
print(f"TOTAL: {total} contactos actualizados")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|