summaryrefslogtreecommitdiff
path: root/addons/sms/models/sms_sms.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/sms/models/sms_sms.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/sms/models/sms_sms.py')
-rw-r--r--addons/sms/models/sms_sms.py143
1 files changed, 143 insertions, 0 deletions
diff --git a/addons/sms/models/sms_sms.py b/addons/sms/models/sms_sms.py
new file mode 100644
index 00000000..a1c197a6
--- /dev/null
+++ b/addons/sms/models/sms_sms.py
@@ -0,0 +1,143 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import logging
+import threading
+
+from odoo import api, fields, models, tools
+
+_logger = logging.getLogger(__name__)
+
+
+class SmsSms(models.Model):
+ _name = 'sms.sms'
+ _description = 'Outgoing SMS'
+ _rec_name = 'number'
+ _order = 'id DESC'
+
+ IAP_TO_SMS_STATE = {
+ 'success': 'sent',
+ 'insufficient_credit': 'sms_credit',
+ 'wrong_number_format': 'sms_number_format',
+ 'server_error': 'sms_server',
+ 'unregistered': 'sms_acc'
+ }
+
+ number = fields.Char('Number')
+ body = fields.Text()
+ partner_id = fields.Many2one('res.partner', 'Customer')
+ mail_message_id = fields.Many2one('mail.message', index=True)
+ state = fields.Selection([
+ ('outgoing', 'In Queue'),
+ ('sent', 'Sent'),
+ ('error', 'Error'),
+ ('canceled', 'Canceled')
+ ], 'SMS Status', readonly=True, copy=False, default='outgoing', required=True)
+ error_code = fields.Selection([
+ ('sms_number_missing', 'Missing Number'),
+ ('sms_number_format', 'Wrong Number Format'),
+ ('sms_credit', 'Insufficient Credit'),
+ ('sms_server', 'Server Error'),
+ ('sms_acc', 'Unregistered Account'),
+ # mass mode specific codes
+ ('sms_blacklist', 'Blacklisted'),
+ ('sms_duplicate', 'Duplicate'),
+ ], copy=False)
+
+ def send(self, delete_all=False, auto_commit=False, raise_exception=False):
+ """ Main API method to send SMS.
+
+ :param delete_all: delete all SMS (sent or not); otherwise delete only
+ sent SMS;
+ :param auto_commit: commit after each batch of SMS;
+ :param raise_exception: raise if there is an issue contacting IAP;
+ """
+ for batch_ids in self._split_batch():
+ self.browse(batch_ids)._send(delete_all=delete_all, raise_exception=raise_exception)
+ # auto-commit if asked except in testing mode
+ if auto_commit is True and not getattr(threading.currentThread(), 'testing', False):
+ self._cr.commit()
+
+ def cancel(self):
+ self.state = 'canceled'
+
+ @api.model
+ def _process_queue(self, ids=None):
+ """ Send immediately queued messages, committing after each message is sent.
+ This is not transactional and should not be called during another transaction!
+
+ :param list ids: optional list of emails ids to send. If passed no search
+ is performed, and these ids are used instead.
+ """
+ domain = [('state', '=', 'outgoing')]
+
+ filtered_ids = self.search(domain, limit=10000).ids # TDE note: arbitrary limit we might have to update
+ if ids:
+ ids = list(set(filtered_ids) & set(ids))
+ else:
+ ids = filtered_ids
+ ids.sort()
+
+ res = None
+ try:
+ # auto-commit except in testing mode
+ auto_commit = not getattr(threading.currentThread(), 'testing', False)
+ res = self.browse(ids).send(delete_all=False, auto_commit=auto_commit, raise_exception=False)
+ except Exception:
+ _logger.exception("Failed processing SMS queue")
+ return res
+
+ def _split_batch(self):
+ batch_size = int(self.env['ir.config_parameter'].sudo().get_param('sms.session.batch.size', 500))
+ for sms_batch in tools.split_every(batch_size, self.ids):
+ yield sms_batch
+
+ def _send(self, delete_all=False, raise_exception=False):
+ """ This method tries to send SMS after checking the number (presence and
+ formatting). """
+ iap_data = [{
+ 'res_id': record.id,
+ 'number': record.number,
+ 'content': record.body,
+ } for record in self]
+
+ try:
+ iap_results = self.env['sms.api']._send_sms_batch(iap_data)
+ except Exception as e:
+ _logger.info('Sent batch %s SMS: %s: failed with exception %s', len(self.ids), self.ids, e)
+ if raise_exception:
+ raise
+ self._postprocess_iap_sent_sms([{'res_id': sms.id, 'state': 'server_error'} for sms in self], delete_all=delete_all)
+ else:
+ _logger.info('Send batch %s SMS: %s: gave %s', len(self.ids), self.ids, iap_results)
+ self._postprocess_iap_sent_sms(iap_results, delete_all=delete_all)
+
+ def _postprocess_iap_sent_sms(self, iap_results, failure_reason=None, delete_all=False):
+ if delete_all:
+ todelete_sms_ids = [item['res_id'] for item in iap_results]
+ else:
+ todelete_sms_ids = [item['res_id'] for item in iap_results if item['state'] == 'success']
+
+ for state in self.IAP_TO_SMS_STATE.keys():
+ sms_ids = [item['res_id'] for item in iap_results if item['state'] == state]
+ if sms_ids:
+ if state != 'success' and not delete_all:
+ self.env['sms.sms'].sudo().browse(sms_ids).write({
+ 'state': 'error',
+ 'error_code': self.IAP_TO_SMS_STATE[state],
+ })
+ notifications = self.env['mail.notification'].sudo().search([
+ ('notification_type', '=', 'sms'),
+ ('sms_id', 'in', sms_ids),
+ ('notification_status', 'not in', ('sent', 'canceled'))]
+ )
+ if notifications:
+ notifications.write({
+ 'notification_status': 'sent' if state == 'success' else 'exception',
+ 'failure_type': self.IAP_TO_SMS_STATE[state] if state != 'success' else False,
+ 'failure_reason': failure_reason if failure_reason else False,
+ })
+ self.mail_message_id._notify_message_notification_update()
+
+ if todelete_sms_ids:
+ self.browse(todelete_sms_ids).sudo().unlink()