def test_message_sms_crash_wrong_number_single(self): with self.sudo('employee'), self.mockSMSGateway( nbr_t_error= { phone_validation.phone_get_sanitized_record_number(self.partner_2): 'wrong_format_number' }): test_record = self.env['mail.test.sms'].browse(self.test_record.id) messages = test_record._message_sms( self._test_body, partner_ids=(self.partner_1 | self.partner_2 | self.partner_3).ids) self.assertSMSNotification([ { 'partner': self.partner_1, 'state': 'sent' }, { 'partner': self.partner_2, 'state': 'exception', 'failure_type': 'sms_number_format' }, { 'partner': self.partner_3, 'state': 'sent' }, ], self._test_body, messages)
def assertSMSStatistics(self, recipients_info, mailing, records, check_sms=True): """ Check content of notifications. :param recipients_info: list[{ 'partner': res.partner record (may be empty), 'number': number used for notification (may be empty, computed based on partner), 'state': outgoing / sent / ignored / exception / opened (sent by default), 'record: linked record, 'failure_type': optional: sms_number_missing / sms_number_format / sms_credit / sms_server }, { ... }] """ traces = self.env['mailing.trace'].search([ ('mass_mailing_id', 'in', mailing.ids), ('res_id', 'in', records.ids) ]) self.assertTrue(all(s.model == records._name for s in traces)) # self.assertTrue(all(s.utm_campaign_id == mailing.campaign_id for s in traces)) self.assertEqual(set(s.res_id for s in traces), set(records.ids)) for recipient_info in recipients_info: partner = recipient_info.get('partner', self.env['res.partner']) number = recipient_info.get('number') state = recipient_info.get('state', 'outgoing') content = recipient_info.get('content', None) if number is None and partner: number = phone_validation.phone_get_sanitized_record_number( partner) notif = traces.filtered( lambda s: s.sms_number == number and s.state == state) self.assertTrue( notif, 'SMS: not found notification for number %s, (state: %s)' % (number, state)) if check_sms: if state == 'sent': self.assertSMSSent([number], content) elif state == 'outgoing': self.assertSMSOutgoing(partner, number, content) elif state == 'exception': self.assertSMSFailed(partner, number, recipient_info.get('failure_type'), content) elif state == 'ignored': self.assertSMSCanceled( partner, number, recipient_info.get('failure_type', False), content) else: raise NotImplementedError()
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 assertSMSOutgoing(self, partner, number, content=None): """ Check outgoing SMS. Search is done for a pair partner / number where partner can be an empty recordset. """ if number is None and partner: number = phone_validation.phone_get_sanitized_record_number(partner) sms = self.env['sms.sms'].sudo().search([ ('partner_id', '=', partner.id), ('number', '=', number), ('state', '=', 'outgoing') ]) self.assertTrue(sms, 'SMS: not found failed SMS for %s (number: %s)' % (partner, number)) if content is not None: self.assertEqual(sms.body, content)
def assertSMSNotification(self, recipients_info, content, messages=None, check_sms=True): """ Check content of notifications. :param recipients_info: list[{ 'partner': res.partner record (may be empty), 'number': number used for notification (may be empty, computed based on partner), 'state': ready / sent / exception / canceled (sent by default), 'failure_type': optional: sms_number_missing / sms_number_format / sms_credit / sms_server }, { ... }] """ partners = self.env['res.partner'].concat(*list(p['partner'] for p in recipients_info if p.get('partner'))) numbers = [p['number'] for p in recipients_info if p.get('number')] base_domain = [ '|', ('res_partner_id', 'in', partners.ids), '&', ('res_partner_id', '=', False), ('sms_number', 'in', numbers), ('notification_type', '=', 'sms') ] if messages is not None: base_domain += [('mail_message_id', 'in', messages.ids)] notifications = self.env['mail.notification'].search(base_domain) self.assertEqual(notifications.mapped('res_partner_id'), partners) for recipient_info in recipients_info: partner = recipient_info.get('partner', self.env['res.partner']) number = recipient_info.get('number') state = recipient_info.get('state', 'sent') if number is None and partner: number = phone_validation.phone_get_sanitized_record_number(partner) notif = notifications.filtered(lambda n: n.res_partner_id == partner and n.sms_number == number and n.notification_status == state) self.assertTrue(notif, 'SMS: not found notification for %s (number: %s, state: %s)' % (partner, number, state)) if state not in ('sent', 'ready', 'canceled'): self.assertEqual(notif.failure_type, recipient_info['failure_type']) if check_sms: if state == 'sent': self.assertSMSSent([number], content) elif state == 'ready': self.assertSMSOutgoing(partner, number, content) elif state == 'exception': self.assertSMSFailed(partner, number, recipient_info['failure_type'], content) elif state == 'canceled': self.assertSMSCanceled(partner, number, recipient_info.get('failure_type', False), content) else: raise NotImplementedError('Not implemented') if messages is not None: for message in messages: self.assertEqual(content, tools.html2plaintext(message.body).rstrip('\n'))