コード例 #1
0
 def _compile_directive_snippet(self, el, options):
     el.set('t-call', el.attrib.pop('t-snippet'))
     name = self.env['ir.ui.view'].search([
         ('key', '=', el.attrib.get('t-call'))
     ]).display_name
     thumbnail = el.attrib.pop('t-thumbnail', "oe-thumbnail")
     div = u'<div name="%s" data-oe-type="snippet" data-oe-thumbnail="%s">' % (
         escape(pycompat.to_text(name)), escape(
             pycompat.to_text(thumbnail)))
     return [self._append(ast.Str(div))] + self._compile_node(
         el, options) + [self._append(ast.Str(u'</div>'))]
コード例 #2
0
 def _compile_directive_install(self, el, options):
     if self.user_has_groups('base.group_system'):
         module = self.env['ir.module.module'].search([
             ('name', '=', el.attrib.get('t-install'))
         ])
         if not module or module.state == 'installed':
             return []
         name = el.attrib.get('string') or 'Snippet'
         thumbnail = el.attrib.pop('t-thumbnail', 'oe-thumbnail')
         div = u'<div name="%s" data-oe-type="snippet" data-module-id="%s" data-oe-thumbnail="%s"><section/></div>' % (
             escape(pycompat.to_text(name)), module.id,
             escape(pycompat.to_text(thumbnail)))
         return [self._append(ast.Str(div))]
     else:
         return []
コード例 #3
0
ファイル: fields.py プロジェクト: yasr3mr96/actpy
    def value_to_html(self, value, options):
        if 'decimal_precision' in options:
            precision = self.env['decimal.precision'].search([
                ('name', '=', options['decimal_precision'])
            ]).digits
        else:
            precision = options['precision']

        if precision is None:
            fmt = '%f'
        else:
            value = float_utils.float_round(value, precision_digits=precision)
            fmt = '%.{precision}f'.format(precision=precision)

        formatted = self.user_lang().format(fmt, value, grouping=True).replace(
            r'-', u'\u2011')

        # %f does not strip trailing zeroes. %g does but its precision causes
        # it to switch to scientific notation starting at a million *and* to
        # strip decimals. So use %f and if no precision was specified manually
        # strip trailing 0.
        if precision is None:
            formatted = re.sub(r'(?:(0|\d+?)0+)$', r'\1', formatted)

        return pycompat.to_text(formatted)
コード例 #4
0
ファイル: fields.py プロジェクト: yasr3mr96/actpy
    def value_to_html(self, value, options):
        if not value:
            return ''
        lang = self.user_lang()
        locale = babel.Locale.parse(lang.code)

        if isinstance(value, pycompat.string_types):
            value = fields.Datetime.from_string(value)

        value = fields.Datetime.context_timestamp(self, value)

        if options and 'format' in options:
            pattern = options['format']
        else:
            if options and options.get('time_only'):
                strftime_pattern = (u"%s" % (lang.time_format))
            else:
                strftime_pattern = (u"%s %s" %
                                    (lang.date_format, lang.time_format))

            pattern = posix_to_ldml(strftime_pattern, locale=locale)

        if options and options.get('hide_seconds'):
            pattern = pattern.replace(":ss", "").replace(":s", "")

        return pycompat.to_text(
            babel.dates.format_datetime(value, format=pattern, locale=locale))
コード例 #5
0
ファイル: fields.py プロジェクト: yasr3mr96/actpy
    def value_to_html(self, value, options):
        """ value_to_html(value, field, options=None)

        Converts a single value to its HTML version/output
        :rtype: unicode
        """
        return html_escape(pycompat.to_text(value), options)
コード例 #6
0
ファイル: fields.py プロジェクト: yasr3mr96/actpy
def nl2br(string):
    """ Converts newlines to HTML linebreaks in ``string``. returns
    the unicode result

    :param str string:
    :rtype: unicode
    """
    return pycompat.to_text(string).replace(u'\n', u'<br>\n')
コード例 #7
0
ファイル: iap.py プロジェクト: yasr3mr96/actpy
def charge(env,
           key,
           account_token,
           credit,
           description=None,
           credit_template=None):
    """
    Account charge context manager: takes a hold for ``credit``
    amount before executing the body, then captures it if there
    is no error, or cancels it if the body generates an exception.

    :param str key: service identifier
    :param str account_token: user identifier
    :param int credit: cost of the body's operation
    :param description: a description of the purpose of the charge,
                        the user will be able to see it in their
                        dashboard
    :type description: str
    :param credit_template: a QWeb template to render and show to the
                            user if their account does not have enough
                            credits for the requested operation
    :type credit_template: str
    """
    endpoint = get_endpoint(env)
    params = {
        'account_token': account_token,
        'credit': credit,
        'key': key,
        'description': description,
    }
    try:
        transaction_token = jsonrpc(endpoint + '/iap/1/authorize',
                                    params=params)
    except InsufficientCreditError as e:
        if credit_template:
            arguments = json.loads(e.args[0])
            arguments['body'] = pycompat.to_text(
                env['ir.qweb'].render(credit_template))
            e.args = (json.dumps(arguments), )
        raise e
    try:
        transaction = IapTransaction()
        transaction.credit = credit
        yield transaction
    except Exception as e:
        params = {
            'token': transaction_token,
            'key': key,
        }
        r = jsonrpc(endpoint + '/iap/1/cancel', params=params)
        raise e
    else:
        params = {
            'token': transaction_token,
            'key': key,
            'credit_to_capture': transaction.credit,
        }
        r = jsonrpc(endpoint + '/iap/1/capture', params=params)  # noqa
コード例 #8
0
ファイル: tax2csv.py プロジェクト: yasr3mr96/actpy
 def fiscal_pos_map_to_csv(self):
     writer = pycompat.csv_writer(
         open(
             'account.fiscal.'
             'position.tax.template-%s.csv' % self.suffix, 'wb'))
     fiscal_pos_map_iterator = self.iter_fiscal_pos_map()
     keys = next(fiscal_pos_map_iterator)
     writer.writerow(keys)
     for row in fiscal_pos_map_iterator:
         writer.writerow([pycompat.to_text(s) for s in row.values()])
コード例 #9
0
ファイル: ir_qweb.py プロジェクト: yasr3mr96/actpy
    def _get_asset_content(self, xmlid, options):
        options = dict(options,
            inherit_branding=False, inherit_branding_auto=False,
            edit_translations=False, translatable=False,
            rendering_bundle=True)

        env = self.env(context=options)

        # TODO: This helper can be used by any template that wants to embedd the backend.
        #       It is currently necessary because the ir.ui.view bundle inheritance does not
        #       match the module dependency graph.
        def get_modules_order():
            if request:
                from actpy.addons.web.controllers.main import module_boot
                return json.dumps(module_boot())
            return '[]'
        template = env['ir.qweb'].render(xmlid, {"get_modules_order": get_modules_order})

        files = []
        remains = []
        for el in html.fragments_fromstring(template):
            if isinstance(el, pycompat.string_types):
                remains.append(pycompat.to_text(el))
            elif isinstance(el, html.HtmlElement):
                href = el.get('href', '')
                src = el.get('src', '')
                atype = el.get('type')
                media = el.get('media')

                can_aggregate = not urls.url_parse(href).netloc and not href.startswith('/web/content')
                if el.tag == 'style' or (el.tag == 'link' and el.get('rel') == 'stylesheet' and can_aggregate):
                    if href.endswith('.sass'):
                        atype = 'text/sass'
                    elif href.endswith('.less'):
                        atype = 'text/less'
                    if atype not in ('text/less', 'text/sass'):
                        atype = 'text/css'
                    path = [segment for segment in href.split('/') if segment]
                    filename = get_resource_path(*path) if path else None
                    files.append({'atype': atype, 'url': href, 'filename': filename, 'content': el.text, 'media': media})
                elif el.tag == 'script':
                    atype = 'text/javascript'
                    path = [segment for segment in src.split('/') if segment]
                    filename = get_resource_path(*path) if path else None
                    files.append({'atype': atype, 'url': src, 'filename': filename, 'content': el.text, 'media': media})
                else:
                    remains.append(html.tostring(el, encoding='unicode'))
            else:
                try:
                    remains.append(html.tostring(el, encoding='unicode'))
                except Exception:
                    # notYETimplementederror
                    raise NotImplementedError

        return (files, remains)
コード例 #10
0
ファイル: fields.py プロジェクト: yasr3mr96/actpy
    def value_to_html(self, value, options):
        locale = babel.Locale.parse(self.user_lang().code)

        if isinstance(value, pycompat.string_types):
            value = fields.Datetime.from_string(value)

        # value should be a naive datetime in UTC. So is fields.Datetime.now()
        reference = fields.Datetime.from_string(options['now'])

        return pycompat.to_text(
            babel.dates.format_timedelta(value - reference,
                                         add_direction=True,
                                         locale=locale))
コード例 #11
0
ファイル: fields.py プロジェクト: yasr3mr96/actpy
    def record_to_html(self, record, field_name, options):
        if not getattr(record, field_name):
            return None

        view = getattr(record, field_name)

        if view._name != "ir.ui.view":
            _logger.warning("%s.%s must be a 'ir.ui.view' model." %
                            (record, field_name))
            return None

        view = view.with_context(object=record)

        return pycompat.to_text(view.render(view._context, engine='ir.qweb'))
コード例 #12
0
ファイル: ir_mail_server.py プロジェクト: yasr3mr96/actpy
    def encode_addr(addr):
        name, email = addr
        # If s is a <text string>, then charset is a hint specifying the
        # character set of the characters in the string. The Unicode string
        # will be encoded using the following charsets in order: us-ascii,
        # the charset hint, utf-8. The first character set to not provoke a
        # UnicodeError is used.
        # -> always pass a text string to Header

        # also Header.__str__ in Python 3 "Returns an approximation of the
        # Header as a string, using an unlimited line length.", the old one
        # was "A synonym for Header.encode()." so call encode() directly?
        name = Header(pycompat.to_text(name)).encode()
        return formataddr((name, email))
コード例 #13
0
ファイル: ir_qweb.py プロジェクト: yasr3mr96/actpy
    def record_to_html(self, record, field_name, options):
        assert options['tagName'] != 'img',\
            "Oddly enough, the root tag of an image field can not be img. " \
            "That is because the image goes into the tag, or it gets the " \
            "hose again."

        if options.get('qweb_img_raw_data', False):
            return super(Image, self).record_to_html(record, field_name,
                                                     options)

        aclasses = ['img', 'img-responsive'] if options.get(
            'qweb_img_responsive', True) else ['img']
        aclasses += options.get('class', '').split()
        classes = ' '.join(pycompat.imap(escape, aclasses))

        max_size = None
        if options.get('resize'):
            max_size = options.get('resize')
        else:
            max_width, max_height = options.get('max_width', 0), options.get(
                'max_height', 0)
            if max_width or max_height:
                max_size = '%sx%s' % (max_width, max_height)

        sha = hashlib.sha1(getattr(
            record, '__last_update').encode('utf-8')).hexdigest()[0:7]
        max_size = '' if max_size is None else '/%s' % max_size
        src = '/web/image/%s/%s/%s%s?unique=%s' % (record._name, record.id,
                                                   field_name, max_size, sha)

        alt = None
        if options.get('alt-field') and getattr(record, options['alt-field'],
                                                None):
            alt = escape(record[options['alt-field']])
        elif options.get('alt'):
            alt = options['alt']

        src_zoom = None
        if options.get('zoom') and getattr(record, options['zoom'], None):
            src_zoom = '/web/image/%s/%s/%s%s?unique=%s' % (
                record._name, record.id, options['zoom'], max_size, sha)
        elif options.get('zoom'):
            src_zoom = options['zoom']

        img = '<img class="%s" src="%s" style="%s"%s%s/>' % \
            (classes, src, options.get('style', ''), ' alt="%s"' % alt if alt else '', ' data-zoom="1" data-zoom-image="%s"' % src_zoom if src_zoom else '')
        return pycompat.to_text(img)
コード例 #14
0
ファイル: tax2csv.py プロジェクト: yasr3mr96/actpy
 def taxes_to_csv(self):
     writer = pycompat.csv_writer(
         open('account.tax.template-%s.csv' % self.suffix, 'wb'))
     taxes_iterator = self.iter_taxes()
     keys = next(taxes_iterator)
     writer.writerow(keys[3:] + ['sequence'])
     seq = 100
     for row in sorted(taxes_iterator, key=lambda r: r['description']):
         if not _is_true(row['active']):
             continue
         seq += 1
         if row['parent_id:id']:
             cur_seq = seq + 1000
         else:
             cur_seq = seq
         writer.writerow(
             [pycompat.to_text(v)
              for v in list(row.values())[3:]] + [cur_seq])
コード例 #15
0
ファイル: tax2csv.py プロジェクト: yasr3mr96/actpy
    def tax_codes_to_csv(self):
        writer = pycompat.csv_writer(
            open('account.tax.code.template-%s.csv' % self.suffix, 'wb'))
        tax_codes_iterator = self.iter_tax_codes()
        keys = next(tax_codes_iterator)
        writer.writerow(keys)

        # write structure tax codes
        tax_codes = {}  # code: id
        for row in tax_codes_iterator:
            tax_code = row['code']
            if tax_code in tax_codes:
                raise RuntimeError('duplicate tax code %s' % tax_code)
            tax_codes[tax_code] = row['id']
            writer.writerow([pycompat.to_text(v) for v in row.values()])

        # read taxes and add leaf tax codes
        new_tax_codes = {}  # id: parent_code

        def add_new_tax_code(tax_code_id, new_name, new_parent_code):
            if not tax_code_id:
                return
            name, parent_code = new_tax_codes.get(tax_code_id, (None, None))
            if parent_code and parent_code != new_parent_code:
                raise RuntimeError('tax code "%s" already exist with '
                                   'parent %s while trying to add it with '
                                   'parent %s' %
                                   (tax_code_id, parent_code, new_parent_code))
            else:
                new_tax_codes[tax_code_id] = (new_name, new_parent_code)

        taxes_iterator = self.iter_taxes()
        next(taxes_iterator)
        for row in taxes_iterator:
            if not _is_true(row['active']):
                continue
            if row['child_depend'] and row['amount'] != 1:
                raise RuntimeError('amount must be one if child_depend '
                                   'for %s' % row['id'])
            # base parent
            base_code = row['BASE_CODE']
            if not base_code or base_code == '/':
                base_code = 'NA'
            if base_code not in tax_codes:
                raise RuntimeError('undefined tax code %s' % base_code)
            if base_code != 'NA':
                if row['child_depend']:
                    raise RuntimeError('base code specified '
                                       'with child_depend for %s' % row['id'])
            if not row['child_depend']:
                # ... in lux, we have the same code for invoice and refund
                if base_code != 'NA':
                    assert row[
                        'base_code_id:id'], 'missing base_code_id for %s' % row[
                            'id']
                assert row['ref_base_code_id:id'] == row['base_code_id:id']
                add_new_tax_code(row['base_code_id:id'],
                                 'Base - ' + row['name'], base_code)
            # tax parent
            tax_code = row['TAX_CODE']
            if not tax_code or tax_code == '/':
                tax_code = 'NA'
            if tax_code not in tax_codes:
                raise RuntimeError('undefined tax code %s' % tax_code)
            if tax_code == 'NA':
                if row['amount'] and not row['child_depend']:
                    raise RuntimeError('TAX_CODE not specified '
                                       'for non-zero tax %s' % row['id'])
                if row['tax_code_id:id']:
                    raise RuntimeError('tax_code_id specified '
                                       'for tax %s' % row['id'])
            else:
                if row['child_depend']:
                    raise RuntimeError('TAX_CODE specified '
                                       'with child_depend for %s' % row['id'])
                if not row['amount']:
                    raise RuntimeError('TAX_CODE specified '
                                       'for zero tax %s' % row['id'])
                if not row['tax_code_id:id']:
                    raise RuntimeError('tax_code_id not specified '
                                       'for tax %s' % row['id'])
            if not row['child_depend'] and row['amount']:
                # ... in lux, we have the same code for invoice and refund
                assert row[
                    'tax_code_id:id'], 'missing tax_code_id for %s' % row['id']
                assert row['ref_tax_code_id:id'] == row['tax_code_id:id']
                add_new_tax_code(row['tax_code_id:id'],
                                 'Taxe - ' + row['name'], tax_code)

        for tax_code_id in sorted(new_tax_codes):
            name, parent_code = new_tax_codes[tax_code_id]
            writer.writerow([
                tax_code_id, u'lu_tct_m' + parent_code,
                tax_code_id.replace('lu_tax_code_template_', u''), u'1', u'',
                pycompat.to_text(name), u''
            ])
コード例 #16
0
ファイル: fields.py プロジェクト: yasr3mr96/actpy
 def value_to_html(self, value, options):
     return pycompat.to_text(value)
コード例 #17
0
ファイル: fields.py プロジェクト: yasr3mr96/actpy
 def value_to_html(self, value, options):
     if not value:
         return ''
     return html_escape(
         pycompat.to_text(options['selection'][value]) or u'', options)
コード例 #18
0
    def binary_content(cls,
                       xmlid=None,
                       model='ir.attachment',
                       id=None,
                       field='datas',
                       unique=False,
                       filename=None,
                       filename_field='datas_fname',
                       download=False,
                       mimetype=None,
                       default_mimetype='application/octet-stream',
                       access_token=None,
                       env=None):
        """ Get file, attachment or downloadable content

        If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the
        binary field (via ``default_get``), otherwise fetches the field for
        that precise record.

        :param str xmlid: xmlid of the record
        :param str model: name of the model to fetch the binary from
        :param int id: id of the record from which to fetch the binary
        :param str field: binary field
        :param bool unique: add a max-age for the cache control
        :param str filename: choose a filename
        :param str filename_field: if not create an filename with model-id-field
        :param bool download: apply headers to download the file
        :param str mimetype: mintype of the field (for headers)
        :param str default_mimetype: default mintype if no mintype found
        :param str access_token: optional token for unauthenticated access
                                 only available  for ir.attachment
        :param Environment env: by default use request.env
        :returns: (status, headers, content)
        """
        env = env or request.env
        # get object and content
        obj = None
        if xmlid:
            obj = env.ref(xmlid, False)
        elif id and model == 'ir.attachment' and access_token:
            obj = env[model].sudo().browse(int(id))
            if not consteq(obj.access_token, access_token):
                return (403, [], None)
        elif id and model in env.registry:
            obj = env[model].browse(int(id))

        # obj exists
        if not obj or not obj.exists() or field not in obj:
            return (404, [], None)

        # check read access
        try:
            last_update = obj['__last_update']
        except AccessError:
            return (403, [], None)

        status, headers, content = None, [], None

        # attachment by url check
        module_resource_path = None
        if model == 'ir.attachment' and obj.type == 'url' and obj.url:
            url_match = re.match("^/(\w+)/(.+)$", obj.url)
            if url_match:
                module = url_match.group(1)
                module_path = get_module_path(module)
                module_resource_path = get_resource_path(
                    module, url_match.group(2))
                if module_path and module_resource_path:
                    module_path = os.path.join(
                        os.path.normpath(module_path),
                        '')  # join ensures the path ends with '/'
                    module_resource_path = os.path.normpath(
                        module_resource_path)
                    if module_resource_path.startswith(module_path):
                        with open(module_resource_path, 'rb') as f:
                            content = base64.b64encode(f.read())
                        last_update = pycompat.text_type(
                            os.path.getmtime(module_resource_path))

            if not module_resource_path:
                module_resource_path = obj.url

            if not content:
                status = 301
                content = module_resource_path
        else:
            content = obj[field] or ''

        # filename
        if not filename:
            if filename_field in obj:
                filename = obj[filename_field]
            elif module_resource_path:
                filename = os.path.basename(module_resource_path)
            else:
                filename = "%s-%s-%s" % (obj._name, obj.id, field)

        # mimetype
        mimetype = 'mimetype' in obj and obj.mimetype or False
        if not mimetype:
            if filename:
                mimetype = mimetypes.guess_type(filename)[0]
            if not mimetype and getattr(env[model]._fields[field],
                                        'attachment', False):
                # for binary fields, fetch the ir_attachement for mimetype check
                attach_mimetype = env['ir.attachment'].search_read(
                    domain=[('res_model', '=', model), ('res_id', '=', id),
                            ('res_field', '=', field)],
                    fields=['mimetype'],
                    limit=1)
                mimetype = attach_mimetype and attach_mimetype[0]['mimetype']
            if not mimetype:
                mimetype = guess_mimetype(base64.b64decode(content),
                                          default=default_mimetype)

        headers += [('Content-Type', mimetype),
                    ('X-Content-Type-Options', 'nosniff')]

        # cache
        etag = bool(request) and request.httprequest.headers.get(
            'If-None-Match')
        retag = '"%s"' % hashlib.md5(
            pycompat.to_text(content).encode('utf-8')).hexdigest()
        status = status or (304 if etag == retag else 200)
        headers.append(('ETag', retag))
        headers.append(
            ('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0)))

        # content-disposition default name
        if download:
            headers.append(
                ('Content-Disposition', cls.content_disposition(filename)))
        return (status, headers, content)
コード例 #19
0
ファイル: fields.py プロジェクト: yasr3mr96/actpy
 def value_to_html(self, value, options):
     return pycompat.to_text(self.user_lang().format('%d',
                                                     value,
                                                     grouping=True).replace(
                                                         r'-', u'\u2011'))