# Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.iap.tools import iap_tools from odoo.tools.translate import _, LazyTranslate _lt = LazyTranslate(__name__) ERROR_MESSAGES = { # Errors that could occur while updating sender name 'format_error': _lt("Your sender name must be between 3 and 11 characters long and only contain alphanumeric characters."), 'unregistered_account': _lt("Your sms account has not been activated yet."), 'existing_sender': _lt("This account already has an existing sender name and it cannot be changed."), # Errors that could occur while sending the verification code 'invalid_phone_number': _lt("Invalid phone number. Please make sure to follow the international format, i.e. a plus sign (+), then country code, city code, and local phone number. For example: +1 555-555-555"), 'verification_sms_delivery': _lt( "We were not able to reach you via your phone number. " "If you have requested multiple codes recently, please retry later." ), 'closed_feature': _lt("The SMS Service is currently unavailable for new users and new accounts registrations are suspended."), 'banned_account': _lt("This phone number/account has been banned from our service."), # Errors that could occur while verifying the code 'invalid_code': _lt("The verification code is incorrect."), 'no_sms_account': _lt("We were not able to find your account in our database."), 'too_many_attempts': _lt("You tried too many times. Please retry later."), # Default error 'unknown_error': _lt("An unknown error occurred. Please contact Odoo support if this error persists."), } class SmsApi: DEFAULT_ENDPOINT = 'https://sms.api.odoo.com' def __init__(self, env, account=None): self.env = env self.account = account or self.env['iap.account'].get('sms') def _contact_iap(self, local_endpoint, params, timeout=15): params['account_token'] = self.account.account_token endpoint = self.env['ir.config_parameter'].sudo().get_param('sms.endpoint', self.DEFAULT_ENDPOINT) return iap_tools.iap_jsonrpc(endpoint + local_endpoint, params=params, timeout=timeout) def _send_sms_batch(self, messages, delivery_reports_url=False): """ Send SMS using IAP in batch mode :param list messages: list of SMS (grouped by content) to send: formatted as ```[ { 'content' : str, 'numbers' : [ { 'uuid' : str, 'number' : str }, { 'uuid' : str, 'number' : str }, ... ] }, ... ]``` :param str delivery_reports_url: url to route receiving delivery reports :return: response from the endpoint called, which is a list of results formatted as ```[ { uuid: UUID of the request, state: ONE of: { 'success', 'processing', 'server_error', 'unregistered', 'insufficient_credit', 'wrong_number_format', 'duplicate_message', 'country_not_supported', 'registration_needed', }, credit: Optional: Credits spent to send SMS (provided if the actual price is known) }, ... ]``` """ return self._contact_iap('/api/sms/3/send', { 'messages': messages, 'webhook_url': delivery_reports_url, 'dbuuid': self.env['ir.config_parameter'].sudo().get_param('database.uuid') }) def _get_sms_api_error_messages(self): """Return a mapping of `_send_sms_batch` errors to an error message. We prefer a dict instead of a message-per-error-state based method so that we only call config parameters getters once and avoid extra RPC calls.""" buy_credits_url = self.env['iap.account'].sudo().get_credits_url(service_name='sms') buy_credits = '{}'.format(buy_credits_url, _("Buy credits.")) sms_endpoint = self.env['ir.config_parameter'].sudo().get_param('sms.endpoint', self.DEFAULT_ENDPOINT) sms_account_token = self.env['iap.account'].sudo().get('sms').account_token register_now = f'%s' % ( _('Register now.') ) return { 'unregistered': _("You don't have an eligible IAP account."), 'insufficient_credit': ' '.join([_("You don't have enough credits on your IAP account."), buy_credits]), 'wrong_number_format': _("The number you're trying to reach is not correctly formatted."), 'duplicate_message': _("This SMS has been removed as the number was already used."), 'country_not_supported': _("The destination country is not supported."), 'incompatible_content': _("The content of the message violates rules applied by our providers."), 'registration_needed': ' '.join([_("Country-specific registration required."), register_now]), } def _send_verification_sms(self, phone_number): return self._contact_iap('/api/sms/1/account/create', { 'phone_number': phone_number, }) def _verify_account(self, verification_code): return self._contact_iap('/api/sms/2/account/verify', { 'code': verification_code, }) def _set_sender_name(self, sender_name): return self._contact_iap('/api/sms/1/account/update_sender', { 'sender_name': sender_name, })