Esempio n. 1
0
    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
Esempio n. 2
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, html_escape(lead.name))
     self._send_transient_message(partner, msg)
Esempio n. 3
0
 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
Esempio n. 4
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:
         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)
Esempio n. 5
0
    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
Esempio n. 6
0
    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)
Esempio n. 7
0
 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)))
Esempio n. 8
0
 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)
Esempio n. 9
0
    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),
        ])
Esempio n. 10
0
    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