Example #1
0
 def _execute_command_lead(self, **kwargs):
     partner = self.env.user.partner_id
     key = kwargs['body']
     channel_partners = self.env['mail.channel.partner'].search([
         ('partner_id', '!=', partner.id),
         ('channel_id', '=', self.id)], limit=1
     )
     if key.strip() == '/lead':
         msg = self._define_command_lead()['help']
     else:
         description = ''.join(
             '%s: %s\n' % (message.author_id.name or self.anonymous_name, message.body)
             for message in self.channel_message_ids.sorted('id')
         )
         lead = self.env['crm.lead'].create({
             'name': html2plaintext(key[5:]),
             'partner_id': channel_partners.partner_id.id,
             'user_id': None,
             'team_id': None,
             'description': html2plaintext(description),
             'referred': partner.name
         })
         lead._onchange_partner_id()
         msg = _('Created a new lead: <a href="#" data-oe-id="%s" data-oe-model="crm.lead">%s</a>') % (lead.id, lead.name)
     self._send_transient_message(partner, msg)
Example #2
0
 def _convert_visitor_to_lead(self, partner, channel_partners, key):
     description = ''.join(
         '%s: %s\n' %
         (message.author_id.name or self.anonymous_name, message.body)
         for message in self.channel_message_ids.sorted('id'))
     utm_source = self.env.ref('crm_livechat.utm_source_livechat',
                               raise_if_not_found=False)
     lead = self.env['crm.lead'].create({
         'name':
         html2plaintext(key[5:]),
         'partner_id':
         channel_partners.partner_id.id,
         'user_id':
         None,
         'team_id':
         None,
         'description':
         html2plaintext(description),
         'referred':
         partner.name,
         'source_id':
         utm_source and utm_source.id,
     })
     lead._onchange_partner_id()
     return lead
Example #3
0
 def _compute_description(self):
     for message in self:
         if message.subject:
             message.description = message.subject
         else:
             plaintext_ct = '' if not message.body else html2plaintext(message.body)
             message.description = plaintext_ct[:30] + '%s' % (' [...]' if len(plaintext_ct) >= 30 else '')
Example #4
0
 def assertSMSLogged(self, records, body):
     for record in records:
         message = record.message_ids[-1]
         self.assertEqual(message.subtype_id, self.env.ref('mail.mt_note'))
         self.assertEqual(message.message_type, 'sms')
         self.assertEqual(
             tools.html2plaintext(message.body).rstrip('\n'), body)
Example #5
0
 def _compute_teaser(self):
     for blog_post in self:
         if blog_post.teaser_manual:
             blog_post.teaser = blog_post.teaser_manual
         else:
             content = html2plaintext(blog_post.content).replace('\n', ' ')
             blog_post.teaser = content[:150] + '...'
Example #6
0
 def setHtmlFallbackText(self, padID, html):
     try:
         # Prevents malformed HTML errors
         html_wellformed = '<html><body>' + html + '</body></html>'
         return self.setHtml(padID, html_wellformed)
     except Exception:
         _logger.exception(
             'Falling back to setText. SetHtml failed with message:')
         return self.setText(padID, html2plaintext(html).encode('UTF-8'))
Example #7
0
 def action_create_calendar_event(self):
     self.ensure_one()
     action = self.env.ref('calendar.action_calendar_event').read()[0]
     action['context'] = {
         'default_activity_type_id': self.activity_type_id.id,
         'default_res_id': self.env.context.get('default_res_id'),
         'default_res_model': self.env.context.get('default_res_model'),
         'default_name': self.summary or self.res_name,
         'default_description': self.note and tools.html2plaintext(self.note).strip() or '',
         'default_activity_ids': [(6, 0, self.ids)],
     }
     return action
Example #8
0
 def message_post(self, **kwargs):
     """ Gửi tin từ eagle -> facebook
         TODO: if sender in [list_of_fb_manager]  // trường hợp nhiều fbmanager cho 1 kênh """
     res = super(MailChannel, self).message_post(**kwargs)
     for channel in self:
         if channel.channel_type == 'fb':
             if not res.author_id.psid and res.message_type != 'notification':  # không phải người dùng facebook
                 send_message = self.env['omi.facebook.utils'].send_message
                 recipients = channel.channel_partner_ids - res.author_id
                 for recipient in recipients:
                     send_message(partner=recipient,
                                  text=html2plaintext(res.body))
     return res
 def message_new(self, msg, custom_values=None):
     """ Overrides mail_thread message_new that is called by the mailgateway
         through message_process.
         This override updates the document according to the email.
     """
     if custom_values is None:
         custom_values = {}
     desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
     defaults = {
         'name': msg.get('subject') or _("No Subject"),
         'description': desc,
         'email_from': msg.get('from'),
         'email_cc': msg.get('cc'),
         'partner_id': msg.get('author_id', False),
     }
     if msg.get('priority'):
         defaults['priority'] = msg.get('priority')
     defaults.update(custom_values)
     return super(CrmClaim, self).message_new(msg, custom_values=defaults)
Example #10
0
    def _mark_done(self):
        """ Will add certification to employee's resumé if
        - The survey is a certification
        - The user is linked to an employee
        - The user succeeded the test """

        super(SurveyUserInput, self)._mark_done()

        certificate_user_inputs = self.filtered(
            lambda user_input: user_input.survey_id.certificate and user_input.
            quizz_passed)
        partner_has_completed = {
            user_input.partner_id.id: user_input.survey_id
            for user_input in certificate_user_inputs
        }
        employees = self.env['hr.employee'].sudo().search([
            ('user_id.partner_id', 'in',
             certificate_user_inputs.mapped('partner_id').ids)
        ])
        for employee in employees:
            line_type = self.env.ref(
                'hr_skills_survey.resume_type_certification',
                raise_if_not_found=False)
            survey = partner_has_completed.get(employee.user_id.partner_id.id)
            self.env['hr.resume.line'].create({
                'employee_id':
                employee.id,
                'name':
                survey.title,
                'date_start':
                fields.Date.today(),
                'date_end':
                fields.Date.today(),
                'description':
                html2plaintext(survey.description),
                'line_type_id':
                line_type and line_type.id,
                'display_type':
                'certification',
                'survey_id':
                survey.id
            })
Example #11
0
    def _send_prepare_values(self, partner=None):
        """Return a dictionary for specific email values, depending on a
        partner, or generic to the whole recipients given by mail.email_to.

            :param Model partner: specific recipient partner
        """
        self.ensure_one()
        body = self._send_prepare_body()
        body_alternative = tools.html2plaintext(body)
        if partner:
            email_to = [
                formataddr((partner.name or 'False', partner.email or 'False'))
            ]
        else:
            email_to = tools.email_split_and_format(self.email_to)
        res = {
            'body': body,
            'body_alternative': body_alternative,
            'email_to': email_to,
        }
        return res
Example #12
0
    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 = partner.phone_get_sanitized_number()

            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'))
Example #13
0
 def _compute_name(self):
     """ Read the first line of the memo to determine the note name """
     for note in self:
         text = html2plaintext(note.memo) if note.memo else ''
         note.name = text.strip().replace('*', '').split("\n")[0]
Example #14
0
    def channel(self,
                channel,
                category=None,
                tag=None,
                page=1,
                slide_type=None,
                uncategorized=False,
                sorting=None,
                search=None,
                **kw):
        if not channel.can_access_from_current_website():
            raise werkzeug.exceptions.NotFound()

        domain = self._get_channel_slides_base_domain(channel)

        pager_url = "/slides/%s" % (channel.id)
        pager_args = {}
        slide_types = dict(request.env['slide.slide']._fields['slide_type'].
                           _description_selection(request.env))

        if search:
            domain += [
                '|', '|', '|', ('name', 'ilike', search),
                ('description', 'ilike', search),
                ('html_content', 'ilike', search)
            ]
            pager_args['search'] = search
        else:
            if category:
                domain += [('category_id', '=', category.id)]
                pager_url += "/category/%s" % category.id
            elif tag:
                domain += [('tag_ids.id', '=', tag.id)]
                pager_url += "/tag/%s" % tag.id
            if uncategorized:
                domain += [('category_id', '=', False)]
                pager_url += "?uncategorized=1"
            elif slide_type:
                domain += [('slide_type', '=', slide_type)]
                pager_url += "?slide_type=%s" % slide_type

        # sorting criterion
        if channel.channel_type == 'documentation':
            actual_sorting = sorting if sorting and sorting in request.env[
                'slide.slide']._order_by_strategy else channel.promote_strategy
        else:
            actual_sorting = 'sequence'
        order = request.env['slide.slide']._order_by_strategy[actual_sorting]
        pager_args['sorting'] = actual_sorting

        slide_count = request.env['slide.slide'].sudo().search_count(domain)
        page_count = math.ceil(slide_count / self._slides_per_page)
        pager = request.website.pager(
            url=pager_url,
            total=slide_count,
            page=page,
            step=self._slides_per_page,
            url_args=pager_args,
            scope=page_count
            if page_count < self._pager_max_pages else self._pager_max_pages)

        query_string = None
        if category:
            query_string = "?search_category=%s" % category.id
        elif tag:
            query_string = "?search_tag=%s" % tag.id
        elif slide_type:
            query_string = "?search_slide_type=%s" % slide_type
        elif uncategorized:
            query_string = "?search_uncategorized=1"

        values = {
            'channel': channel,
            'main_object': channel,
            'active_tab': kw.get('active_tab', 'home'),
            # search
            'search_category': category,
            'search_tag': tag,
            'search_slide_type': slide_type,
            'search_uncategorized': uncategorized,
            'query_string': query_string,
            'slide_types': slide_types,
            'sorting': actual_sorting,
            'search': search,
            # chatter
            'rating_avg': channel.rating_avg,
            'rating_count': channel.rating_count,
            # display data
            'user': request.env.user,
            'pager': pager,
            'is_public_user': request.website.is_public_user(),
            # display upload modal
            'enable_slide_upload': 'enable_slide_upload' in kw,
        }
        if not request.env.user._is_public():
            last_message = request.env['mail.message'].search(
                [('model', '=', channel._name), ('res_id', '=', channel.id),
                 ('author_id', '=', request.env.user.partner_id.id),
                 ('message_type', '=', 'comment'),
                 ('website_published', '=', True)],
                order='write_date DESC',
                limit=1)
            if last_message:
                last_message_values = last_message.read(
                    ['body', 'rating_value', 'attachment_ids'])[0]
                last_message_attachment_ids = last_message_values.pop(
                    'attachment_ids', [])
                if last_message_attachment_ids:
                    last_message_attachment_ids = json.dumps(
                        request.env['ir.attachment'].browse(
                            last_message_attachment_ids).read([
                                'id', 'name', 'mimetype', 'file_size',
                                'access_token'
                            ]))
            else:
                last_message_values = {}
                last_message_attachment_ids = []
            values.update({
                'last_message_id':
                last_message_values.get('id'),
                'last_message':
                tools.html2plaintext(last_message_values.get('body', '')),
                'last_rating_value':
                last_message_values.get('rating_value'),
                'last_message_attachment_ids':
                last_message_attachment_ids,
            })
            if channel.can_review:
                values.update({
                    'message_post_hash':
                    channel._sign_token(request.env.user.partner_id.id),
                    'message_post_pid':
                    request.env.user.partner_id.id,
                })

        # fetch slides and handle uncategorized slides; done as sudo because we want to display all
        # of them but unreachable ones won't be clickable (+ slide controller will crash anyway)
        # documentation mode may display less slides than content by category but overhead of
        # computation is reasonable
        values['slide_promoted'] = request.env['slide.slide'].sudo().search(
            domain, limit=1, order=order)
        values['category_data'] = channel._get_categorized_slides(
            domain,
            order,
            force_void=not category,
            limit=False if channel.channel_type != 'documentation' else
            self._slides_per_page if category else self._slides_per_category,
            offset=pager['offset'])
        values['channel_progress'] = self._get_channel_progress(
            channel, include_quiz=True)

        # for sys admins: prepare data to install directly modules from eLearning when
        # uploading slides. Currently supporting only survey, because why not.
        if request.env.user.has_group('base.group_system'):
            module = request.env.ref('base.module_survey')
            if module.state != 'installed':
                values['modules_to_install'] = [{
                    'id':
                    module.id,
                    'name':
                    module.shortdesc,
                    'motivational':
                    _('Evaluate and certificate your students.'),
                }]

        values = self._prepare_additional_channel_values(values, **kw)
        return request.render('website_slides.course_main', values)
Example #15
0
    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_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