117 lines
5.3 KiB
Python
117 lines
5.3 KiB
Python
import logging
|
|
import requests
|
|
|
|
from odoo import _
|
|
from odoo.addons.sms.tools.sms_api import SmsApiBase
|
|
from odoo.addons.sms_twilio.tools.sms_twilio import get_twilio_from_number, get_twilio_status_callback_url
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SmsApiTwilio(SmsApiBase):
|
|
PROVIDER_TO_SMS_FAILURE_TYPE = SmsApiBase.PROVIDER_TO_SMS_FAILURE_TYPE | {
|
|
'twilio_acc_unverified': 'sms_acc',
|
|
'twilio_authentication': 'sms_credit',
|
|
'twilio_callback': 'twilio_callback',
|
|
'twilio_from_missing': 'twilio_from_missing',
|
|
'twilio_from_to': 'twilio_from_to',
|
|
}
|
|
|
|
def _sms_twilio_send_request(self, session, to_number, body, uuid):
|
|
company_sudo = (self.company or self.env.company).sudo()
|
|
company_sudo._assert_twilio_sid()
|
|
from_number = get_twilio_from_number(company_sudo, to_number)
|
|
data = {
|
|
'From': from_number.number or '', # avoid 'False', to have clear missing From error
|
|
'To': to_number,
|
|
'Body': body,
|
|
'StatusCallback': get_twilio_status_callback_url(company_sudo, uuid),
|
|
}
|
|
try:
|
|
return session.post(
|
|
f'https://api.twilio.com/2010-04-01/Accounts/{company_sudo.sms_twilio_account_sid}/Messages.json',
|
|
data=data,
|
|
auth=(company_sudo.sms_twilio_account_sid, company_sudo.sms_twilio_auth_token),
|
|
timeout=5,
|
|
)
|
|
except requests.exceptions.RequestException as e:
|
|
_logger.warning('Twilio SMS API error: %s', str(e))
|
|
return None
|
|
|
|
def _send_sms_batch(self, messages, delivery_reports_url=False):
|
|
""" Send a batch of SMS using twilio.
|
|
See params and returns in original method sms/tools/sms_api.py
|
|
In addition to the uuid and state, we add the sms_twilio_sid to the returns (one per sms)
|
|
"""
|
|
# Use a session as we have to sequentially call twilio, might save time
|
|
session = requests.Session()
|
|
|
|
res = []
|
|
for message in messages:
|
|
body = message.get('content') or ''
|
|
for number_info in message.get('numbers') or []:
|
|
uuid = number_info['uuid']
|
|
response = self._sms_twilio_send_request(session, number_info['number'], body, uuid)
|
|
fields_values = {
|
|
'failure_reason': _("Unknown failure at sending, please contact Odoo support"),
|
|
'state': 'server_error',
|
|
'uuid': uuid,
|
|
}
|
|
if response is not None:
|
|
response_json = response.json()
|
|
if not response.ok or response_json.get('error'):
|
|
failure_type = self._twilio_error_code_to_odoo_state(response_json)
|
|
error_message = response_json.get('message') or response_json.get('error_message') or self._get_sms_api_error_messages().get(failure_type)
|
|
fields_values.update({
|
|
'failure_reason': error_message,
|
|
'failure_type': failure_type,
|
|
'state': failure_type,
|
|
})
|
|
else:
|
|
fields_values.update({
|
|
'failure_reason': False,
|
|
'failure_type': False,
|
|
'sms_twilio_sid': response_json.get('sid'),
|
|
'state': 'sent',
|
|
})
|
|
res.append(fields_values)
|
|
return res
|
|
|
|
def _twilio_error_code_to_odoo_state(self, response_json):
|
|
error_code = response_json.get('code') or response_json.get('error_code')
|
|
# number issues
|
|
if error_code in (21211, 21614, 21265): # See https://www.twilio.com/docs/errors/xxxxx
|
|
return "wrong_number_format"
|
|
elif error_code == 21604:
|
|
# A "To" phone number is required
|
|
return "sms_number_missing"
|
|
elif error_code == 21266:
|
|
return "twilio_from_to"
|
|
elif error_code == 21603:
|
|
return "twilio_from_missing"
|
|
# configuration
|
|
elif error_code == 21608:
|
|
return "twilio_acc_unverified"
|
|
elif error_code == 21609:
|
|
# Twilio StatusCallback URL is incorrect
|
|
return "twilio_callback"
|
|
_logger.warning('Twilio SMS: Unknown error "%s" (code: %s)', response_json.get('message'), error_code)
|
|
return "unknown"
|
|
|
|
def _get_sms_api_error_messages(self):
|
|
# TDE TODO: clean failure type management
|
|
error_dict = super()._get_sms_api_error_messages()
|
|
error_dict.update({
|
|
'sms_acc': _("Trial Account Limitation"),
|
|
'sms_number_missing': _("A 'To' phone number is required"),
|
|
'twilio_acc_unverified': _("Unverified recipient on Trial Account"),
|
|
'twilio_authentication': _("Twilio Authentication Error"),
|
|
'twilio_callback': _("Twilio StatusCallback URL is incorrect"),
|
|
'twilio_from_missing': ("A 'From' number is required to send a message"),
|
|
'twilio_from_to': _("'To' and 'From' numbers cannot be the same"),
|
|
'wrong_number_format': _("The number you're trying to reach is not correctly formatted"),
|
|
# fallback
|
|
'unknown': _("Unknown error, please contact Odoo support"),
|
|
})
|
|
return error_dict
|