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)
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
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 '')
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)
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] + '...'
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'))
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
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)
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 })
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
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'))
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]
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)
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