You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
5.3 KiB

9 years ago
  1. # -*- coding: utf-8 -*-
  2. # © 2014-2016 ACSONE SA/NV (<http://acsone.eu>)
  3. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
  4. from collections import defaultdict
  5. import logging
  6. from openerp.report import report_sxw
  7. from ..models.accounting_none import AccountingNone
  8. from ..models.data_error import DataError
  9. _logger = logging.getLogger(__name__)
  10. try:
  11. from openerp.addons.report_xlsx.report.report_xlsx import ReportXlsx
  12. except ImportError:
  13. _logger.debug("report_xlsx not installed, Excel export non functional")
  14. class ReportXlsx(object):
  15. def __init__(self, *args, **kwargs):
  16. pass
  17. ROW_HEIGHT = 15 # xlsxwriter units
  18. COL_WIDTH = 0.9 # xlsxwriter units
  19. MIN_COL_WIDTH = 10 # characters
  20. MAX_COL_WIDTH = 50 # characters
  21. class MisBuilderXlsx(ReportXlsx):
  22. def __init__(self, name, table, rml=False, parser=False, header=True,
  23. store=False):
  24. super(MisBuilderXlsx, self).__init__(
  25. name, table, rml, parser, header, store)
  26. def generate_xlsx_report(self, workbook, data, objects):
  27. # get the computed result of the report
  28. matrix = objects._compute_matrix()
  29. style_obj = self.env['mis.report.style']
  30. # create worksheet
  31. report_name = u'{} - {}'.format(
  32. objects[0].name, objects[0].company_id.name)
  33. sheet = workbook.add_worksheet(report_name[:31])
  34. row_pos = 0
  35. col_pos = 0
  36. # width of the labels column
  37. label_col_width = MIN_COL_WIDTH
  38. # {col_pos: max width in characters}
  39. col_width = defaultdict(lambda: MIN_COL_WIDTH)
  40. # document title
  41. bold = workbook.add_format({'bold': True})
  42. header_format = workbook.add_format({
  43. 'bold': True, 'align': 'center', 'bg_color': '#F0EEEE'})
  44. sheet.write(row_pos, 0, report_name, bold)
  45. row_pos += 2
  46. # column headers
  47. sheet.write(row_pos, 0, '', header_format)
  48. col_pos = 1
  49. for col in matrix.iter_cols():
  50. label = col.label
  51. if col.description:
  52. label += '\n' + col.description
  53. sheet.set_row(row_pos, ROW_HEIGHT * 2)
  54. if col.colspan > 1:
  55. sheet.merge_range(
  56. row_pos, col_pos, row_pos,
  57. col_pos + col.colspan-1,
  58. label, header_format)
  59. else:
  60. sheet.write(row_pos, col_pos, label, header_format)
  61. col_width[col_pos] = max(col_width[col_pos],
  62. len(col.label or ''),
  63. len(col.description or ''))
  64. col_pos += col.colspan
  65. row_pos += 1
  66. # sub column headers
  67. sheet.write(row_pos, 0, '', header_format)
  68. col_pos = 1
  69. for subcol in matrix.iter_subcols():
  70. label = subcol.label
  71. if subcol.description:
  72. label += '\n' + subcol.description
  73. sheet.set_row(row_pos, ROW_HEIGHT * 2)
  74. sheet.write(row_pos, col_pos, label, header_format)
  75. col_width[col_pos] = max(col_width[col_pos],
  76. len(subcol.label or ''),
  77. len(subcol.description or ''))
  78. col_pos += 1
  79. row_pos += 1
  80. # rows
  81. for row in matrix.iter_rows():
  82. row_xlsx_style = style_obj.to_xlsx_style(row.style_props)
  83. row_format = workbook.add_format(row_xlsx_style)
  84. col_pos = 0
  85. label = row.label
  86. if row.description:
  87. label += '\n' + row.description
  88. sheet.set_row(row_pos, ROW_HEIGHT * 2)
  89. sheet.write(row_pos, col_pos, label, row_format)
  90. label_col_width = max(label_col_width,
  91. len(row.label or ''),
  92. len(row.description or ''))
  93. for cell in row.iter_cells():
  94. col_pos += 1
  95. if not cell or cell.val is AccountingNone:
  96. # TODO col/subcol format
  97. sheet.write(row_pos, col_pos, '', row_format)
  98. continue
  99. cell_xlsx_style = style_obj.to_xlsx_style(cell.style_props)
  100. cell_xlsx_style['align'] = 'right'
  101. cell_format = workbook.add_format(cell_xlsx_style)
  102. if isinstance(cell.val, DataError):
  103. val = cell.val.name
  104. # TODO display cell.val.msg as Excel comment?
  105. elif cell.val is None or cell.val is AccountingNone:
  106. val = ''
  107. else:
  108. val = cell.val / float(cell.style_props.get('divider', 1))
  109. sheet.write(row_pos, col_pos, val, cell_format)
  110. col_width[col_pos] = max(col_width[col_pos],
  111. len(cell.val_rendered or ''))
  112. row_pos += 1
  113. # adjust col widths
  114. sheet.set_column(0, 0, min(label_col_width, MAX_COL_WIDTH) * COL_WIDTH)
  115. data_col_width = min(MAX_COL_WIDTH, max(col_width.values()))
  116. min_col_pos = min(col_width.keys())
  117. max_col_pos = max(col_width.keys())
  118. sheet.set_column(min_col_pos, max_col_pos, data_col_width * COL_WIDTH)
  119. MisBuilderXlsx('report.mis.report.instance.xlsx',
  120. 'mis.report.instance', parser=report_sxw.rml_parse)