From f851ea6d7d7cacab09600ee5857ada47e617a5e6 Mon Sep 17 00:00:00 2001 From: DANYDHSV Date: Sat, 3 Jan 2026 11:07:29 -0600 Subject: [PATCH] =?UTF-8?q?feat:=20soporte=20multi-servicio,=20optimizaci?= =?UTF-8?q?=C3=B3n=20lazy=20loading=20y=20sincronizaci=C3=B3n=20avanzada?= =?UTF-8?q?=20con=20CallBell?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Implementación de gestión multi-servicio para contraseñas de antena con etiquetas condicionales. - Optimización de rendimiento mediante lazy loading para evitar llamadas redundantes a la API de UISP. - Mejora de sincronización con CallBell: contraseñas en formato JSON, unificación de peticiones PATCH y corrección de comparación de saldo. - Generación de contraseñas printer-friendly (alfanuméricas + @, #) sin caracteres ambiguos. - Validación granular de provisionamiento para evitar errores en sitios inactivos. - Actualización de CHANGELOG.md y README.md. --- CHANGELOG.md | 14 ++- README.md | 12 +- data/plugin.log | 62 +++++++++++ src/Facade/AbstractMessageNotifierFacade.php | 27 ++++- src/Facade/AbstractStripeOperationsFacade.php | 27 ++++- src/Facade/ClientCallBellAPI.php | 103 +++++------------- 6 files changed, 152 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f12a732..088a940e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,18 @@ 3️⃣ **Lazy Loading & Optimización de Recursos**: Implementación de un "Lazy Check" que detecta si ya hay una contraseña válida en el CRM para omitir llamadas innecesarias a la API de UISP, mejorando la velocidad y reduciendo el consumo de CPU. ### 🔵 Mejoras -1️⃣ **Contraseñas "Printer-Friendly"**: El generador de contraseñas ahora utiliza un set de caracteres optimizado para mini-impresoras térmicas (Alfanumérico + `@`, `#`), eliminando caracteres ambiguos como `l`, `I`, `0`, `O`. -2️⃣ **Mensajes de Estado en CRM**: Se agregaron alertas visuales en el campo de contraseña para indicar estados de provisión: `⚠️ Sin sitio vinculado`, `⚠️ Sin antena vinculada`, `⚠️ Cliente sin servicios`. -3️⃣ **Robustez en Entornos de Prueba**: Refinamiento del bypass de desarrollo para mantener la estabilidad de las claves generadas y evitar bucles infinitos de webhooks. +1️⃣ **Etiquetado Inteligente de Servicios**: Las etiquetas `Servicio 1:`, `Servicio 2:` ahora solo aparecen si el cliente tiene múltiples servicios; para un solo servicio, la contraseña se muestra directamente. +2️⃣ **Sincronización Avanzada con CallBell**: + - Nuevo campo `Password Antena` enviado en formato JSON estructurado. + - Unificación de peticiones PATCH (Resumen + Campos) en una sola llamada para mayor eficiencia. +3️⃣ **Contraseñas "Printer-Friendly"**: El generador de contraseñas ahora utiliza un set de caracteres optimizado para mini-impresoras térmicas (Alfanumérico + `@`, `#`), eliminando caracteres ambiguos como `l`, `I`, `0`, `O`. +4️⃣ **Mensajes de Estado en CRM**: Se agregaron alertas visuales en el campo de contraseña para indicar estados de provisión: `⚠️ Sin sitio vinculado`, `⚠️ Sin antena vinculada`, `⚠️ Cliente sin servicios`. +5️⃣ **Robustez en Entornos de Prueba**: Refinamiento del bypass de desarrollo para mantener la estabilidad de las claves generadas y evitar bucles infinitos de webhooks. ### 🟡 Bugs Resueltos -1️⃣ Se solucionó el bucle infinito de actualizaciones en el atributo `passwordAntenaCliente` que ocurría al detectar cambios en servicios sin dispositivos vinculados. +1️⃣ **Sincronización de Saldo**: Se corrigió la discrepancia de nombres entre `Saldo Actual` y `Saldo` que causaba actualizaciones redundantes infinitas con CallBell. +2️⃣ **Parseo de Passwords**: Refinamiento de expresiones regulares para capturar correctamente contraseñas multi-servicio. +3️⃣ Se solucionó el bucle infinito de actualizaciones en el atributo `passwordAntenaCliente` que ocurría al detectar cambios en servicios sin dispositivos vinculados. ## VERSIÓN 2.9.3 - 23-12-2025 ### 🟢 Novedades diff --git a/README.md b/README.md index 67fff401..d1032d3a 100755 --- a/README.md +++ b/README.md @@ -57,10 +57,14 @@ Es necesario configurar los siguientes atributos en UCRM: ### 📅 Gestión de Contraseñas y Visitas Técnicas Cuando se asigna o reprograma una tarea: -1. **Detección Multi-Servicio**: El plugin identifica todos los servicios del cliente y formatea sus contraseñas como `Servicio 1: Servicio 2: ...`. -2. **Validación de Provisionamiento**: Antes de actuar, verifica en UISP si el sitio tiene dispositivos vinculados (evitando errores en estados "Location Inactive"). -3. **Lazy Loading**: Si el CRM ya tiene una contraseña válida, el plugin omite llamadas redundantes a la API para ahorrar recursos. -4. **Notificación**: +1. **Detección Multi-Servicio & Etiquetas Inteligentes**: + - El plugin identifica todos los servicios del cliente. + - Si hay **más de un servicio**, utiliza el formato: `Servicio 1: Servicio 2: ...`. + - Si hay **solo un servicio**, muestra la contraseña directamente sin etiquetas para mayor claridad. +2. **Sincronización CallBell Avanzada**: + - Los datos técnicos y financieros se sincronizan en una sola petición optimizada. + - Las contraseñas se envían como un objeto JSON estructurado al campo `Password Antena`. +3. **Validación de Provisionamiento**: Antes de actuar, verifica en UISP si el sitio tiene dispositivos vinculados (evitando errores en estados "Location Inactive"). - Envía un mensaje al cliente con el nombre del técnico y la fecha (sin hora). - Envía un mensaje al técnico con la dirección, ubicación en Google Maps y las contraseñas de las antenas optimizadas para lectura en impresoras térmicas (alfanumérico + `@`, `#`). diff --git a/data/plugin.log b/data/plugin.log index a8c4a707..0f8db8bd 100644 --- a/data/plugin.log +++ b/data/plugin.log @@ -16348,3 +16348,65 @@ La cadena CURL que se envia es: { Response del CallBell: {"message":{"uuid":"3466911dab994d049d42901582e855ee","status":"enqueued"}} La notificación fue enviada correctamente con estado: enqueued +[2026-01-03 5:24:18.913006] [notice] Logging level set to:debug +[2026-01-03 5:24:18.913078] [debug] Payload recibido: {"uuid":"17e6df39-cb13-4331-ad41-f257941382e8","changeType":"edit","entity":"client","entityId":"2","eventName":"client.edit","extraData":{"entity":{"id":2,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"Chiapas 31","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":"Cliente especial, el m\u00e1s chido del siip internet 2026 yeah xD hola","sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-01-25T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":true,"firstName":"Daniel Humberto","lastName":"Soto Villegas Polleria","username":"danydhsv","contacts":[{"id":2,"clientId":2,"email":"dhsv.141089@gmail.com","phone":"5214181878106","name":null,"isBilling":false,"isContact":true,"types":[{"id":2,"name":"General"},{"id":1000,"name":"WhatsApp"}]},{"id":170,"clientId":2,"email":null,"phone":"5214181148783","name":null,"isBilling":false,"isContact":false,"types":[]}],"attributes":[{"id":113,"clientId":2,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"0021804341999569810","clientZoneVisible":true},{"id":178,"clientId":2,"customAttributeId":15,"name":"Site","key":"site","value":"0LOCS","clientZoneVisible":false},{"id":179,"clientId":2,"customAttributeId":16,"name":"Antena\/Sectorial","key":"antenaSectorial","value":"Sectorial-4b 172.16.13.16\/24","clientZoneVisible":false},{"id":200,"clientId":2,"customAttributeId":14,"name":"Chat de CallBell","key":"chatDeCallbell","value":"https","clientZoneVisible":false},{"id":112,"clientId":2,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_PetN1dhr4rx0kX","clientZoneVisible":true},{"id":252,"clientId":2,"customAttributeId":17,"name":"Password Antena Cliente","key":"passwordAntenaCliente","value":"Servicio 1: {au{AQ8Cy?)pNSHe Servicio 2: ,v=d6}cb8Hn6b}yg","clientZoneVisible":false}],"accountBalance":3150,"accountCredit":3150,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1564414,"addressGpsLon":-100.9383654,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":true,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"entityBeforeEdit":{"id":2,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"Chiapas 31","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":"Cliente especial, el m\u00e1s chido del siip internet 2026 yeah xD hola","sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-01-25T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":true,"firstName":"Daniel Humberto","lastName":"Soto Villegas","username":"danydhsv","contacts":[{"id":2,"clientId":2,"email":"dhsv.141089@gmail.com","phone":"5214181878106","name":null,"isBilling":false,"isContact":true,"types":[{"id":2,"name":"General"},{"id":1000,"name":"WhatsApp"}]},{"id":170,"clientId":2,"email":null,"phone":"5214181148783","name":null,"isBilling":false,"isContact":false,"types":[]}],"attributes":[{"id":113,"clientId":2,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"0021804341999569810","clientZoneVisible":true},{"id":178,"clientId":2,"customAttributeId":15,"name":"Site","key":"site","value":"0LOCS","clientZoneVisible":false},{"id":179,"clientId":2,"customAttributeId":16,"name":"Antena\/Sectorial","key":"antenaSectorial","value":"Sectorial-4b 172.16.13.16\/24","clientZoneVisible":false},{"id":200,"clientId":2,"customAttributeId":14,"name":"Chat de CallBell","key":"chatDeCallbell","value":"https","clientZoneVisible":false},{"id":112,"clientId":2,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_PetN1dhr4rx0kX","clientZoneVisible":true},{"id":252,"clientId":2,"customAttributeId":17,"name":"Password Antena Cliente","key":"passwordAntenaCliente","value":"Servicio 1: {au{AQ8Cy?)pNSHe Servicio 2: ,v=d6}cb8Hn6b}yg","clientZoneVisible":false}],"accountBalance":3150,"accountCredit":3150,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1564414,"addressGpsLon":-100.9383654,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":true,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}}} + +[2026-01-03 5:24:19.029026] [debug] Evento recibido: client.edit +[2026-01-03 5:24:19.029158] [info] Procesando evento client.edit para entityId: 2 +[2026-01-03 5:24:19.029218] [debug] Payload completo client.edit: {"uuid":"17e6df39-cb13-4331-ad41-f257941382e8","changeType":"edit","entity":"client","entityId":"2","eventName":"client.edit","extraData":{"entity":{"id":2,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"Chiapas 31","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":"Cliente especial, el m\u00e1s chido del siip internet 2026 yeah xD hola","sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-01-25T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":true,"firstName":"Daniel Humberto","lastName":"Soto Villegas Polleria","username":"danydhsv","contacts":[{"id":2,"clientId":2,"email":"dhsv.141089@gmail.com","phone":"5214181878106","name":null,"isBilling":false,"isContact":true,"types":[{"id":2,"name":"General"},{"id":1000,"name":"WhatsApp"}]},{"id":170,"clientId":2,"email":null,"phone":"5214181148783","name":null,"isBilling":false,"isContact":false,"types":[]}],"attributes":[{"id":113,"clientId":2,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"0021804341999569810","clientZoneVisible":true},{"id":178,"clientId":2,"customAttributeId":15,"name":"Site","key":"site","value":"0LOCS","clientZoneVisible":false},{"id":179,"clientId":2,"customAttributeId":16,"name":"Antena\/Sectorial","key":"antenaSectorial","value":"Sectorial-4b 172.16.13.16\/24","clientZoneVisible":false},{"id":200,"clientId":2,"customAttributeId":14,"name":"Chat de CallBell","key":"chatDeCallbell","value":"https","clientZoneVisible":false},{"id":112,"clientId":2,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_PetN1dhr4rx0kX","clientZoneVisible":true},{"id":252,"clientId":2,"customAttributeId":17,"name":"Password Antena Cliente","key":"passwordAntenaCliente","value":"Servicio 1: {au{AQ8Cy?)pNSHe Servicio 2: ,v=d6}cb8Hn6b}yg","clientZoneVisible":false}],"accountBalance":3150,"accountCredit":3150,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1564414,"addressGpsLon":-100.9383654,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":true,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"entityBeforeEdit":{"id":2,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"Chiapas 31","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":"Cliente especial, el m\u00e1s chido del siip internet 2026 yeah xD hola","sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-01-25T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":true,"firstName":"Daniel Humberto","lastName":"Soto Villegas","username":"danydhsv","contacts":[{"id":2,"clientId":2,"email":"dhsv.141089@gmail.com","phone":"5214181878106","name":null,"isBilling":false,"isContact":true,"types":[{"id":2,"name":"General"},{"id":1000,"name":"WhatsApp"}]},{"id":170,"clientId":2,"email":null,"phone":"5214181148783","name":null,"isBilling":false,"isContact":false,"types":[]}],"attributes":[{"id":113,"clientId":2,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"0021804341999569810","clientZoneVisible":true},{"id":178,"clientId":2,"customAttributeId":15,"name":"Site","key":"site","value":"0LOCS","clientZoneVisible":false},{"id":179,"clientId":2,"customAttributeId":16,"name":"Antena\/Sectorial","key":"antenaSectorial","value":"Sectorial-4b 172.16.13.16\/24","clientZoneVisible":false},{"id":200,"clientId":2,"customAttributeId":14,"name":"Chat de CallBell","key":"chatDeCallbell","value":"https","clientZoneVisible":false},{"id":112,"clientId":2,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_PetN1dhr4rx0kX","clientZoneVisible":true},{"id":252,"clientId":2,"customAttributeId":17,"name":"Password Antena Cliente","key":"passwordAntenaCliente","value":"Servicio 1: {au{AQ8Cy?)pNSHe Servicio 2: ,v=d6}cb8Hn6b}yg","clientZoneVisible":false}],"accountBalance":3150,"accountCredit":3150,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1564414,"addressGpsLon":-100.9383654,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":true,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}}} +[2026-01-03 5:24:19.029246] [info] Llamando a updatePasswordAntenaIfNeeded para cliente: 2 +[2026-01-03 5:24:19.029258] [info] Iniciando verificación/sincronización de contraseña para el cliente ID: 2 +[2026-01-03 5:24:19.128562] [info] Llamada finalizada exitosamente. +Notificacion data: {"uuid":"17e6df39-cb13-4331-ad41-f257941382e8","changeType":"edit","entity":"client","entityId":2,"message":null,"clientId":2,"eventName":"client.edit","clientData":{"id":2,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"Chiapas 31","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":"Cliente especial, el m\u00e1s chido del siip internet 2026 yeah xD hola","sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-01-25T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":true,"firstName":"Daniel Humberto","lastName":"Soto Villegas Polleria","username":"danydhsv","contacts":[{"id":2,"clientId":2,"email":"dhsv.141089@gmail.com","phone":"5214181878106","name":null,"isBilling":false,"isContact":true,"types":[{"id":2,"name":"General"},{"id":1000,"name":"WhatsApp"}]},{"id":170,"clientId":2,"email":null,"phone":"5214181148783","name":null,"isBilling":false,"isContact":false,"types":[]}],"attributes":[{"id":113,"clientId":2,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"0021804341999569810","clientZoneVisible":true},{"id":178,"clientId":2,"customAttributeId":15,"name":"Site","key":"site","value":"0LOCS","clientZoneVisible":false},{"id":179,"clientId":2,"customAttributeId":16,"name":"Antena\/Sectorial","key":"antenaSectorial","value":"Sectorial-4b 172.16.13.16\/24","clientZoneVisible":false},{"id":200,"clientId":2,"customAttributeId":14,"name":"Chat de CallBell","key":"chatDeCallbell","value":"https","clientZoneVisible":false},{"id":112,"clientId":2,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_PetN1dhr4rx0kX","clientZoneVisible":true},{"id":252,"clientId":2,"customAttributeId":17,"name":"Password Antena Cliente","key":"passwordAntenaCliente","value":"Servicio 1: {au{AQ8Cy?)pNSHe Servicio 2: ,v=d6}cb8Hn6b}yg","clientZoneVisible":false}],"accountBalance":3150,"accountCredit":3150,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1564414,"addressGpsLon":-100.9383654,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":true,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"serviceData":null,"invoiceData":null,"paymentData":null} + +Dentro del proceso del patch: + +Datos traidos con payment api: [{"id":718,"clientId":2,"methodId":"d8c1eae9-d41d-479f-aeaf-38497975d7b3","checkNumber":null,"createdDate":"2026-01-02T20:18:37-0600","amount":300,"currencyCode":"MXN","note":null,"receiptSentDate":null,"providerName":null,"providerPaymentId":null,"providerPaymentTime":null,"paymentCovers":[],"creditAmount":300,"userId":1015,"attributes":[]}] + +Nombre del cliente que se va a actualizar: Daniel Humberto Soto Villegas Polleria + +UUID: 74cc2bb45eb8409f92cd5dba99200d26 + +JSON con los datos a actualizar: {"name":"Daniel Humberto Soto Villegas Polleria","custom_fields":{"Cliente":2,"Domicilio":"\ud83d\udccd Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","Nombre":"\ud83d\udc64 Daniel Humberto Soto Villegas Polleria","URL":"\ud83c\udf10 https:\/\/sistema.siip.mx\/crm\/client\/2","Saldo Actual":"\ud83d\udcb23150 a favor","Monto Ultimo Pago":"\ud83d\udcb2 300","Estado":"\ud83d\udfe2 Activo ","Resumen":"{\"Cliente\": \"2\",\"Domicilio\": \"\"Nombre\": \"Daniel Humberto Soto Villegas Polleria\",\"URL\": \"https:\/\/sistema.siip.mx\/crm\/client\/2\",\"Saldo Actual\": \"\ud83d\udcb23150 a favor\",\"Monto Ultimo Pago\": \"$ 300\",\"Estado\": \"Activo\",\"Fecha Ultimo Pago\": \" 02\/01\/2026 20:18 con Personalizado \ud83d\udcdd\ud83d\udcb8\",\"Fecha Ultima Actualizacion\": \"02\/01\/2026 23:24\",\"Clabe Interbancaria\": \"\",\"Site\": \"0LOCS\",\"Antena\/Sectorial\": \"Sectorial-4b 172.16.13.16\/24\"}","Fecha Ultimo Pago":"\ud83d\udcc6\ud83d\udcb8 02\/01\/2026 20:18 con Personalizado \ud83d\udcdd\ud83d\udcb8","Fecha Ultima Actualizacion":"\ud83d\udcc6\ud83d\udd04\ufe0f 02\/01\/2026 23:24","Clabe Interbancaria":null,"Site":"0LOCS","Antena\/Sectorial":"Sectorial-4b 172.16.13.16\/24"}} + +JSON con los datos a actualizar del resumen: {"Cliente": "2","Domicilio": ""Nombre": "Daniel Humberto Soto Villegas Polleria","URL": "https://sistema.siip.mx/crm/client/2","Saldo Actual": "💲3150 a favor","Monto Ultimo Pago": "$ 300","Estado": "Activo","Fecha Ultimo Pago": " 02/01/2026 20:18 con Personalizado 📝💸","Fecha Ultima Actualizacion": "02/01/2026 23:24","Clabe Interbancaria": "","Site": "0LOCS","Antena/Sectorial": "Sectorial-4b 172.16.13.16/24"} + +Response Patch CallBell: {"contact":{"uuid":"74cc2bb45eb8409f92cd5dba99200d26","name":"Daniel Humberto Soto Villegas Polleria","phoneNumber":"5214181878106","avatarUrl":null,"createdAt":"2024-01-08T17:04:13Z","closedAt":"2025-12-09T22:06:49Z","source":"whatsapp","funnelId":null,"href":"https://dash.callbell.eu/contacts/74cc2bb45eb8409f92cd5dba99200d26","conversationHref":"https://dash.callbell.eu/chat/53c8229c428c4081b197ab136feab73b","tags":["s0LOCS"],"assignedUser":null,"customFields":{"user entry point":"inbound_message","Antena/Sectorial":"Sectorial-4b 172.16.13.16/24","Site":"0LOCS","Estado":"🟢 Activo ","Cliente":"2","Domicilio":"📍 Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","Fecha Ultimo Pago":"📆💸 02/01/2026 20:18 con Personalizado 📝💸","Nombre":"👤 Daniel Humberto Soto Villegas Polleria","user name":"Daniel Humberto","Saldo Actual":"💲3150 a favor","Monto Ultimo Pago":"💲 300","URL":"🌐 https://sistema.siip.mx/crm/client/2","Clabe Interbancaria":"124180650741646979","Fecha Ultima Actualizacion":"📆🔄️ 02/01/2026 23:24","Resumen":"{\"Cliente\": \"2\",\"Domicilio\": \"\"Nombre\": \"Daniel Humberto Soto Villegas Polleria\",\"URL\": \"https://sistema.siip.mx/crm/client/2\",\"Saldo Actual\": \"💲3150 a favor\",\"Monto Ultimo Pago\": \"$ 300\",\"Estado\": \"Activo\",\"Fecha Ultimo Pago\": \" 02/01/2026 20:18 con Personalizado 📝💸\",\"Fecha Ultima Actualizacion\": \"02/01/2026 23:24\",\"Clabe Interbancaria\": \"\",\"Site\": \"0LOCS\",\"Antena/Sectorial\": \"Sectorial-4b 172.16.13.16/24\"}"},"team":{"uuid":"5faeed738d6a44ccacf6509762eb288d","name":"General","default":true,"members":5,"createdAt":"2023-11-07T00:37:10Z"},"channel":{"uuid":"dbaa248932634e7ea4346a320960c24a","title":null,"type":"whatsapp","main":true},"blockedAt":null}} + +Response 2 Patch CallBell: {"contact":{"uuid":"74cc2bb45eb8409f92cd5dba99200d26","name":"Daniel Humberto Soto Villegas Polleria","phoneNumber":"5214181878106","avatarUrl":null,"createdAt":"2024-01-08T17:04:13Z","closedAt":"2025-12-09T22:06:49Z","source":"whatsapp","funnelId":null,"href":"https://dash.callbell.eu/contacts/74cc2bb45eb8409f92cd5dba99200d26","conversationHref":"https://dash.callbell.eu/chat/53c8229c428c4081b197ab136feab73b","tags":["s0LOCS"],"assignedUser":null,"customFields":{"user entry point":"inbound_message","Antena/Sectorial":"Sectorial-4b 172.16.13.16/24","Site":"0LOCS","Estado":"🟢 Activo ","Cliente":"2","Domicilio":"📍 Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","Fecha Ultimo Pago":"📆💸 02/01/2026 20:18 con Personalizado 📝💸","Nombre":"👤 Daniel Humberto Soto Villegas Polleria","user name":"Daniel Humberto","Saldo Actual":"💲3150 a favor","Monto Ultimo Pago":"💲 300","URL":"🌐 https://sistema.siip.mx/crm/client/2","Clabe Interbancaria":"124180650741646979","Fecha Ultima Actualizacion":"📆🔄️ 02/01/2026 23:24","Resumen":"{\"Cliente\": \"2\",\"Domicilio\": \"\"Nombre\": \"Daniel Humberto Soto Villegas Polleria\",\"URL\": \"https://sistema.siip.mx/crm/client/2\",\"Saldo Actual\": \"💲3150 a favor\",\"Monto Ultimo Pago\": \"$ 300\",\"Estado\": \"Activo\",\"Fecha Ultimo Pago\": \" 02/01/2026 20:18 con Personalizado 📝💸\",\"Fecha Ultima Actualizacion\": \"02/01/2026 23:24\",\"Clabe Interbancaria\": \"\",\"Site\": \"0LOCS\",\"Antena/Sectorial\": \"Sectorial-4b 172.16.13.16/24\"}"},"team":{"uuid":"5faeed738d6a44ccacf6509762eb288d","name":"General","default":true,"members":5,"createdAt":"2023-11-07T00:37:10Z"},"channel":{"uuid":"dbaa248932634e7ea4346a320960c24a","title":null,"type":"whatsapp","main":true},"blockedAt":null}} + +[2026-01-03 8:48:56.233753] [notice] Logging level set to:debug +[2026-01-03 8:48:56.233978] [debug] Payload recibido: {"uuid":"ca4f9a3e-7916-426b-838e-e91c82dd6367","changeType":"edit","entity":"job","entityId":"63","eventName":"job.edit","extraData":{"entity":{"id":63,"title":"Pruebas servicio 2","description":"revisar al maistro","assignedUserId":1019,"clientId":2,"date":"2025-12-26T11:00:13-0600","duration":60,"status":1,"address":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800, Mexico","gpsLat":null,"gpsLon":null,"attachments":[],"tasks":[{"id":3,"jobId":63,"label":"Revisar cable","closed":false}]},"entityBeforeEdit":{"id":63,"title":"Pruebas servicio 2","description":"revisar al maistro","assignedUserId":1019,"clientId":2,"date":"2025-12-26T11:00:13-0600","duration":60,"status":1,"address":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800, Mexico","gpsLat":null,"gpsLon":null,"attachments":[],"tasks":[]}}} + +[2026-01-03 8:48:56.281311] [debug] Evento recibido: job.edit +[2026-01-03 8:48:56.281493] [debug] Se actualiza un trabajo + +[2026-01-03 8:48:56.281546] [debug] Validando claves dentro de entityBeforeEdit y entity +[2026-01-03 8:48:56.281589] [debug] Edición de trabajo "En curso" sin cambios de fecha o técnico relevantes para notificación +[2026-01-03 8:49:37.604098] [notice] Logging level set to:debug +[2026-01-03 8:49:37.604178] [debug] Payload recibido: {"uuid":"d90bc798-099f-4ae8-b9d0-b4c740ac794f","changeType":"edit","entity":"job","entityId":"63","eventName":"job.edit","extraData":{"entity":{"id":63,"title":"Pruebas servicio 2","description":"revisar al maistro","assignedUserId":1019,"clientId":2,"date":"2025-12-26T11:00:13-0600","duration":60,"status":1,"address":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800, Mexico","gpsLat":null,"gpsLon":null,"attachments":[],"tasks":[{"id":3,"jobId":63,"label":"Revisar cable","closed":true}]},"entityBeforeEdit":{"id":63,"title":"Pruebas servicio 2","description":"revisar al maistro","assignedUserId":1019,"clientId":2,"date":"2025-12-26T11:00:13-0600","duration":60,"status":1,"address":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800, Mexico","gpsLat":null,"gpsLon":null,"attachments":[],"tasks":[{"id":3,"jobId":63,"label":"Revisar cable","closed":false}]}}} + +[2026-01-03 8:49:37.646231] [debug] Evento recibido: job.edit +[2026-01-03 8:49:37.646361] [debug] Se actualiza un trabajo + +[2026-01-03 8:49:37.646379] [debug] Validando claves dentro de entityBeforeEdit y entity +[2026-01-03 8:49:37.646394] [debug] Edición de trabajo "En curso" sin cambios de fecha o técnico relevantes para notificación +[2026-01-03 8:52:28.360755] [notice] Logging level set to:debug +[2026-01-03 8:52:28.360872] [debug] Payload recibido: {"uuid":"6cb97a30-6555-4a05-a496-ad372612d9ca","changeType":"edit","entity":"job","entityId":"63","eventName":"job.edit","extraData":{"entity":{"id":63,"title":"Pruebas servicio 2","description":"revisar al maistro","assignedUserId":1019,"clientId":2,"date":"2025-12-26T11:00:13-0600","duration":60,"status":1,"address":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800, Mexico","gpsLat":"21.1564414","gpsLon":"-100.9383654","attachments":[],"tasks":[{"id":3,"jobId":63,"label":"Revisar cable","closed":true}]},"entityBeforeEdit":{"id":63,"title":"Pruebas servicio 2","description":"revisar al maistro","assignedUserId":1019,"clientId":2,"date":"2025-12-26T11:00:13-0600","duration":60,"status":1,"address":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800, Mexico","gpsLat":null,"gpsLon":null,"attachments":[],"tasks":[{"id":3,"jobId":63,"label":"Revisar cable","closed":true}]}}} + +[2026-01-03 8:52:28.405308] [debug] Evento recibido: job.edit +[2026-01-03 8:52:28.405555] [debug] Se actualiza un trabajo + +[2026-01-03 8:52:28.405620] [debug] Validando claves dentro de entityBeforeEdit y entity +[2026-01-03 8:52:28.405638] [debug] Edición de trabajo "En curso" sin cambios de fecha o técnico relevantes para notificación +[2026-01-03 8:59:50.724664] [notice] Logging level set to:debug +[2026-01-03 8:59:50.724811] [debug] Payload recibido: {"uuid":"4afd1988-26d8-467e-9def-50da584814a4","changeType":"insert","entity":"service","entityId":"170","eventName":"service.add","extraData":{"entity":{"id":170,"prepaid":false,"clientId":173,"status":1,"name":"Basico 300","fullAddress":"baja california sur 23, Dolores Hidalgo, 37800","street1":"baja california sur 23","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","note":null,"addressGpsLat":21.1561965,"addressGpsLon":-100.9394271,"servicePlanId":6,"servicePlanPeriodId":26,"price":300,"hasIndividualPrice":false,"totalPrice":300,"currencyCode":"MXN","invoiceLabel":null,"contractId":null,"contractLengthType":1,"minimumContractLengthMonths":null,"activeFrom":"2026-01-03T00:00:00-0600","activeTo":null,"contractEndDate":null,"discountType":0,"discountValue":null,"discountInvoiceLabel":"Descuento","discountFrom":null,"discountTo":null,"tax1Id":null,"tax2Id":null,"tax3Id":null,"invoicingStart":"2026-01-03T00:00:00-0600","invoicingPeriodType":1,"invoicingPeriodStartDay":1,"nextInvoicingDayAdjustment":10,"invoicingProratedSeparately":true,"invoicingSeparately":false,"sendEmailsAutomatically":null,"useCreditAutomatically":true,"servicePlanName":"Basico 300","servicePlanPrice":300,"servicePlanPeriod":1,"servicePlanType":"Internet","downloadSpeed":8,"uploadSpeed":8,"hasOutage":false,"unmsClientSiteStatus":null,"fccBlockId":null,"lastInvoicedDate":null,"unmsClientSiteId":"7f593fb2-9b2c-4e44-9adf-403eac461495","attributes":[{"id":"e965ec6c-cc58-443f-9b0c-8a095c90abd6","serviceId":170,"customAttributeId":18,"name":"Extensor Wifi","key":"extensorWifi","value":"0","clientZoneVisible":true}],"addressData":null,"suspensionReasonId":null,"serviceChangeRequestId":null,"setupFeePrice":null,"earlyTerminationFeePrice":null,"downloadSpeedOverride":null,"uploadSpeedOverride":null,"trafficShapingOverrideEnd":null,"trafficShapingOverrideEnabled":false,"servicePlanGroupId":null,"suspensionPeriods":[],"surcharges":[]},"entityBeforeEdit":null}} + +[2026-01-03 8:59:50.991399] [debug] Evento recibido: service.add +[2026-01-03 9:00:04.167088] [notice] Logging level set to:debug +[2026-01-03 9:00:04.168425] [debug] Payload recibido: {"uuid":"a123917d-1a81-4c94-813a-0995e81c15d0","changeType":"edit","entity":"service","entityId":"170","eventName":"service.edit","extraData":{"entity":{"id":170,"prepaid":false,"clientId":173,"status":1,"name":"Basico 300","fullAddress":"baja california sur 23, Dolores Hidalgo, 37800","street1":"baja california sur 23","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","note":null,"addressGpsLat":21.1561965,"addressGpsLon":-100.9394271,"servicePlanId":6,"servicePlanPeriodId":26,"price":300,"hasIndividualPrice":false,"totalPrice":300,"currencyCode":"MXN","invoiceLabel":null,"contractId":null,"contractLengthType":1,"minimumContractLengthMonths":null,"activeFrom":"2026-01-03T00:00:00-0600","activeTo":null,"contractEndDate":null,"discountType":0,"discountValue":null,"discountInvoiceLabel":"Descuento","discountFrom":null,"discountTo":null,"tax1Id":null,"tax2Id":null,"tax3Id":null,"invoicingStart":"2026-01-03T00:00:00-0600","invoicingPeriodType":1,"invoicingPeriodStartDay":1,"nextInvoicingDayAdjustment":10,"invoicingProratedSeparately":true,"invoicingSeparately":false,"sendEmailsAutomatically":null,"useCreditAutomatically":true,"servicePlanName":"Basico 300","servicePlanPrice":300,"servicePlanPeriod":1,"servicePlanType":"Internet","downloadSpeed":8,"uploadSpeed":8,"hasOutage":false,"unmsClientSiteStatus":null,"fccBlockId":null,"lastInvoicedDate":null,"unmsClientSiteId":"7f593fb2-9b2c-4e44-9adf-403eac461495","attributes":[{"id":"e965ec6c-cc58-443f-9b0c-8a095c90abd6","serviceId":170,"customAttributeId":18,"name":"Extensor Wifi","key":"extensorWifi","value":"0","clientZoneVisible":true}],"addressData":null,"suspensionReasonId":null,"serviceChangeRequestId":null,"setupFeePrice":null,"earlyTerminationFeePrice":null,"downloadSpeedOverride":null,"uploadSpeedOverride":null,"trafficShapingOverrideEnd":null,"trafficShapingOverrideEnabled":false,"servicePlanGroupId":null,"suspensionPeriods":[],"surcharges":[]},"entityBeforeEdit":{"id":170,"prepaid":false,"clientId":173,"status":1,"name":"Basico 300","fullAddress":"baja california sur 23, Dolores Hidalgo, 37800","street1":"baja california sur 23","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","note":null,"addressGpsLat":21.1561965,"addressGpsLon":-100.9394271,"servicePlanId":6,"servicePlanPeriodId":26,"price":300,"hasIndividualPrice":false,"totalPrice":300,"currencyCode":"MXN","invoiceLabel":null,"contractId":null,"contractLengthType":1,"minimumContractLengthMonths":null,"activeFrom":"2026-01-03T00:00:00-0600","activeTo":null,"contractEndDate":null,"discountType":0,"discountValue":null,"discountInvoiceLabel":"Descuento","discountFrom":null,"discountTo":null,"tax1Id":null,"tax2Id":null,"tax3Id":null,"invoicingStart":"2026-01-03T00:00:00-0600","invoicingPeriodType":1,"invoicingPeriodStartDay":1,"nextInvoicingDayAdjustment":10,"invoicingProratedSeparately":true,"invoicingSeparately":false,"sendEmailsAutomatically":null,"useCreditAutomatically":true,"servicePlanName":"Basico 300","servicePlanPrice":300,"servicePlanPeriod":1,"servicePlanType":"Internet","downloadSpeed":8,"uploadSpeed":8,"hasOutage":false,"unmsClientSiteStatus":null,"fccBlockId":null,"lastInvoicedDate":null,"unmsClientSiteId":"7f593fb2-9b2c-4e44-9adf-403eac461495","attributes":[{"id":"e965ec6c-cc58-443f-9b0c-8a095c90abd6","serviceId":170,"customAttributeId":18,"name":"Extensor Wifi","key":"extensorWifi","value":"0","clientZoneVisible":true}],"addressData":null,"suspensionReasonId":null,"serviceChangeRequestId":null,"setupFeePrice":null,"earlyTerminationFeePrice":null,"downloadSpeedOverride":null,"uploadSpeedOverride":null,"trafficShapingOverrideEnd":null,"trafficShapingOverrideEnabled":false,"servicePlanGroupId":null,"suspensionPeriods":[],"surcharges":[]}}} + +[2026-01-03 9:00:04.415158] [debug] Evento recibido: service.edit +[2026-01-03 9:00:04.415359] [debug] Se editó el servicio a un cliente + +[2026-01-03 9:00:04.415507] [info] Iniciando verificación/sincronización de contraseña para el cliente ID: 173 diff --git a/src/Facade/AbstractMessageNotifierFacade.php b/src/Facade/AbstractMessageNotifierFacade.php index 35eb1c50..9d28ee1f 100755 --- a/src/Facade/AbstractMessageNotifierFacade.php +++ b/src/Facade/AbstractMessageNotifierFacade.php @@ -287,8 +287,9 @@ abstract class AbstractMessageNotifierFacade $allServicePasswords = []; $isTestEnv = ($ipServer === '172.16.5.134' || $ipServer === 'pruebas.internet.mx' || $ipServer === 'venus.siip.mx'); + $numServices = count($svcs); foreach ($svcs as $index => $svc) { - $label = "Servicio " . ($index + 1) . ":"; + $label = ($numServices > 1) ? "Servicio " . ($index + 1) . ":" : ""; $siteId = $svc['unmsClientSiteId'] ?? null; $passwordValue = ""; @@ -296,10 +297,24 @@ abstract class AbstractMessageNotifierFacade $passwordValue = "⚠️ Sin sitio"; } else { if ($isTestEnv) { - // Lógica de bypass: intentar recuperar de la cadena existente si existe y es válida - if (!empty($passCRM) && preg_match('/Servicio ' . ($index + 1) . ':\s*([^⚠️\s]+)/', $passCRM, $matches)) { - $passwordValue = $matches[1]; - } else { + // Lógica de bypass: intentar recuperar de la cadena existente + $foundInCRM = false; + if (!empty($passCRM)) { + if ($numServices > 1) { + if (preg_match('/Servicio ' . ($index + 1) . ':\s*([^⚠️\s]+)/', $passCRM, $matches)) { + $passwordValue = $matches[1]; + $foundInCRM = true; + } + } else { + // Caso de un solo servicio: si no tiene advertencias ni etiquetas, la tomamos a secas + if (strpos($passCRM, '⚠️') === false && strpos($passCRM, 'Servicio') === false) { + $passwordValue = trim($passCRM); + $foundInCRM = true; + } + } + } + + if (!$foundInCRM) { $passwordValue = $this->generateStrongPassword(16); } } else { @@ -352,7 +367,7 @@ abstract class AbstractMessageNotifierFacade } } } - $allServicePasswords[] = "$label $passwordValue"; + $allServicePasswords[] = trim("$label $passwordValue"); } $finalValue = implode(' ', $allServicePasswords); diff --git a/src/Facade/AbstractStripeOperationsFacade.php b/src/Facade/AbstractStripeOperationsFacade.php index 72b03cdc..102441b4 100755 --- a/src/Facade/AbstractStripeOperationsFacade.php +++ b/src/Facade/AbstractStripeOperationsFacade.php @@ -195,8 +195,9 @@ abstract class AbstractStripeOperationsFacade $allServicePasswords = []; $isTestEnv = ($ipServer === '172.16.5.134' || $ipServer === 'pruebas.internet.mx' || $ipServer === 'venus.siip.mx'); + $numServices = count($svcs); foreach ($svcs as $index => $svc) { - $label = "Servicio " . ($index + 1) . ":"; + $label = ($numServices > 1) ? "Servicio " . ($index + 1) . ":" : ""; $siteId = $svc['unmsClientSiteId'] ?? null; $passwordValue = ""; @@ -204,10 +205,24 @@ abstract class AbstractStripeOperationsFacade $passwordValue = "⚠️ Sin sitio"; } else { if ($isTestEnv) { - // Lógica de bypass: intentar recuperar de la cadena existente si existe y es válida - if (!empty($passCRM) && preg_match('/Servicio ' . ($index + 1) . ':\s*([^⚠️\s]+)/', $passCRM, $matches)) { - $passwordValue = $matches[1]; - } else { + // Lógica de bypass: intentar recuperar de la cadena existente + $foundInCRM = false; + if (!empty($passCRM)) { + if ($numServices > 1) { + if (preg_match('/Servicio ' . ($index + 1) . ':\s*([^⚠️\s]+)/', $passCRM, $matches)) { + $passwordValue = $matches[1]; + $foundInCRM = true; + } + } else { + // Caso de un solo servicio: si no tiene advertencias ni etiquetas, asumimos que es el pass + if (strpos($passCRM, '⚠️') === false && strpos($passCRM, 'Servicio') === false) { + $passwordValue = trim($passCRM); + $foundInCRM = true; + } + } + } + + if (!$foundInCRM) { $passwordValue = $this->generateStrongPassword(16); } } else { @@ -260,7 +275,7 @@ abstract class AbstractStripeOperationsFacade } } } - $allServicePasswords[] = "$label $passwordValue"; + $allServicePasswords[] = trim("$label $passwordValue"); } $finalValue = implode(' ', $allServicePasswords); diff --git a/src/Facade/ClientCallBellAPI.php b/src/Facade/ClientCallBellAPI.php index f9bbbdbe..105572cc 100755 --- a/src/Facade/ClientCallBellAPI.php +++ b/src/Facade/ClientCallBellAPI.php @@ -876,6 +876,7 @@ class ClientCallBellAPI $attributes = $notificationData->clientData['attributes']; //Obtener los atributos del cliente $site = ''; $antenaSectorial = ''; + $passAntenaUCRM = ''; // Iterar sobre los atributos foreach ($attributes as $attribute) { @@ -887,8 +888,29 @@ class ClientCallBellAPI if ($attribute['key'] === 'antenaSectorial') { $antenaSectorial = $attribute['value']; } + if ($attribute['key'] === 'passwordAntenaCliente') { + $passAntenaUCRM = $attribute['value'] ?? ''; + } } + // Parsear contraseñas multi-servicio a JSON + $passAntenaJSON = []; + if (!empty($passAntenaUCRM)) { + if (strpos($passAntenaUCRM, 'Servicio') !== false) { + // Buscamos patrones "Servicio X: " + // Usamos una expresión más robusta para capturar hasta el siguiente "Servicio" o el final de la cadena + preg_match_all('/Servicio (\d+):\s*(.*?)(?=\s*Servicio \d+:|$)/', $passAntenaUCRM, $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + $numServicio = "Servicio " . $match[1]; + $passAntenaJSON[$numServicio] = trim($match[2]); + } + } else { + // Un solo servicio sin etiqueta (o con advertencia ⚠️) + $passAntenaJSON["Servicio 1"] = trim($passAntenaUCRM); + } + } + $passAntenaFinal = !empty($passAntenaJSON) ? json_encode($passAntenaJSON) : ""; + $log->appendLog("Dentro del proceso del patch: " . PHP_EOL); $this->ucrmApi = UcrmApi::create(); $payments = $this->ucrmApi->get( @@ -917,16 +939,9 @@ class ClientCallBellAPI 'Content-Type: application/json', ]); - $ch2 = curl_init(); - curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch2, CURLOPT_CUSTOMREQUEST, 'PATCH'); - curl_setopt($ch2, CURLOPT_HTTPHEADER, [ - 'Authorization: Bearer ' . $this->CallBellAPIToken, - 'Content-Type: application/json', - ]); $UrlChatCallBell = 'https://api.callbell.eu/v1/contacts/' . $uuid; curl_setopt($ch, CURLOPT_URL, $UrlChatCallBell); - curl_setopt($ch2, CURLOPT_URL, $UrlChatCallBell); + $nombre_cliente = sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']); $log->appendLog("Nombre del cliente que se va a actualizar: " . $nombre_cliente . PHP_EOL); $log->appendLog("UUID: " . $uuid . PHP_EOL); @@ -978,22 +993,6 @@ class ClientCallBellAPI //$fecha_ultimoPago = $fecha_ultimoPago->modify('-6 hours'); $fecha_ultimoPago_ajustada = $fecha_ultimoPago->format("d/m/Y H:i"); - //$log->appendLog("las dos fechas ajustadas : " . $fecha_actual_ajustada.' aqui la otra: '.$fecha_ultimoPago_ajustada. PHP_EOL); - - // $attributes = $notificationData->clientData['attributes']; //Obtener los atributos del cliente - - // // Variable para almacenar los valores de los atributos que comienzan con "clabe" - // $clabeInterbancaria = ''; - - // // Iterar sobre los atributoss - // foreach ($attributes as $attribute) { - // // Verificar si la "key" comienza con "clabe" - // if (strpos($attribute['key'], 'clabe') === 0) { - // // Agregar el valor al array $clabeValues - // $clabeInterbancaria = $attribute['value']; - // } - // } - $accountBalance = $notificationData->clientData['accountBalance']; $saldoTexto = ''; @@ -1010,8 +1009,6 @@ class ClientCallBellAPI $resumenClienteJSON = '{' . '"Cliente": "' . $notificationData->clientData['id'] . '",' . - '"Domicilio": "' . - //(($notificationData->clientData['fullAddress'] == null) ? 'Sin domicilio' : '' . $notificationData->clientData['fullAddress']) . '",' . '"Nombre": "' . sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']) . '",' . '"URL": "https://sistema.siip.mx/crm/client/' . $notificationData->clientId . '",' . '"Saldo Actual": "' . $saldoTexto . '",' . @@ -1022,11 +1019,11 @@ class ClientCallBellAPI '"Fecha Ultima Actualizacion": "' . $fecha_actual_ajustada . '",' . '"Clabe Interbancaria": "' . $clabeInterbancaria . '",' . '"Site": "' . $site . '",' . - '"Antena/Sectorial": "' . $antenaSectorial . '"' . + '"Antena/Sectorial": "' . $antenaSectorial . '",' . + '"Password Antena": ' . (empty($passAntenaFinal) ? '""' : $passAntenaFinal) . '}'; $data_CRM = [ - //"uuid" => $json_responseAPI->contact->uuid, "name" => sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']), "custom_fields" => [ @@ -1043,74 +1040,34 @@ class ClientCallBellAPI "Clabe Interbancaria" => $clabeInterbancaria, "Site" => $site, "Antena/Sectorial" => $antenaSectorial, + "Password Antena" => $passAntenaFinal, ], ]; $log->appendLog("JSON con los datos a actualizar: " . json_encode($data_CRM) . PHP_EOL); - $data_CRM2 = [ - "custom_fields" => [ - "Resumen" => $resumenClienteJSON, - ], - ]; - - $log->appendLog("JSON con los datos a actualizar del resumen: " . $resumenClienteJSON . PHP_EOL); - + // OPT: Comparación inteligente para evitar patches innecesarios if ( $response_getContactCallBell['custom_fields']['Cliente'] != $data_CRM['custom_fields']['Cliente'] || $response_getContactCallBell['custom_fields']['Domicilio'] != $data_CRM['custom_fields']['Domicilio'] || $response_getContactCallBell['custom_fields']['Nombre'] != $data_CRM['custom_fields']['Nombre'] || $response_getContactCallBell['custom_fields']['URL'] != $data_CRM['custom_fields']['URL'] - || $response_getContactCallBell['custom_fields']['Saldo'] != $data_CRM['custom_fields']['Saldo'] + || $response_getContactCallBell['custom_fields']['Saldo Actual'] != $data_CRM['custom_fields']['Saldo Actual'] || $response_getContactCallBell['custom_fields']['Estado'] != $data_CRM['custom_fields']['Estado'] || $response_getContactCallBell['custom_fields']['Fecha Ultimo Pago'] != $data_CRM['custom_fields']['Fecha Ultimo Pago'] || $response_getContactCallBell['custom_fields']['Monto Ultimo Pago'] != $data_CRM['custom_fields']['Monto Ultimo Pago'] + || ($response_getContactCallBell['custom_fields']['Password Antena'] ?? '') != $data_CRM['custom_fields']['Password Antena'] || $response_getContactCallBell['name'] != $data_CRM['name'] ) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data_CRM)); - curl_setopt($ch2, CURLOPT_POSTFIELDS, json_encode($data_CRM2)); $response = curl_exec($ch); $log->appendLog("Response Patch CallBell: " . $response . PHP_EOL); - $response2 = curl_exec($ch2); - $log->appendLog("Response 2 Patch CallBell: " . $response2 . PHP_EOL); curl_close($ch); - curl_close($ch2); - - // if($fileNameComprobante != null){ - // sleep(3); - // $this->deleteFileWordPressAndLocal($fileNameComprobante); - // } - - // $json_data_patch = '{ - // "attributes": [ - // { - // "value": "' . $UrlChatCallBell . '", - // "customAttributeId": 21 - // } - // ] - - // }'; //JSON para hacer patch de los custom fields del cliente en el UISCP CRM, Campo para el Stripe Customer ID y la Clabe interbancaria - - // $clientguzz = new Client(); //instancia de cliente GuzzleHttp para consumir API UISP CRM - // try { - // $responseCRM = $clientguzz->patch($baseUri . 'clients/' . $notificationData->clientData['id'], [ - // 'json' => json_decode($json_data_patch, true), - // 'headers' => [ - // 'X-Auth-App-Key' => $token, // Cambia el nombre de la cabecera de autorización - // 'Accept' => 'application/json', // Indica que esperamos una respuesta en formato JSON - // ], - // 'verify' => false, - // ]); //aquí se contruye la petición para hacer patch hacia el cliente en sus custom fields con la API del UISP UCRM - - // } catch (GuzzleException $error) { - // echo "Error al hacer el patch al CRM: " . $error->getMessage() . PHP_EOL; - // //exit(); - // } - // $log->appendLog(json_encode($responseCRM) . PHP_EOL); //imprimir respuesta del patch de CRM con la clabe y Customer ID Stripe } else { $log->appendLog("No hay cambios que actualizar " . PHP_EOL); + curl_close($ch); } }