def execute(cls, ids, data): ''' Execute the report on record ids. The dictionary with data that will be set in local context of the report. It returns a tuple with: report type, data, a boolean to direct print, the report name ''' pool = Pool() ActionReport = pool.get('ir.action.report') cls.check_access() action_id = data.get('action_id') if action_id is None: action_reports = ActionReport.search([('report_name', '=', cls.__name__)]) assert action_reports, '%s not found' % cls action_report = action_reports[0] else: action_report = ActionReport(action_id) records = [] model = action_report.model or data.get('model') if model: records = cls._get_records(ids, model, data) if action_report.single and len(records) > 1: content = BytesIO() with zipfile.ZipFile(content, 'w') as content_zip: for record in records: oext, rcontent = cls._execute([record], data, action_report) filename = slugify('%s-%s' % (record.id, record.rec_name)) rfilename = '%s.%s' % (filename, oext) content_zip.writestr(rfilename, rcontent) content = content.getvalue() oext = 'zip' else: oext, content = cls._execute(records, data, action_report) if not isinstance(content, str): content = bytearray(content) if bytes == str else bytes(content) suffix = '-'.join(r.rec_name for r in records[:5]) if len(records) > 5: suffix += '__' + str(len(records[5:])) report_name = '-'.join(filter(None, [action_report.name, suffix])) return (oext, content, action_report.direct_print, report_name)
def data(request, pool, model): User = pool.get('res.user') Lang = pool.get('ir.lang') try: Model = pool.get(model) except KeyError: abort(HTTPStatus.NOT_FOUND) transaction = Transaction() context = User(transaction.user).get_preferences(context_only=True) language = request.args.get('l') if language: context['language'] = language try: domain = json.loads(request.args.get('d', '[]'), object_hook=JSONDecoder()) except json.JSONDecodeError: abort(HTTPStatus.BAD_REQUEST) try: ctx = json.loads(request.args.get('c', '{}'), object_hook=JSONDecoder()) except json.JSONDecoder: abort(HTTPStatus.BAD_REQUEST) for key in list(ctx.keys()): if key.startswith('_') and key != '_datetime': del ctx[key] context.update(ctx) limit = None offset = 0 if 's' in request.args: try: limit = int(request.args.get('s')) if 'p' in request.args: offset = int(request.args.get('p')) * limit except ValueError: abort(HTTPStatus.BAD_REQUEST) if 'o' in request.args: order = [(o.split(',', 1) + [''])[:2] for o in request.args.getlist('o')] else: order = None fields_names = request.args.getlist('f') encoding = request.args.get('enc', 'UTF-8') delimiter = request.args.get('dl', ',') quotechar = request.args.get('qc', '"') try: header = bool(int(request.args.get('h', True))) locale_format = bool(int(request.args.get('loc', False))) except ValueError: abort(HTTPStatus.BAD_REQUEST) with transaction.set_context(**context): lang = Lang.get(transaction.language) def format_(row): for i, value in enumerate(row): if locale_format: if isinstance(value, Number): value = lang.format('%.12g', value) elif isinstance(value, (dt.date, dt.datetime)): value = lang.strftime(value) elif isinstance(value, bool): value = int(value) row[i] = value return row try: if domain and isinstance(domain[0], (int, float)): rows = Model.export_data(domain, fields_names) else: rows = Model.export_data_domain(domain, fields_names, limit=limit, offset=offset, order=order) except (ValueError, KeyError): abort(HTTPStatus.BAD_REQUEST) data = io.StringIO(newline='') writer = csv.writer(data, delimiter=delimiter, quotechar=quotechar) if header: writer.writerow(fields_names) for row in rows: writer.writerow(format_(row)) data = data.getvalue().encode(encoding) filename = slugify(Model.__names__()['model']) + '.csv' filename = filename.encode('latin-1', 'ignore') response = Response(data, mimetype='text/csv; charset=' + encoding) response.headers.add('Content-Disposition', 'attachment', filename=filename) response.headers.add('Content-Length', len(data)) return response
def on_change_string(self): if not self.name and self.string: self.name = slugify(self.string.lower(), hyphenate='_')
def execute(cls, ids, data): ''' Execute the report on record ids. The dictionary with data that will be set in local context of the report. It returns a tuple with: report type, data, a boolean to direct print, the report name ''' pool = Pool() ActionReport = pool.get('ir.action.report') cls.check_access() action_id = data.get('action_id') if action_id is None: action_reports = ActionReport.search([('report_name', '=', cls.__name__)]) assert action_reports, '%s not found' % cls action_report = action_reports[0] else: action_report = ActionReport(action_id) def report_name(records): name = '-'.join(r.rec_name for r in records[:5]) if len(records) > 5: name += '__' + str(len(records[5:])) return name records = [] model = action_report.model or data.get('model') if model: records = cls._get_records(ids, model, data) if action_report.single: groups = [[r] for r in records] headers = [dict(cls.header_key(r)) for r in records] else: groups = [] headers = [] for key, group in groupby(records, key=cls.header_key): groups.append(list(group)) headers.append(dict(key)) n = len(groups) if n > 1: padding = math.ceil(math.log10(n)) content = BytesIO() with zipfile.ZipFile(content, 'w') as content_zip: for i, (header, group_records) in enumerate(zip(headers, groups), 1): oext, rcontent = cls._execute(group_records, header, data, action_report) filename = report_name(group_records) number = str(i).zfill(padding) filename = slugify('%s-%s' % (number, filename)) rfilename = '%s.%s' % (filename, oext) content_zip.writestr(rfilename, rcontent) content = content.getvalue() oext = 'zip' else: oext, content = cls._execute(groups[0], headers[0], data, action_report) if not isinstance(content, str): content = bytearray(content) if bytes == str else bytes(content) filename = '-'.join( filter( None, [action_report.name, report_name(records)])) return (oext, content, action_report.direct_print, filename)
def test_slugify_hyphenate(self): "Test hyphenate in slugify" self.assertEqual(slugify('foo bar', hyphenate='_'), 'foo_bar')
def test_slugify(self): "Test slugify" self.assertEqual(slugify('unicode ♥ is ☢'), 'unicode-is')
def execute(cls, ids, data): ''' Execute the report on record ids. The dictionary with data that will be set in local context of the report. It returns a tuple with: report type, data, a boolean to direct print, the report name (with or without the record names) ''' pool = Pool() ActionReport = pool.get('ir.action.report') cls.check_access() context = Transaction().context ids = list(map(int, ids)) action_id = data.get('action_id') if action_id is None: action_reports = ActionReport.search([('report_name', '=', cls.__name__)]) assert action_reports, '%s not found' % cls action_report = action_reports[0] else: action_report = ActionReport(action_id) def report_name(records, reserved_length=0): names = [] name_length = 0 record_count = len(records) max_length = (REPORT_NAME_MAX_LENGTH - reserved_length - len(str(record_count)) - 2) if action_report.record_name: template = TextTemplate(action_report.record_name) else: template = None for record in records[:5]: if template: record_name = template.generate(record=record).render() else: record_name = record.rec_name name_length += len(unicodedata.normalize('NFKD', record_name)) + 1 if name_length > max_length: break names.append(record_name) name = '-'.join(names) if len(records) > len(names): name += '__' + str(record_count - len(names)) return name records = [] model = action_report.model or data.get('model') if model: records = cls._get_records(ids, model, data) if not records: groups = [[]] headers = [{}] elif action_report.single: groups = [[r] for r in records] headers = [dict(cls.header_key(r)) for r in records] else: groups = [] headers = [] for key, group in groupby(records, key=cls.header_key): groups.append(list(group)) headers.append(dict(key)) n = len(groups) join_string = '-' if n > 1: padding = math.ceil(math.log10(n)) content = BytesIO() with zipfile.ZipFile(content, 'w') as content_zip: for i, (header, group_records) in enumerate(zip(headers, groups), 1): oext, rcontent = cls._execute(group_records, header, data, action_report) number = str(i).zfill(padding) filename = report_name(group_records, len(number) + len(join_string)) filename = slugify(join_string.join([number, filename])) rfilename = '%s.%s' % (filename, oext) content_zip.writestr(rfilename, rcontent) content = content.getvalue() oext = 'zip' else: oext, content = cls._execute(groups[0], headers[0], data, action_report) if not isinstance(content, str): content = bytearray(content) if bytes == str else bytes(content) action_report_name = action_report.name[:REPORT_NAME_MAX_LENGTH] if context.get('with_rec_name', True): filename = join_string.join( filter(None, [ action_report_name, report_name(records, len(action_report_name) + len(join_string)) ])) else: filename = action_report_name return (oext, content, action_report.direct_print, filename)