Adición de los eventos: [invoice.draft_approved, invoice.add_draft] para sincronizar el saldo del cliente a CallBell así como del evento service.edit

This commit is contained in:
server 2025-02-18 23:27:27 +00:00
parent c3824ba827
commit 398dcc462f
7 changed files with 1574 additions and 61 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.pdf
*.log
*.png
.vscode/
*.zip

View File

@ -1,7 +1,6 @@
# SMS notifier - Twilio # SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp
* This plugin sends SMS notifications to clients. * This plugin sends WhatsApp notifications to clients.
* SMS is triggered by an event which happened in UCRM, e.g. new invoice has been issued, or client's sevice became suspended.
* It only sends SMS to clients having a phone number set in their contacts details. * It only sends SMS to clients having a phone number set in their contacts details.
* [Twilio](https://www.twilio.com/) account is required to access its API. * [Twilio](https://www.twilio.com/) account is required to access its API.
@ -29,7 +28,7 @@ Note: there are two sets of credentials available, the default ("LIVE credential
## Usage ## Usage
* In UCRM admin, go to System / Webhooks / Endpoints * In UCRM admin, go to System / Webhooks / Endpoints
* Click Test Endpoint * Click Test Endpoint
* Go to System / Plugins / SMS notifications via Twilio * Go to System / Plugins / SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp
* In the log output, you'll see `Webhook test successful.` * In the log output, you'll see `Webhook test successful.`
## Variables replaced ## Variables replaced
@ -206,7 +205,7 @@ Client variables are replaced always; payment invoice and service only with the
* Replace the TwilioNotifierFacade and any references to it with a different class which extends AbstractMessageNotifierFacade * Replace the TwilioNotifierFacade and any references to it with a different class which extends AbstractMessageNotifierFacade
* Update libraries in composer.json as needed * Update libraries in composer.json as needed
* Communicate with the remote system in the sendMessage() function * Communicate with the remote system in the sendMessage() function
* Preferably also change the SmsNotifier namespace to some other (not strictly necessary).
Read more about creating your own plugin in the [Developer documentation](https://github.com/Ubiquiti-App/UCRM-plugins/blob/master/docs/index.md). Read more about creating your own plugin in the [Developer documentation](https://github.com/Ubiquiti-App/UCRM-plugins/blob/master/docs/index.md).

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
"displayName": "SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp", "displayName": "SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp",
"description": "Este plugin sincroniza los clientes del sitema UISP CRM con los contactos de WhatsApp en CallBell, además procesa pagos de Stripe como las trasferencias bancarias y genera referencias de pago vía OXXO, además envía comprobantes de pago en formato imagen PNG o texto vía Whatsapp a los clientes", "description": "Este plugin sincroniza los clientes del sitema UISP CRM con los contactos de WhatsApp en CallBell, además procesa pagos de Stripe como las trasferencias bancarias y genera referencias de pago vía OXXO, además envía comprobantes de pago en formato imagen PNG o texto vía Whatsapp a los clientes",
"url": "https://siip.mx/", "url": "https://siip.mx/",
"version": "2.6.5", "version": "2.6.6",
"unmsVersionCompliancy": { "unmsVersionCompliancy": {
"min": "2.1.0", "min": "2.1.0",
"max": null "max": null

View File

@ -298,7 +298,7 @@ abstract class AbstractMessageNotifierFacade
break; break;
} }
} }
$this->logger->debug('tipo de dato de installerWhatsApp: ' . gettype($installerWhatsApp) . PHP_EOL); //$this->logger->debug('tipo de dato de installerWhatsApp: ' . gettype($installerWhatsApp) . PHP_EOL);
// Validar si se encontró el WhatsApp // Validar si se encontró el WhatsApp
if (empty($installerWhatsApp)) { if (empty($installerWhatsApp)) {
@ -309,7 +309,8 @@ abstract class AbstractMessageNotifierFacade
$this->ucrmApi = UcrmApi::create(); $this->ucrmApi = UcrmApi::create();
$usersInstallers = $this->ucrmApi->get('users/admins/' . $installerId, []); $usersInstallers = $this->ucrmApi->get('users/admins/' . $installerId, []);
$this->logger->debug('Valor de $usersInstallers ' . json_encode($usersInstallers) . PHP_EOL); //$this->logger->debug('Valor de $usersInstallers ' . json_encode($usersInstallers) . PHP_EOL);
$firstName = $usersInstallers['firstName'] ?? ''; $firstName = $usersInstallers['firstName'] ?? '';
$lastName = $usersInstallers['lastName'] ?? ''; $lastName = $usersInstallers['lastName'] ?? '';
$installerFullName = trim("$firstName $lastName"); $installerFullName = trim("$firstName $lastName");

View File

@ -222,59 +222,13 @@ class Plugin
$configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create(); $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
$config = $configManager->loadConfig(); $config = $configManager->loadConfig();
//ejemplo de json con etoquetas o tags: {"uuid":"52d0f856-fa68-42c3-b706-d94a82adcb51","changeType":"edit","entity":"client","entityId":"144","eventName":"client.edit","extraData":{"entity":{"id":144,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"56 Avenida Norte","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Avenida Norte 56, Dolores, Dolores Hidalgo Cuna de la Independencia Nacional, Gto., M\u00e9xico","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-07-29T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"El More","lastName":"L\u00f3pez","username":null,"contacts":[{"id":148,"clientId":144,"email":"elmorelopez2014@gmail.com","phone":null,"name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[{"id":3,"name":"STRIPE","colorBackground":"#e30000","colorText":"#fff"},{"id":2,"name":"NS EXENTO","colorBackground":"#42a3df","colorText":"#fff"}],"invitationEmailSentDate":null,"avatarColor":"#607d8b","addressGpsLat":21.1652947,"addressGpsLon":-100.940078,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"entityBeforeEdit":{"id":144,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"56 Avenida Norte","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Avenida Norte 56, Dolores, Dolores Hidalgo Cuna de la Independencia Nacional, Gto., M\u00e9xico","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-07-29T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"El More","lastName":"L\u00f3pez","username":null,"contacts":[{"id":148,"clientId":144,"email":"elmorelopez2014@gmail.com","phone":null,"name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[{"id":3,"name":"STRIPE","colorBackground":"#e30000","colorText":"#fff"}],"invitationEmailSentDate":null,"avatarColor":"#607d8b","addressGpsLat":21.1652947,"addressGpsLon":-100.940078,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}}} //ejemplo de json para facturas de borrador: {"uuid":"cc5164fa-a7ec-483a-ae62-1eb02e69d82c","changeType":"insert","entity":"invoice","entityId":"1563","eventName":"invoice.add_draft","extraData":{"entity":{"id":1563,"clientId":2,"number":"001521","createdDate":"2025-02-18T12:48:43-0600","dueDate":"2025-03-04T12:48:43-0600","emailSentDate":null,"maturityDays":14,"taxableSupplyDate":"2025-02-18T00:00:00-0600","notes":null,"adminNotes":null,"items":[{"id":1566,"type":"service","label":"PREMIUM 18\/02\/2025 \u2013 28\/02\/2025","price":700,"quantity":0.36666666666666664,"total":256.66666666666663,"unit":null,"tax1Id":null,"tax2Id":null,"tax3Id":null,"serviceId":134,"serviceSurchargeId":null,"productId":null,"feeId":null,"discountPrice":0,"discountQuantity":0,"discountTotal":0}],"subtotal":256.67,"discount":null,"discountLabel":"Descuento","taxes":[],"total":256.67,"amountPaid":0,"totalUntaxed":256.67,"totalDiscount":0,"totalTaxAmount":0,"amountToPay":256.67,"currencyCode":"MXN","status":1,"paymentCovers":[],"invoiceTemplateId":2,"proformaInvoiceTemplateId":2,"organizationName":"SIIP Pruebas","organizationRegistrationNumber":null,"organizationTaxId":null,"organizationStreet1":"Morel 34","organizationStreet2":null,"organizationCity":"Dolores Hidalgo","organizationStateId":null,"organizationCountryId":173,"organizationZipCode":"37800","organizationBankAccountName":null,"organizationBankAccountField1":null,"organizationBankAccountField2":null,"clientFirstName":"Daniel Humberto","clientLastName":"Soto Villegas el boy","clientCompanyName":null,"clientCompanyRegistrationNumber":null,"clientCompanyTaxId":null,"clientStreet1":"31 Chiapas","clientStreet2":null,"clientCity":"Dolores Hidalgo Cuna de la Independencia Nacional","clientCountryId":173,"clientStateId":null,"clientZipCode":"37800","attributes":[],"uncollectible":false,"proforma":false,"generatedInvoiceId":null,"proformaInvoiceId":null,"isAppliedVatReverseCharge":false,"payAutomatically":false},"entityBeforeEdit":null}}
$jsonTest = '{"uuid":"79009823-1415-47b2-b170-304db4010453","changeType":"edit","entity":"client","entityId":"167","eventName":"client.edit","extraData":{"entity":{"id":167,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"34 Avenida Sur","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Avenida Sur 34, Centro, Dolores Hidalgo Cuna de la Independencia Nacional, Gto., M\u00e9xico","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2025-02-10T00:00:00-0600","leadConvertedAt":"2025-02-10T23:11:22-0600","companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Javier","lastName":"Alatorre","username":null,"contacts":[{"id":173,"clientId":167,"email":null,"phone":"4181878106","name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[{"id":174,"clientId":167,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_Rkh9CoRTpjlZUu","clientZoneVisible":true},{"id":175,"clientId":167,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"124180228993431717","clientZoneVisible":true}],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[{"id":3,"name":"STRIPE","colorBackground":"#e30000","colorText":"#fff"}],"invitationEmailSentDate":null,"avatarColor":"#6a1b9a","addressGpsLat":21.1519382,"addressGpsLon":-100.9371879,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"entityBeforeEdit":{"id":167,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"34 Avenida Sur","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Avenida Sur 34, Centro, Dolores Hidalgo Cuna de la Independencia Nacional, Gto., M\u00e9xico","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2025-02-10T00:00:00-0600","leadConvertedAt":"2025-02-10T23:11:22-0600","companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Javier","lastName":"Alatorre","username":null,"contacts":[{"id":173,"clientId":167,"email":null,"phone":"4181878106","name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[{"id":174,"clientId":167,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_Rkh9CoRTpjlZUu","clientZoneVisible":true},{"id":175,"clientId":167,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"124180228993431717","clientZoneVisible":true}],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#6a1b9a","addressGpsLat":21.1519382,"addressGpsLon":-100.9371879,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}}}';
$jsonTest = '{"uuid":"cc5164fa-a7ec-483a-ae62-1eb02e69d82c","changeType":"insert","entity":"invoice","entityId":"1563","eventName":"invoice.add_draft","extraData":{"entity":{"id":1563,"clientId":2,"number":"001521","createdDate":"2025-02-18T12:48:43-0600","dueDate":"2025-03-04T12:48:43-0600","emailSentDate":null,"maturityDays":14,"taxableSupplyDate":"2025-02-18T00:00:00-0600","notes":null,"adminNotes":null,"items":[{"id":1566,"type":"service","label":"PREMIUM 18\/02\/2025 \u2013 28\/02\/2025","price":700,"quantity":0.36666666666666664,"total":256.66666666666663,"unit":null,"tax1Id":null,"tax2Id":null,"tax3Id":null,"serviceId":134,"serviceSurchargeId":null,"productId":null,"feeId":null,"discountPrice":0,"discountQuantity":0,"discountTotal":0}],"subtotal":256.67,"discount":null,"discountLabel":"Descuento","taxes":[],"total":256.67,"amountPaid":0,"totalUntaxed":256.67,"totalDiscount":0,"totalTaxAmount":0,"amountToPay":256.67,"currencyCode":"MXN","status":1,"paymentCovers":[],"invoiceTemplateId":2,"proformaInvoiceTemplateId":2,"organizationName":"SIIP Pruebas","organizationRegistrationNumber":null,"organizationTaxId":null,"organizationStreet1":"Morel 34","organizationStreet2":null,"organizationCity":"Dolores Hidalgo","organizationStateId":null,"organizationCountryId":173,"organizationZipCode":"37800","organizationBankAccountName":null,"organizationBankAccountField1":null,"organizationBankAccountField2":null,"clientFirstName":"Daniel Humberto","clientLastName":"Soto Villegas el boy","clientCompanyName":null,"clientCompanyRegistrationNumber":null,"clientCompanyTaxId":null,"clientStreet1":"31 Chiapas","clientStreet2":null,"clientCity":"Dolores Hidalgo Cuna de la Independencia Nacional","clientCountryId":173,"clientStateId":null,"clientZipCode":"37800","attributes":[],"uncollectible":false,"proforma":false,"generatedInvoiceId":null,"proformaInvoiceId":null,"isAppliedVatReverseCharge":false,"payAutomatically":false},"entityBeforeEdit":null}}
';
$jsonData = json_decode($jsonTest, true); $jsonData = json_decode($jsonTest, true);
// Validar que 'entity' y 'entityBeforeEdit' existen y contienen las clave 'tags' y buscar si existe la etiqueta 'STRIPE' en entity pero no en entityBeforeEdit $accountBalance = $jsonData['extraData']['entity']['tags'];
if (
isset($jsonData['extraData']['entity']['tags']) &&
isset($jsonData['extraData']['entityBeforeEdit']['tags'])
) {
$tags = $jsonData['extraData']['entity']['tags'];
$tagsBefore = $jsonData['extraData']['entityBeforeEdit']['tags'];
$this->logger->debug('Validando claves dentro de entity y entityBeforeEdit');
// Validar que 'tags' existe en ambas entidades
if (array_key_exists('tags', $jsonData['extraData']['entity']) && array_key_exists('tags', $jsonData['extraData']['entityBeforeEdit'])) {
$this->logger->debug('Los datos entity y entityBeforeEdit contienen el campo tags');
$tags = $jsonData['extraData']['entity']['tags'];
$tagsBefore = $jsonData['extraData']['entityBeforeEdit']['tags'];
$this->logger->debug('Validando si la etiqueta STRIPE existe en entity pero no en entityBeforeEdit');
// Comprobar si la etiqueta 'STRIPE' existe en 'tags' pero no en 'tagsBefore'
$stripeTagExists = false;
$stripeTagExistsBefore = false;
foreach ($tags as $tag) {
if ($tag['name'] === 'STRIPE') {
$stripeTagExists = true;
break;
}
}
foreach ($tagsBefore as $tag) {
if ($tag['name'] === 'STRIPE') {
$stripeTagExistsBefore = true;
break;
}
}
// Comprobar si la etiqueta 'STRIPE' existe en 'tags' pero no en 'tagsBefore'
if ($stripeTagExists && !$stripeTagExistsBefore) {
$this->logger->debug('La etiqueta STRIPE se agregó al cliente');
$this->pluginNotifierFacade->createStripeClient($jsonData);
} else {
$this->logger->debug('La etiqueta STRIPE no se agregó al cliente');
}
} else {
$this->logger->warning('El campo tags no existe en entity o entityBeforeEdit');
}
} else {
$this->logger->warning('Los datos entity o entityBeforeEdit no están presentes en extraData');
}
$this->logger->info('Webhook test successful.'); $this->logger->info('Webhook test successful.');
@ -493,7 +447,10 @@ class Plugin
// $this->logger->warning('El campo isLead no existe en los datos del evento'); // $this->logger->warning('El campo isLead no existe en los datos del evento');
// } // }
} else if ($notification->eventName === 'service.suspend') { } else if ($notification->eventName === 'service.edit') {
$this->logger->debug('Se editó el servicio a un cliente' . PHP_EOL);
$this->notifierFacade->verifyServiceActionToDo($notification);
}else if ($notification->eventName === 'service.suspend') {
$this->logger->debug('Se suspendió el servicio a un cliente' . PHP_EOL); $this->logger->debug('Se suspendió el servicio a un cliente' . PHP_EOL);
$this->notifierFacade->verifyServiceActionToDo($notification); $this->notifierFacade->verifyServiceActionToDo($notification);
} else if ($notification->eventName === 'service.suspend_cancel') { } else if ($notification->eventName === 'service.suspend_cancel') {
@ -523,6 +480,12 @@ class Plugin
} else if ($notification->eventName === 'invoice.edit') { } else if ($notification->eventName === 'invoice.edit') {
$this->logger->debug('Edición de Factura' . PHP_EOL); $this->logger->debug('Edición de Factura' . PHP_EOL);
$this->notifierFacade->verifyInvoiceActionToDo($notification); $this->notifierFacade->verifyInvoiceActionToDo($notification);
} else if ($notification->eventName === 'invoice.add_draft') {
$this->logger->debug('Adición de borrador de Factura' . PHP_EOL);
$this->notifierFacade->verifyInvoiceActionToDo($notification);
} else if ($notification->eventName === 'invoice.draft_approved') {
$this->logger->debug('Aprobación de Factura' . PHP_EOL);
$this->notifierFacade->verifyInvoiceActionToDo($notification);
} else if ($notification->eventName === 'job.add') { } else if ($notification->eventName === 'job.add') {
$this->logger->debug('Se ha agregado un nuevo trabajo' . PHP_EOL); $this->logger->debug('Se ha agregado un nuevo trabajo' . PHP_EOL);

View File

@ -5,7 +5,7 @@
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => 'e1e3f409c90cfd5edbae6d9c1ad7065106555849', 'reference' => 'c3824ba827c740086875251761ced485fb46b070',
'name' => 'ucrm-plugins/sms-twilio', 'name' => 'ucrm-plugins/sms-twilio',
'dev' => false, 'dev' => false,
), ),
@ -307,7 +307,7 @@
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => 'e1e3f409c90cfd5edbae6d9c1ad7065106555849', 'reference' => 'c3824ba827c740086875251761ced485fb46b070',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
), ),