def _sms_get_recipients_info(self, force_field=False): """" Get SMS recipient information on current record set. This method checks for numbers and sanitation in order to centralize computation. Example of use cases * click on a field -> number is actually forced from field, find customer linked to record, force its number to field or fallback on customer fields; * contact -> find numbers from all possible phone fields on record, find customer, force its number to found field number or fallback on customer fields; :return dict: record.id: { 'partner': a res.partner recordset that is the customer (void or singleton); 'sanitized': sanitized number to use (coming from record's field or partner's mobile or phone). Set to False is number impossible to parse and format; 'number': original number before sanitation; } for each record in self """ result = dict.fromkeys(self.ids, False) number_fields = self._sms_get_number_fields() for record in self: tocheck_fields = [force_field] if force_field else number_fields all_numbers = [record[fname] for fname in tocheck_fields if fname in record] all_partners = record._sms_get_default_partners() valid_number = False for fname in [f for f in tocheck_fields if f in record]: valid_number = phone_validation.phone_get_sanitized_record_number(record, number_fname=fname) if valid_number: break if valid_number: result[record.id] = { 'partner': all_partners[0] if all_partners else self.env['res.partner'], 'sanitized': valid_number, 'number': valid_number, } elif all_partners: partner_number, partner = False, self.env['res.partner'] for partner in all_partners: partner_number = partner.mobile or partner.phone if partner_number: partner_number = phone_validation.phone_sanitize_numbers_string_w_record(partner_number, record)[partner_number]['sanitized'] if partner_number: break if partner_number: result[record.id] = {'partner': partner, 'sanitized': partner_number, 'number': partner_number} else: result[record.id] = {'partner': partner, 'sanitized': False, 'number': partner.mobile or partner.phone} elif all_numbers: result[record.id] = {'partner': self.env['res.partner'], 'sanitized': False, 'number': all_numbers[0]} else: result[record.id] = {'partner': self.env['res.partner'], 'sanitized': False, 'number': False} return result
def _compute_sanitized_numbers(self): if self.numbers: record = self._get_records() if self.res_model and self.res_id else self.env.user sanitize_res = phone_validation.phone_sanitize_numbers_string_w_record(self.numbers, record) sanitized_numbers = [info['sanitized'] for info in sanitize_res.values() if info['sanitized']] invalid_numbers = [number for number, info in sanitize_res.items() if info['code']] if invalid_numbers: raise UserError(_('Following numbers are not correctly encoded: %s') % repr(invalid_numbers)) self.sanitized_numbers = ','.join(sanitized_numbers) else: self.sanitized_numbers = False
def _notify_record_by_sms(self, message, recipients_data, msg_vals=False, sms_numbers=None, sms_pid_to_number=None, check_existing=False, put_in_queue=False, **kwargs): """ Notification method: by SMS. :param message: mail.message record to notify; :param recipients_data: see ``_notify_thread``; :param msg_vals: see ``_notify_thread``; :param sms_numbers: additional numbers to notify in addition to partners and classic recipients; :param pid_to_number: force a number to notify for a given partner ID instead of taking its mobile / phone number; :param check_existing: check for existing notifications to update based on mailed recipient, otherwise create new notifications; :param put_in_queue: use cron to send queued SMS instead of sending them directly; """ sms_pid_to_number = sms_pid_to_number if sms_pid_to_number is not None else {} sms_numbers = sms_numbers if sms_numbers is not None else [] sms_create_vals = [] sms_all = self.env['sms.sms'].sudo() # pre-compute SMS data body = msg_vals['body'] if msg_vals and msg_vals.get('body') else message.body sms_base_vals = { 'body': html2plaintext(body).rstrip('\n'), 'mail_message_id': message.id, 'state': 'outgoing', } # notify from computed recipients_data (followers, specific recipients) partners_data = [r for r in recipients_data['partners'] if r['notif'] == 'sms'] partner_ids = [r['id'] for r in partners_data] if partner_ids: for partner in self.env['res.partner'].sudo().browse(partner_ids): number = sms_pid_to_number.get(partner.id) or partner.mobile or partner.phone sanitize_res = phone_validation.phone_sanitize_numbers_string_w_record(number, partner)[number] number = sanitize_res['sanitized'] or number sms_create_vals.append(dict( sms_base_vals, partner_id=partner.id, number=number )) # notify from additional numbers if sms_numbers: sanitized = phone_validation.phone_sanitize_numbers_w_record(sms_numbers, self) tocreate_numbers = [ value['sanitized'] or original for original, value in sanitized.items() if value['code'] != 'empty' ] sms_create_vals += [dict(sms_base_vals, partner_id=False, number=n) for n in tocreate_numbers] # create sms and notification existing_pids, existing_numbers = [], [] if sms_create_vals: sms_all |= self.env['sms.sms'].sudo().create(sms_create_vals) if check_existing: existing = self.env['mail.notification'].sudo().search([ '|', ('res_partner_id', 'in', partner_ids), '&', ('res_partner_id', '=', False), ('sms_number', 'in', sms_numbers), ('notification_type', '=', 'sms'), ('mail_message_id', '=', message.id) ]) for n in existing: if n.res_partner_id.id in partner_ids and n.mail_message_id == message: existing_pids.append(n.res_partner_id.id) if not n.res_partner_id and n.sms_number in sms_numbers and n.mail_message_id == message: existing_numbers.append(n.sms_number) notif_create_values = [{ 'mail_message_id': message.id, 'res_partner_id': sms.partner_id.id, 'sms_number': sms.number, 'notification_type': 'sms', 'sms_id': sms.id, 'is_read': True, # discard Inbox notification 'notification_status': 'ready', } for sms in sms_all if (sms.partner_id and sms.partner_id.id not in existing_pids) or (not sms.partner_id and sms.number not in existing_numbers)] if notif_create_values: self.env['mail.notification'].sudo().create(notif_create_values) if existing_pids or existing_numbers: for sms in sms_all: notif = next((n for n in existing if (n.res_partner_id.id in existing_pids and n.res_partner_id.id == sms.partner_id.id) or (not n.res_partner_id and n.sms_number in existing_numbers and n.sms_number == sms.number)), False) if notif: notif.write({ 'notification_type': 'sms', 'notification_status': 'ready', 'sms_id': sms.id, 'sms_number': sms.number, }) if sms_all and not put_in_queue: sms_all.send(auto_commit=False, raise_exception=False) return True