def remove(self, ids, **kwargs): """ Removes a web-based image attachment if it is used by no view (template) Returns a dict mapping attachments which would not be removed (if any) mapped to the views preventing their removal """ Attachment = attachments_to_remove = request.env['ir.attachment'] Views = request.env['ir.ui.view'] # views blocking removal of the attachment removal_blocked_by = {} for attachment in Attachment.browse(ids): # in-document URLs are html-escaped, a straight search will not # find them url = tools.html_escape(attachment.local_url) views = Views.search([ "|", ('arch_db', 'like', '"%s"' % url), ('arch_db', 'like', "'%s'" % url) ]) if views: removal_blocked_by[attachment.id] = views.read(['name']) else: attachments_to_remove += attachment if attachments_to_remove: attachments_to_remove.unlink() return removal_blocked_by
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, html_escape(lead.name)) self._send_transient_message(partner, msg)
def partner_interested(self, comment=False): message = _('<p>I am interested by this lead.</p>') if comment: message += '<p>%s</p>' % html_escape(comment) for lead in self: lead.message_post(body=message) lead.sudo().convert_opportunity(lead.partner_id.id) # sudo required to convert partner data
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: lead = self._convert_visitor_to_lead(partner, channel_partners, key) msg = _( 'Created a new lead: <a href="#" data-oe-id="%s" data-oe-model="crm.lead">%s</a>' ) % (lead.id, html_escape(lead.name)) self._send_transient_message(partner, msg)
def _get_lead_days(self, product): """Returns the cumulative delay and its description encountered by a procurement going through the rules in `self`. :param product: the product of the procurement :type product: :class:`~flectra.addons.product.models.product.ProductProduct` :return: the cumulative delay and cumulative delay's description :rtype: tuple """ delay = sum( self.filtered(lambda r: r.action in ['pull', 'pull_push']).mapped( 'delay')) delay_description = ''.join([ '<tr><td>%s %s</td><td class="text-right">+ %d %s</td></tr>' % (_('Delay on'), html_escape(rule.name), rule.delay, _('day(s)')) for rule in self if rule.action in ['pull', 'pull_push'] and rule.delay ]) return delay, delay_description
def partner_desinterested(self, comment=False, contacted=False, spam=False): if contacted: message = '<p>%s</p>' % _('I am not interested by this lead. I contacted the lead.') else: message = '<p>%s</p>' % _('I am not interested by this lead. I have not contacted the lead.') partner_ids = self.env['res.partner'].search( [('id', 'child_of', self.env.user.partner_id.commercial_partner_id.id)]) self.message_unsubscribe(partner_ids=partner_ids.ids) if comment: message += '<p>%s</p>' % html_escape(comment) self.message_post(body=message) values = { 'partner_assigned_id': False, } if spam: tag_spam = self.env.ref('website_crm_partner_assign.tag_portal_lead_is_spam', False) if tag_spam and tag_spam not in self.tag_ids: values['tag_ids'] = [(4, tag_spam.id, False)] if partner_ids: values['partner_declined_ids'] = [(4, p, 0) for p in partner_ids.ids] self.sudo().write(values)
def report(self, output_format, report_name, token, report_id=False, **kw): uid = request.session.uid domain = [('create_uid', '=', uid)] stock_traceability = request.env[ 'stock.traceability.report'].with_user(uid).search(domain, limit=1) line_data = json.loads(kw['data']) try: if output_format == 'pdf': response = request.make_response( stock_traceability.with_context( active_id=report_id).get_pdf(line_data), headers=[('Content-Type', 'application/pdf'), ('Content-Disposition', 'attachment; filename=' + 'stock_traceability' + '.pdf;')]) response.set_cookie('fileToken', token) return response except Exception as e: se = _serialize_exception(e) error = { 'code': 200, 'message': 'Flectra Server Error', 'data': se } return request.make_response(html_escape(json.dumps(error)))
def _format_error_message(self, error_title, errors): bullet_list_msg = ''.join('<li>%s</li>' % html_escape(msg) for msg in errors) return '%s<ul>%s</ul>' % (error_title, bullet_list_msg)
def shape(self, module, filename, **kwargs): """ Returns a color-customized svg (background shape or illustration). """ svg = None if module == 'illustration': attachment = request.env['ir.attachment'].sudo().search( [('url', '=like', request.httprequest.path), ('public', '=', True)], limit=1) if not attachment: raise werkzeug.exceptions.NotFound() svg = b64decode(attachment.datas).decode('utf-8') else: shape_path = get_resource_path(module, 'static', 'shapes', filename) if not shape_path: raise werkzeug.exceptions.NotFound() with tools.file_open(shape_path, 'r') as file: svg = file.read() user_colors = [] for key, value in kwargs.items(): colorMatch = re.match('^c([1-5])$', key) if colorMatch: # Check that color is hex or rgb(a) to prevent arbitrary injection if not re.match( r'(?i)^#[0-9A-F]{6,8}$|^rgba?\(\d{1,3},\d{1,3},\d{1,3}(?:,[0-9.]{1,4})?\)$', value.replace(' ', '')): raise werkzeug.exceptions.BadRequest() user_colors.append( [tools.html_escape(value), colorMatch.group(1)]) elif key == 'flip': if value == 'x': svg = svg.replace('<svg ', '<svg style="transform: scaleX(-1);" ') elif value == 'y': svg = svg.replace('<svg ', '<svg style="transform: scaleY(-1)" ') elif value == 'xy': svg = svg.replace('<svg ', '<svg style="transform: scale(-1)" ') default_palette = { '1': '#3AADAA', '2': '#7C6576', '3': '#F6F6F6', '4': '#FFFFFF', '5': '#383E45', } color_mapping = { default_palette[palette_number]: color for color, palette_number in user_colors } # create a case-insensitive regex to match all the colors to replace, eg: '(?i)(#3AADAA)|(#7C6576)' regex = '(?i)%s' % '|'.join('(%s)' % color for color in color_mapping.keys()) def subber(match): key = match.group().upper() return color_mapping[key] if key in color_mapping else key svg = re.sub(regex, subber, svg) return request.make_response(svg, [ ('Content-type', 'image/svg+xml'), ('Cache-control', 'max-age=%s' % http.STATIC_CACHE_LONG), ])
def _l10n_es_edi_call_web_service_sign(self, invoices, info_list): company = invoices.company_id # All are sharing the same value, see '_get_batch_key'. csv_number = invoices.mapped('l10n_es_edi_csv')[0] # Set registration date invoices.filtered(lambda inv: not inv.l10n_es_registration_date).write( { 'l10n_es_registration_date': fields.Date.context_today(self), }) # === Call the web service === # Get connection data. l10n_es_edi_tax_agency = company.mapped('l10n_es_edi_tax_agency')[0] connection_vals = getattr( self, f'_l10n_es_edi_web_service_{l10n_es_edi_tax_agency}_vals')( invoices) header = { 'IDVersionSii': '1.1', 'Titular': { 'NombreRazon': company.name[:120], 'NIF': company.vat[2:], }, 'TipoComunicacion': 'A1' if csv_number else 'A0', } session = requests.Session() session.cert = company.l10n_es_edi_certificate_id session.mount('https://', PatchedHTTPAdapter()) transport = Transport(operation_timeout=60, timeout=60, session=session) client = zeep.Client(connection_vals['url'], transport=transport) if invoices[0].is_sale_document(): service_name = 'SuministroFactEmitidas' else: service_name = 'SuministroFactRecibidas' if company.l10n_es_edi_test_env and not connection_vals.get( 'test_url'): service_name += 'Pruebas' # Establish the connection. serv = client.bind('siiService', service_name) if company.l10n_es_edi_test_env and connection_vals.get('test_url'): serv._binding_options['address'] = connection_vals['test_url'] msg = '' try: if invoices[0].is_sale_document(): res = serv.SuministroLRFacturasEmitidas(header, info_list) else: res = serv.SuministroLRFacturasRecibidas(header, info_list) except requests.exceptions.SSLError as error: msg = _("The SSL certificate could not be validated.") except zeep.exceptions.Error as error: msg = _("Networking error:\n%s") % error except Exception as error: msg = str(error) finally: if msg: return { inv: { 'error': msg, 'blocking_level': 'warning', } for inv in invoices } # Process response. if not res or not res.RespuestaLinea: return { inv: { 'error': _("The web service is not responding"), 'blocking_level': 'warning', } for inv in invoices } resp_state = res["EstadoEnvio"] l10n_es_edi_csv = res['CSV'] if resp_state == 'Correcto': invoices.write({'l10n_es_edi_csv': l10n_es_edi_csv}) return {inv: {'success': True} for inv in invoices} results = {} for respl in res.RespuestaLinea: invoice_number = respl.IDFactura.NumSerieFacturaEmisor # Retrieve the corresponding invoice. # Note: ref can be the same for different partners but there is no enough information on the response # to match the partner. # Note: Invoices are batched per move_type. if invoices[0].is_sale_document(): inv = invoices.filtered( lambda x: x.name[:60] == invoice_number) else: # 'ref' can be the same for different partners. candidates = invoices.filtered( lambda x: x.ref[:60] == invoice_number) if len(candidates) >= 1: respl_partner_info = respl.IDFactura.IDEmisorFactura inv = None for candidate in candidates: partner_info = self._l10n_es_edi_get_partner_info( candidate.commercial_partner_id) if partner_info.get('NIF') and partner_info[ 'NIF'] == respl_partner_info.NIF: inv = candidate break if partner_info.get('IDOtro') and all( getattr(respl_partner_info.IDOtro, k) == v for k, v in partner_info['IDOtro'].items()): inv = candidate break if not inv: # This case shouldn't happen and means there is something wrong in this code. However, we can't # raise anything since the document has already been approved by the government. The result # will only be a badly logged message into the chatter so, not a big deal. inv = candidates[0] else: inv = candidates resp_line_state = respl.EstadoRegistro if resp_line_state in ('Correcto', 'AceptadoConErrores'): inv.l10n_es_edi_csv = l10n_es_edi_csv results[inv] = {'success': True} if resp_line_state == 'AceptadoConErrores': inv.message_post( body=_("This was accepted with errors: ") + html_escape(respl.DescripcionErrorRegistro)) elif respl.RegistroDuplicado: results[inv] = {'success': True} inv.message_post(body=_( "We saw that this invoice was sent correctly before, but we did not treat " "the response. Make sure it is not because of a wrong configuration." )) else: results[inv] = { 'error': _("[%s] %s", respl.CodigoErrorRegistro, respl.DescripcionErrorRegistro), 'blocking_level': 'error', } return results