diff --git a/addons/crm_sms/__manifest__.py b/addons/crm_sms/__manifest__.py
index a32d0b718fe..5b5780916e2 100644
--- a/addons/crm_sms/__manifest__.py
+++ b/addons/crm_sms/__manifest__.py
@@ -10,6 +10,8 @@
'depends': ['crm', 'sms'],
'data': [
'views/crm_lead_views.xml',
+ 'security/ir.model.access.csv',
+ 'security/sms_security.xml',
],
'installable': True,
'application': False,
diff --git a/addons/crm_sms/security/ir.model.access.csv b/addons/crm_sms/security/ir.model.access.csv
new file mode 100644
index 00000000000..f94b6f7ffde
--- /dev/null
+++ b/addons/crm_sms/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_sms_template_sale_manager,access.sms.template.sale.manager,sms.model_sms_template,sales_team.group_sale_manager,1,1,1,1
diff --git a/addons/crm_sms/security/sms_security.xml b/addons/crm_sms/security/sms_security.xml
new file mode 100644
index 00000000000..a3a88f045e9
--- /dev/null
+++ b/addons/crm_sms/security/sms_security.xml
@@ -0,0 +1,9 @@
+
+
+
+ SMS Template: sale manager CRUD on opportunity / partner templates
+
+
+ [('res_model_id.model', 'in', ('crm.lead', 'res.partner'))]
+
+
diff --git a/addons/event_sms/__manifest__.py b/addons/event_sms/__manifest__.py
index 756ade6c0e3..94d9df26851 100644
--- a/addons/event_sms/__manifest__.py
+++ b/addons/event_sms/__manifest__.py
@@ -11,6 +11,8 @@
'data/sms_data.xml',
'views/event_views.xml',
'views/event_mail_views.xml',
+ 'security/ir.model.access.csv',
+ 'security/sms_security.xml',
],
'demo': [
],
diff --git a/addons/event_sms/security/ir.model.access.csv b/addons/event_sms/security/ir.model.access.csv
new file mode 100644
index 00000000000..b34e4dd5b87
--- /dev/null
+++ b/addons/event_sms/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_sms_template_event_manager,access.sms.template.event.manager,sms.model_sms_template,event.group_event_manager,1,1,1,1
diff --git a/addons/event_sms/security/sms_security.xml b/addons/event_sms/security/sms_security.xml
new file mode 100644
index 00000000000..94bc733cf7a
--- /dev/null
+++ b/addons/event_sms/security/sms_security.xml
@@ -0,0 +1,9 @@
+
+
+
+ SMS Template: event manager CRUD on event / registrations templates
+
+
+ [('res_model_id.model', 'in', ('event.event', 'event.registration'))]
+
+
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index 5daf717e26f..101766fe9e2 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -1384,7 +1384,7 @@ class MailThread(models.AbstractModel):
msg_dict['cc'] = ','.join(email_cc_list) if email_cc_list else email_cc
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
# for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
- msg_dict['recipients'] = ','.join(formatted_email
+ msg_dict['recipients'] = ','.join(set(formatted_email
for address in [
tools.decode_message_header(message, 'Delivered-To'),
tools.decode_message_header(message, 'To'),
@@ -1392,14 +1392,15 @@ class MailThread(models.AbstractModel):
tools.decode_message_header(message, 'Resent-To'),
tools.decode_message_header(message, 'Resent-Cc')
] if address
- for formatted_email in tools.email_split_and_format(address)
+ for formatted_email in tools.email_split_and_format(address))
)
- msg_dict['to'] = ','.join(formatted_email
+ msg_dict['to'] = ','.join(set(formatted_email
for address in [
tools.decode_message_header(message, 'Delivered-To'),
tools.decode_message_header(message, 'To')
] if address
for formatted_email in tools.email_split_and_format(address))
+ )
partner_ids = [x.id for x in self._mail_find_partner_from_emails(tools.email_split(msg_dict['recipients']), records=self) if x]
msg_dict['partner_ids'] = partner_ids
# compute references to find if email_message is a reply to an existing thread
diff --git a/addons/mass_mailing/models/mailing_trace.py b/addons/mass_mailing/models/mailing_trace.py
index 38185845545..ef3c51f0141 100644
--- a/addons/mass_mailing/models/mailing_trace.py
+++ b/addons/mass_mailing/models/mailing_trace.py
@@ -31,7 +31,7 @@ class MailingTrace(models.Model):
model = fields.Char(string='Document model')
res_id = fields.Integer(string='Document ID')
# campaign / wave data
- mass_mailing_id = fields.Many2one('mailing.mailing', string='Mailing', index=True)
+ mass_mailing_id = fields.Many2one('mailing.mailing', string='Mailing', index=True, ondelete='cascade')
campaign_id = fields.Many2one(
related='mass_mailing_id.campaign_id',
string='Campaign',
diff --git a/addons/mass_mailing_sms/models/mailing_mailing.py b/addons/mass_mailing_sms/models/mailing_mailing.py
index 49d7b6a0a3c..b71cf3cc274 100644
--- a/addons/mass_mailing_sms/models/mailing_mailing.py
+++ b/addons/mass_mailing_sms/models/mailing_mailing.py
@@ -20,6 +20,8 @@ class Mailing(models.Model):
sms_has_insufficient_credit = fields.Boolean(
'Insufficient IAP credits', compute='_compute_sms_has_insufficient_credit',
help='UX Field to propose to buy IAP credits')
+ sms_force_send = fields.Boolean(
+ 'Send Directly', help='Use at your own risks.')
# opt_out_link
sms_allow_unsubscribe = fields.Boolean('Include opt-out link', default=True)
@@ -63,7 +65,30 @@ class Mailing(models.Model):
# --------------------------------------------------
def action_put_in_queue_sms(self):
- return self.action_put_in_queue()
+ res = self.action_put_in_queue()
+ if self.sms_force_send:
+ self.action_send_mail()
+ return res
+
+ def action_send_now_sms(self):
+ if not self.sms_force_send:
+ self.write({'sms_force_send': True})
+ return self.action_send_mail()
+
+ def action_retry_failed(self):
+ mass_sms = self.filtered(lambda m: m.mailing_type == 'sms')
+ if mass_sms:
+ mass_sms.action_retry_failed_sms()
+ return super(Mailing, self - mass_sms).action_retry_failed()
+
+ def action_retry_failed_sms(self):
+ failed_sms = self.env['sms.sms'].sudo().search([
+ ('mailing_id', 'in', self.ids),
+ ('state', '=', 'error')
+ ])
+ failed_sms.mapped('mailing_trace_ids').unlink()
+ failed_sms.unlink()
+ self.write({'state': 'in_queue'})
def action_test(self):
if self.mailing_type == 'sms':
@@ -166,6 +191,7 @@ class Mailing(models.Model):
'composition_mode': 'mass',
'mailing_id': self.id,
'mass_keep_log': self.keep_archives,
+ 'mass_force_send': self.sms_force_send,
'mass_sms_allow_unsubscribe': self.sms_allow_unsubscribe,
}
@@ -183,11 +209,6 @@ class Mailing(models.Model):
raise UserError(_('There is no recipients selected.'))
composer = self.env['sms.composer'].with_context(active_id=False).create(mailing._send_sms_get_composer_values(res_ids))
- # extra_context = self._get_mass_mailing_context()
-
- # auto-commit except in testing mode
- # auto_commit = not getattr(threading.currentThread(), 'testing', False)
- # composer.send_mail(auto_commit=auto_commit)
composer._action_send_sms()
mailing.write({'state': 'done', 'sent_date': fields.Datetime.now()})
return True
diff --git a/addons/mass_mailing_sms/views/mailing_mailing_views.xml b/addons/mass_mailing_sms/views/mailing_mailing_views.xml
index 54d4c5375b2..b0fb2c129b9 100644
--- a/addons/mass_mailing_sms/views/mailing_mailing_views.xml
+++ b/addons/mass_mailing_sms/views/mailing_mailing_views.xml
@@ -23,10 +23,14 @@
{'invisible': ['|', ('state', 'in', ('in_queue', 'done')), ('mailing_type', '!=', 'mail')]}
-
+ confirm="This will schedule an SMS marketing to all recipients. Do you still want to proceed ?"/>
+
@@ -90,8 +94,9 @@
-
+
+
diff --git a/addons/mass_mailing_sms/wizard/sms_composer.py b/addons/mass_mailing_sms/wizard/sms_composer.py
index 584b15c66eb..aef10ac4f2f 100644
--- a/addons/mass_mailing_sms/wizard/sms_composer.py
+++ b/addons/mass_mailing_sms/wizard/sms_composer.py
@@ -74,12 +74,9 @@ class SMSComposer(models.TransientModel):
all_bodies[sms_id] = body
return all_bodies
- def _prepare_mass_sms_values(self, records=None):
- result = super(SMSComposer, self)._prepare_mass_sms_values(records=records)
+ def _prepare_mass_sms_values(self, records):
+ result = super(SMSComposer, self)._prepare_mass_sms_values(records)
if self.composition_mode == 'mass' and self.mailing_id:
- records = records if records is not None else self._get_records()
-
- # for record_id, sms_values in result.items():
for record in records:
sms_values = result[record.id]
@@ -90,8 +87,8 @@ class SMSComposer(models.TransientModel):
})
return result
- def _action_send_sms_mass(self, records=None):
- sms_all = super(SMSComposer, self)._action_send_sms_mass()
+ def _prepare_mass_sms(self, records, sms_record_values):
+ sms_all = super(SMSComposer, self)._prepare_mass_sms(records, sms_record_values)
if self.mailing_id:
updated_bodies = sms_all._update_body_short_links()
for sms in sms_all:
diff --git a/addons/sms/models/sms_sms.py b/addons/sms/models/sms_sms.py
index 256bebf7eda..081547426ce 100644
--- a/addons/sms/models/sms_sms.py
+++ b/addons/sms/models/sms_sms.py
@@ -86,7 +86,7 @@ class SmsSms(models.Model):
return res
def _split_batch(self):
- batch_size = int(self.env['ir.config_parameter'].sudo().get_param('sms.session.batch.size', 10))
+ 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
diff --git a/addons/sms/security/ir.model.access.csv b/addons/sms/security/ir.model.access.csv
index c906bc097b7..b5c75f2433f 100644
--- a/addons/sms/security/ir.model.access.csv
+++ b/addons/sms/security/ir.model.access.csv
@@ -3,4 +3,4 @@ access_sms_sms_all,access.sms.sms.all,model_sms_sms,,0,0,0,0
access_sms_sms_system,access.sms.sms.system,model_sms_sms,base.group_system,1,1,1,1
access_sms_template_all,access.sms.template.all,model_sms_template,,0,0,0,0
access_sms_template_user,access.sms.template.user,model_sms_template,base.group_user,1,0,0,0
-access_sms_template_system,access.sms.template.system,model_sms_template,base.group_system,1,1,1,0
+access_sms_template_system,access.sms.template.system,model_sms_template,base.group_system,1,1,1,1
diff --git a/addons/sms/wizard/sms_composer.py b/addons/sms/wizard/sms_composer.py
index 520c5df9904..841ef609597 100644
--- a/addons/sms/wizard/sms_composer.py
+++ b/addons/sms/wizard/sms_composer.py
@@ -147,7 +147,12 @@ class SendSMS(models.TransientModel):
self._action_send_sms()
return False
- def _action_send_sms(self, force_send=False):
+ def action_send_sms_mass_now(self):
+ if not self.mass_force_send:
+ self.write({'mass_force_send': True})
+ return self.action_send_sms()
+
+ def _action_send_sms(self):
records = self._get_records()
if self.composition_mode == 'numbers':
return self._action_send_sms_numbers()
@@ -183,17 +188,16 @@ class SendSMS(models.TransientModel):
records = records if records is not None else self._get_records()
sms_record_values = self._prepare_mass_sms_values(records)
- sms_create_vals = [sms_record_values[record.id] for record in records]
- sms = self.env['sms.sms'].sudo().create(sms_create_vals)
+ sms_all = self._prepare_mass_sms(records, sms_record_values)
- if sms and self.mass_keep_log and records and issubclass(type(records), self.pool['mail.thread']):
- log_values = self._prepare_mass_log_values(sms_record_values)
+ if sms_all and self.mass_keep_log and records and issubclass(type(records), self.pool['mail.thread']):
+ log_values = self._prepare_mass_log_values(records, sms_record_values)
records._message_log_batch(**log_values)
- if sms and self.mass_force_send:
- sms.send(auto_commit=False, raise_exception=False)
-
- return sms
+ if sms_all and self.mass_force_send:
+ sms_all.filtered(lambda sms: sms.state == 'outgoing').send(auto_commit=False, raise_exception=False)
+ return self.env['sms.sms'].sudo().search([('id', 'in', sms_all.ids)])
+ return sms_all
# ------------------------------------------------------------
# Mass mode specific
@@ -230,8 +234,7 @@ class SendSMS(models.TransientModel):
all_bodies = self.env['mail.template']._render_template(self.body, records._name, records.ids)
return all_bodies
- def _prepare_mass_sms_values(self, records=None):
- records = records if records is not None else self._get_records()
+ def _prepare_mass_sms_values(self, records):
all_bodies = self._prepare_body_values(records)
all_recipients = self._prepare_recipient_values(records)
blacklist_ids = self._get_blacklist_record_ids(records, all_recipients)
@@ -263,13 +266,17 @@ class SendSMS(models.TransientModel):
}
return result
+ def _prepare_mass_sms(self, records, sms_record_values):
+ sms_create_vals = [sms_record_values[record.id] for record in records]
+ return self.env['sms.sms'].sudo().create(sms_create_vals)
+
def _prepare_log_body_values(self, sms_records_values):
result = {}
for record_id, sms_values in sms_records_values.items():
result[record_id] = sms_values['body']
return result
- def _prepare_mass_log_values(self, sms_records_values):
+ def _prepare_mass_log_values(self, records, sms_records_values):
return {
'bodies': self._prepare_log_body_values(sms_records_values),
'message_type': 'sms',
diff --git a/addons/sms/wizard/sms_composer_views.xml b/addons/sms/wizard/sms_composer_views.xml
index 1cb59d99dd3..e35b87949e9 100644
--- a/addons/sms/wizard/sms_composer_views.xml
+++ b/addons/sms/wizard/sms_composer_views.xml
@@ -39,7 +39,12 @@
diff --git a/addons/stock_sms/__manifest__.py b/addons/stock_sms/__manifest__.py
index 5d35cce66da..2e51b257216 100644
--- a/addons/stock_sms/__manifest__.py
+++ b/addons/stock_sms/__manifest__.py
@@ -13,6 +13,8 @@
'data/mail_data.xml',
'views/res_config_settings_views.xml',
'wizard/confirm_stock_sms_views.xml',
+ 'security/ir.model.access.csv',
+ 'security/sms_security.xml',
],
'application': False,
'auto_install': True,
diff --git a/addons/stock_sms/security/ir.model.access.csv b/addons/stock_sms/security/ir.model.access.csv
new file mode 100644
index 00000000000..70870ff6dbf
--- /dev/null
+++ b/addons/stock_sms/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_sms_template_stock_manager,access.sms.template.stock.manager,sms.model_sms_template,stock.group_stock_manager,1,1,1,1
diff --git a/addons/stock_sms/security/sms_security.xml b/addons/stock_sms/security/sms_security.xml
new file mode 100644
index 00000000000..b729c884241
--- /dev/null
+++ b/addons/stock_sms/security/sms_security.xml
@@ -0,0 +1,9 @@
+
+
+
+ SMS Template: stock manager CRUD on stock picking templates
+
+
+ [('res_model_id.model', '=', 'stock.picking')]
+
+