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.

274 lines
10 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2009-2016 Noviat
  3. # Copyright 2018 Jacques-Etienne Baudoux (BCIM sprl) <je@bcim.be>
  4. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  5. # from datetime import datetime
  6. from openerp.addons.report_xlsx.report.report_xlsx import ReportXlsx
  7. from openerp.addons.account_financial_report_webkit.report.general_ledger \
  8. import GeneralLedgerWebkit
  9. from openerp.tools.translate import _
  10. def cell(row, col, row_abs=False, col_abs=False):
  11. """
  12. Convert numeric row/col notation to an Excel cell
  13. reference string in A1 notation.
  14. """
  15. d = col // 26
  16. m = col % 26
  17. chr1 = "" # Most significant character in AA1
  18. if row_abs:
  19. row_abs = '$'
  20. else:
  21. row_abs = ''
  22. if col_abs:
  23. col_abs = '$'
  24. else:
  25. col_abs = ''
  26. if d > 0:
  27. chr1 = chr(ord('A') + d - 1)
  28. chr2 = chr(ord('A') + m)
  29. # Zero index to 1-index
  30. return col_abs + chr1 + chr2 + row_abs + str(row + 1)
  31. class report_xlsx_format:
  32. decimal_format = '#,##0.00'
  33. date_format = '%Y-%m-%d'
  34. styles = {
  35. 'xls_title': [('bold', True), ('font_size', 10)],
  36. 'bold': [('bold', True)],
  37. 'underline': [('underline', True)],
  38. 'italic': [('italic', True)],
  39. 'fill_green': [('bg_color', '#CCFFCC')],
  40. 'fill_yellow': [('bg_color', '#FFFFCC')],
  41. 'money': [('num_format', decimal_format)],
  42. 'date': [('num_format', date_format)],
  43. 'borders_all': [('border', 1)],
  44. 'center': [('align', 'center')],
  45. 'right': [('align', 'right')],
  46. }
  47. def _get_style(self, wb, keys):
  48. if not isinstance(keys, (list, tuple)):
  49. keys = (keys, )
  50. style = dict(reduce(
  51. lambda x, y: x+y, [self.styles[k] for k in keys]))
  52. style.setdefault('font_size', 9)
  53. return wb.add_format(style)
  54. class AttrDict(dict):
  55. def __init__(self, *args, **kwargs):
  56. super(AttrDict, self).__init__(*args, **kwargs)
  57. self.__dict__ = self
  58. class GeneralLedgerXlsx(ReportXlsx, report_xlsx_format):
  59. column_sizes = [
  60. 10, # date
  61. 8, # period
  62. 15, # move
  63. 8, # journal,
  64. 8, # account_code
  65. 30, # partner
  66. 25, # ref
  67. 45, # label
  68. 30, # counterpart
  69. 12, # debit
  70. 12, # credit
  71. 12, # bal
  72. 12, # filtered_bal
  73. 12, # cumul_bal
  74. 12, # curr_bal
  75. 12, # curr_code
  76. ]
  77. def generate_xlsx_report(self, wb, data, objects):
  78. _p = AttrDict(self.parser_instance.localcontext)
  79. wb.formats[0].set_font_size(9)
  80. ws = wb.add_worksheet(_p.report_name.upper()[:31])
  81. ws.set_default_row(13)
  82. ws.panes_frozen = True
  83. ws.remove_splits = True
  84. ws.portrait = 0 # Landscape
  85. ws.fit_width_to_pages = 1
  86. row_pos = 0
  87. # set print header/footer
  88. # ws.header_str = self.xls_headers['standard']
  89. # ws.footer_str = self.xls_footers['standard']
  90. # cf. account_report_general_ledger.mako
  91. initial_balance_text = {'initial_balance': _('Computed'),
  92. 'opening_balance': _('Opening Entries'),
  93. False: _('No')}
  94. # Title
  95. row_pos = 0
  96. style_title = self._get_style(wb, 'xls_title')
  97. report_name = ' - '.join([_p.report_name.upper(),
  98. _p.company.partner_id.name,
  99. _p.company.currency_id.name])
  100. ws.write(row_pos, 0, report_name, style_title)
  101. for i, size in enumerate(self.column_sizes):
  102. ws.set_column(i, i, size)
  103. row_pos += 2
  104. # Header Table
  105. style_header1 = self._get_style(wb, ('bold', 'fill_green', 'center'))
  106. style_header2 = self._get_style(wb, ('center'))
  107. ws.merge_range(
  108. row_pos, 0, row_pos, 1, _('Chart of Account'), style_header1)
  109. ws.merge_range(
  110. row_pos+1, 0, row_pos+1, 1, _p.chart_account.name, style_header2)
  111. ws.write(row_pos, 2, _('Fiscal Year'), style_header1)
  112. ws.write(row_pos+1, 2, _p.fiscalyear.name if _p.fiscalyear else '-',
  113. style_header2)
  114. df = _('From') + ': %s ' + _('To') + ': %s'
  115. if _p.filter_form(data) == 'filter_date':
  116. dfh = _('Dates Filter')
  117. df = df % (_p.start_date or '', _p.stop_date or '')
  118. else:
  119. dfh = _('Periods Filter')
  120. df = df % (_p.start_period and _p.start_period.name or '',
  121. _p.stop_period and _p.stop_period.name or '')
  122. ws.merge_range(row_pos, 3, row_pos, 5, dfh, style_header1)
  123. ws.merge_range(row_pos+1, 3, row_pos+1, 5, df, style_header2)
  124. ws.write(row_pos, 6, _('Accounts Filter'), style_header1)
  125. text = _p.accounts(data) and ', '.join([
  126. account.code for account in _p.accounts(data)]) or _('All')
  127. ws.write(row_pos+1, 6, text, style_header2)
  128. ws.write(row_pos, 7, _('Target Moves'), style_header1)
  129. ws.write(row_pos+1, 7, _p.display_target_move(data), style_header2)
  130. ws.write(row_pos, 8, _('Initial Balance'), style_header1)
  131. text = initial_balance_text[_p.initial_balance_mode]
  132. ws.write(row_pos+1, 8, text, style_header2)
  133. row_pos += 2
  134. ws.freeze_panes(row_pos, 0)
  135. row_pos += 1
  136. # cell styles for ledger lines
  137. style_account = self._get_style(wb, ('bold'))
  138. style_labels = self._get_style(wb, ('fill_yellow'))
  139. style_labels_r = self._get_style(wb, ('fill_yellow', 'right', 'bold'))
  140. style_initial_balance = self._get_style(wb, ('italic', 'money'))
  141. # style_date = self._get_style(wb, ('date'))
  142. style_lines = self._get_style(wb, ('money'))
  143. style_sums = self._get_style(wb, ('fill_yellow', 'money', 'bold'))
  144. for account in _p.objects:
  145. display_initial_balance = _p['init_balance'][account.id] and \
  146. (_p['init_balance'][account.id].get(
  147. 'debit', 0.0) != 0.0 or
  148. _p['init_balance'][account.id].get('credit', 0.0) != 0.0)
  149. if (not display_initial_balance and
  150. not _p['ledger_lines'][account.id]):
  151. # no lines and no initial balance, do no show account in report
  152. continue
  153. # Write account
  154. name = ' - '.join([account.code, account.name])
  155. ws.write(row_pos, 0, name, style_account)
  156. row_pos += 1
  157. # Write labels
  158. ws.write_row(row_pos, 0, [
  159. _('Date'), _('Period'), _('Entry'), _('Journal'), _('Account'),
  160. _('Partner'), _('Reference'), _('Label'), _('Counterpart')],
  161. style_labels)
  162. ws.write_row(row_pos, 9, [
  163. _('Debit'), _('Credit'), _('Filtered Bal.'), _('Cumul. Bal.')
  164. ], style_labels_r)
  165. row_pos += 1
  166. row_start = row_pos
  167. cumul_balance = cumul_balance_curr = 0
  168. # Write initial balance
  169. if display_initial_balance:
  170. ws.write(row_pos, 8, _('Initial Balance'),
  171. style_initial_balance)
  172. init_balance = _p['init_balance'][account.id]
  173. cumul_balance += init_balance.get('init_balance') or 0.0
  174. cumul_balance_curr += \
  175. init_balance.get('init_balance_currency') or 0.0
  176. row = [
  177. init_balance.get('debit') or 0.0,
  178. init_balance.get('credit') or 0.0,
  179. '',
  180. cumul_balance,
  181. ]
  182. if _p.amount_currency(data):
  183. row.append(cumul_balance_curr)
  184. ws.write_row(row_pos, 9, row, style_initial_balance)
  185. row_pos += 1
  186. # Write lines
  187. for line in _p['ledger_lines'][account.id]:
  188. label_elements = [line.get('lname') or '']
  189. if line.get('invoice_number'):
  190. label_elements.append(
  191. "(%s)" % (line['invoice_number'],))
  192. label = ' '.join(label_elements)
  193. cumul_balance += line.get('balance') or 0.0
  194. if line['ldate']:
  195. ws.write_string(row_pos, 0, line['ldate'])
  196. # FIXME: date format not recognized
  197. # ws.write_datetime(
  198. # row_pos, 0,
  199. # datetime.strptime(line['ldate'], '%Y-%m-%d'),
  200. # style_date)
  201. row = [
  202. line.get('period_code') or '',
  203. line.get('move_name') or '',
  204. line.get('jcode') or '',
  205. account.code,
  206. line.get('partner_name') or '',
  207. line.get('lref'),
  208. label,
  209. line.get('counterparts') or '',
  210. line.get('debit', 0.0),
  211. line.get('credit', 0.0),
  212. line.get('balance', 0.0),
  213. cumul_balance,
  214. ]
  215. if _p.amount_currency(data):
  216. cumul_balance_curr += line.get('amount_currency') or 0.0
  217. row += [
  218. line.get('amount_currency') or 0.0,
  219. line.get('currency_code') or '',
  220. ]
  221. ws.write_row(row_pos, 1, row, style_lines)
  222. row_pos += 1
  223. # Write Sums
  224. row = [
  225. _('Cumulated Balance on Account'),
  226. '=SUM(%s:%s)' % (cell(row_start, 9), cell(row_pos-1, 9)),
  227. '=SUM(%s:%s)' % (cell(row_start, 10), cell(row_pos-1, 10)),
  228. '=SUM(%s:%s)' % (cell(row_start, 11), cell(row_pos-1, 11)),
  229. '=%s-%s' % (cell(row_pos, 9), cell(row_pos, 10)),
  230. ]
  231. if _p.amount_currency(data):
  232. row += [
  233. cumul_balance_curr,
  234. line.get('currency_code') or '',
  235. ]
  236. ws.write_row(row_pos, 8, row, style_sums)
  237. row_pos += 1
  238. GeneralLedgerXlsx('report.account.account_report_general_ledger_xlsx',
  239. 'account.account',
  240. parser=GeneralLedgerWebkit)