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.

148 lines
5.4 KiB

9 years ago
9 years ago
9 years ago
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. _logger = logging.getLogger(__name__)
  9. try:
  10. from openerp.addons.report_xlsx.report.report_xlsx import ReportXlsx
  11. except ImportError:
  12. _logger.debug("report_xslx not installed, Excel export non functional")
  13. class ReportXslx:
  14. pass
  15. ROW_HEIGHT = 15 # xlsxwriter units
  16. COL_WIDTH = 0.9 # xlsxwriter units
  17. MIN_COL_WIDTH = 10 # characters
  18. MAX_COL_WIDTH = 50 # characters
  19. class MisBuilderXslx(ReportXlsx):
  20. def __init__(self, name, table, rml=False, parser=False, header=True,
  21. store=False):
  22. super(MisBuilderXslx, self).__init__(
  23. name, table, rml, parser, header, store)
  24. def make_number_format(self, kpi, comparison=False):
  25. # TODO FIXME comparison
  26. number_format = '#'
  27. if kpi.dp:
  28. number_format += '.'
  29. number_format += '0' * kpi.dp
  30. # TODO FIXME factor
  31. if kpi.prefix:
  32. number_format = u'"{} "{}'.format(kpi.prefix, number_format)
  33. if kpi.suffix:
  34. number_format = u'{}" {}"'.format(number_format, kpi.suffix)
  35. return number_format
  36. def generate_xlsx_report(self, workbook, data, objects):
  37. # get the computed result of the report
  38. matrix = objects._compute_matrix()
  39. # create worksheet
  40. report_name = '{} - {}'.format(
  41. objects[0].name, objects[0].company_id.name)
  42. sheet = workbook.add_worksheet(report_name[:31])
  43. row_pos = 0
  44. col_pos = 0
  45. # width of the labels column
  46. label_col_width = MIN_COL_WIDTH
  47. # {col_pos: max width in characters}
  48. col_width = defaultdict(lambda: MIN_COL_WIDTH)
  49. # document title
  50. bold = workbook.add_format({'bold': True})
  51. header_format = workbook.add_format({
  52. 'bold': True, 'align': 'center', 'bg_color': '#F0EEEE'})
  53. sheet.write(row_pos, 0, report_name, bold)
  54. row_pos += 2
  55. # column headers
  56. sheet.write(row_pos, 0, '', header_format)
  57. col_pos = 1
  58. for col in matrix.iter_cols():
  59. label = col.description
  60. if col.comment:
  61. label += '\n' + col.comment
  62. sheet.set_row(row_pos, ROW_HEIGHT * 2)
  63. if col.colspan > 1:
  64. sheet.merge_range(
  65. row_pos, col_pos, row_pos,
  66. col_pos + col.colspan-1,
  67. label, header_format)
  68. else:
  69. sheet.write(row_pos, col_pos, label, header_format)
  70. col_width[col_pos] = max(col_width[col_pos],
  71. len(col.description or ''),
  72. len(col.comment or ''))
  73. col_pos += col.colspan
  74. row_pos += 1
  75. # sub column headers
  76. sheet.write(row_pos, 0, '', header_format)
  77. col_pos = 1
  78. for subcol in matrix.iter_subcols():
  79. label = subcol.description
  80. if subcol.comment:
  81. label += '\n' + subcol.comment
  82. sheet.set_row(row_pos, ROW_HEIGHT * 2)
  83. sheet.write(row_pos, col_pos, label, header_format)
  84. col_width[col_pos] = max(col_width[col_pos],
  85. len(subcol.description or ''),
  86. len(subcol.comment or ''))
  87. col_pos += 1
  88. row_pos += 1
  89. # rows
  90. for row in matrix.iter_rows():
  91. if row.style:
  92. row_xlsx_style = row.style.to_xlsx_format_properties()
  93. else:
  94. row_xlsx_style = {}
  95. row_format = workbook.add_format(row_xlsx_style)
  96. col_pos = 0
  97. sheet.write(row_pos, col_pos, row.description, row_format)
  98. label_col_width = max(label_col_width, len(row.description or ''))
  99. for cell in row.iter_cells():
  100. col_pos += 1
  101. if not cell or cell.val is AccountingNone:
  102. sheet.write(row_pos, col_pos, '', row_format)
  103. continue
  104. kpi_xlsx_style = dict(row_xlsx_style)
  105. kpi_xlsx_style.update({
  106. 'num_format': self.make_number_format(row.kpi),
  107. 'align': 'right'
  108. })
  109. kpi_format = workbook.add_format(kpi_xlsx_style)
  110. # TODO FIXME kpi computed style
  111. # TODO FIXME pct in comparision columns
  112. val = cell.val
  113. if row.kpi.type == 'pct':
  114. val = val / 0.01
  115. sheet.write(row_pos, col_pos, val, kpi_format)
  116. col_width[col_pos] = max(col_width[col_pos],
  117. len(cell.val_rendered or ''))
  118. row_pos += 1
  119. # adjust col widths
  120. sheet.set_column(0, 0, min(label_col_width, MAX_COL_WIDTH) * COL_WIDTH)
  121. data_col_width = min(MAX_COL_WIDTH, max(*col_width.values()))
  122. min_col_pos = min(*col_width.keys())
  123. max_col_pos = max(*col_width.keys())
  124. sheet.set_column(min_col_pos, max_col_pos, data_col_width * COL_WIDTH)
  125. MisBuilderXslx('report.mis.report.instance.xlsx',
  126. 'mis.report.instance', parser=report_sxw.rml_parse)