Files
odoo_source/addons/web/controllers/list_controller.py
T
Lucas Lefèvre ac00548b28 [IMP] web: Export list view as XLS file
Purpose
=======

Have a quick export feature.

The current export wizard is quite complex.
We want to be able to quickly export a tree view,
with the group by correctly represented, depending on the fields
visible in the list view.

Specification
=============

Add an "EXPORT (XLS)" button in the list view (a little download icon)
- export only columns visible in list view
- export all the records
- while respecting the group by

This should be a generic feature but should be applied to all
the account.move.lines list views.
account.view_move_line_tree_grouped_sales_purchases
account.view_move_line_tree_grouped_bank_cash
account.view_move_line_tree_grouped_misc

Task 2031835

closes odoo/odoo#36943

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2019-09-16 13:57:40 +00:00

99 lines
4.0 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from datetime import datetime
from odoo import http
from odoo.http import request
from odoo.tools.misc import xlwt
HEADER_BOLD = xlwt.easyxf("font: bold on; pattern: pattern solid, fore_colour gray25;")
class TableListExporter(http.Controller):
def _write_group_header(self, worksheet, x, y, group, columns, group_depth=0):
aggregates = group.get('aggregateValues', {})
title = group.get('value')
if group.get('hideHeader'):
return x, y
title = '%s%s (%s)' % ('>' * group_depth, title, group.get('count', 0))
worksheet.write(x, y, title, HEADER_BOLD)
for column in columns[1:]: # No aggregates allowed in the first column
y += 1
worksheet.write(x, y, aggregates.get(column['field'], ''), HEADER_BOLD)
return x + 1, 0
def _write_record(self, worksheet, x, y, record, columns):
for column in columns:
worksheet.write(x, y, record[column['field']])
y += 1
return x + 1, 0
def _write_groups(self, worksheet, x, y, groups, columns, group_depth=0):
"""
Write groups to the xls worksheet. Recursive if groups are nested (chained groupby)
:param worksheet:
:param x: start position where to write the group (vertical axis, pointing downward)
:param y: start position where to write the group (horizontal axis, pointing to the right)
:param groups: list of groups. Each group is a dict containing either records' data
or sub-groups. A group has the following structure:
'data': list of records or list of sub-groups
'isGrouped': True if data contains sub-groups
'value': title of the group
'count': number of records in the group
'aggregateValues': dict container aggregated values of fields {field: aggregatedValue, ...}
'hideHeader': self explanatory, used when the records are not grouped at all.
:param columns: list of displayed columns. Each column is a dict with the following keys:
'field': field name
'aggregateValue': aggregate for all records
'string':
"""
for group in groups:
x, y = self._write_group_header(worksheet, x, y, group, columns, group_depth)
if group['isGrouped']:
# Recursively write sub-groups
x, y = self._write_groups(worksheet, x, y, group['data'], columns, group_depth + 1)
else:
for record in group['data']:
x, y = self._write_record(worksheet, x, y, record, columns)
return x, y
def _write_worksheet(self, worksheet, data):
bold = xlwt.easyxf("font: bold on;")
columns = data['columns']
groups = data['groups']
# Write main header
for y, field in enumerate(columns):
worksheet.write(0, y, field['string'], bold)
# Write data
x, y = 1, 0
x, y = self._write_groups(worksheet, x, y, groups, columns)
# Write column aggregates
for y, field in enumerate(columns):
worksheet.write(x, y, field.get('aggregateValue', ''), bold)
@http.route('/web/list/export_xls', type='http', auth="user")
def export_xls(self, data, token):
data = json.loads(data)
title = data.get('title', 'export')
workbook = xlwt.Workbook()
worksheet = workbook.add_sheet(title)
self._write_worksheet(worksheet, data)
response = request.make_response(None,
headers=[('Content-Type', 'application/vnd.ms-excel'),
('Content-Disposition', 'attachment; filename="%s - %s.xls"' % (title, datetime.now()))],
cookies={'fileToken': token})
workbook.save(response.stream)
return response