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.

450 lines
16 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2009-2018 Noviat
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. import logging
  5. from odoo.addons.report_xlsx_helper.report.abstract_report_xlsx \
  6. import AbstractReportXlsx
  7. from odoo.report import report_sxw
  8. from odoo.tools.translate import translate
  9. _logger = logging.getLogger(__name__)
  10. IR_TRANSLATION_NAME = 'move.line.list.xls'
  11. class MoveLineXlsx(AbstractReportXlsx):
  12. def _(self, src):
  13. lang = self.env.context.get('lang', 'en_US')
  14. val = translate(
  15. self.env.cr, IR_TRANSLATION_NAME, 'report', lang, src) or src
  16. return val
  17. def _get_ws_params(self, workbook, data, amls):
  18. # XLSX Template
  19. col_specs = {
  20. 'move': {
  21. 'header': {
  22. 'value': self._('Entry'),
  23. },
  24. 'lines': {
  25. 'value': self._render("line.move_id.name"),
  26. },
  27. 'width': 20,
  28. },
  29. 'name': {
  30. 'header': {
  31. 'value': self._('Name'),
  32. },
  33. 'lines': {
  34. 'value': self._render("line.name"),
  35. },
  36. 'width': 42,
  37. },
  38. 'ref': {
  39. 'header': {
  40. 'value': self._('Reference'),
  41. },
  42. 'lines': {
  43. 'value': self._render("line.ref"),
  44. },
  45. 'width': 42,
  46. },
  47. 'date': {
  48. 'header': {
  49. 'value': self._('Effective Date'),
  50. },
  51. 'lines': {
  52. 'value': self._render(
  53. "datetime.strptime(line.date, '%Y-%m-%d')"),
  54. 'format': self.format_tcell_date_left,
  55. },
  56. 'width': 13,
  57. },
  58. 'partner': {
  59. 'header': {
  60. 'value': self._('Partner'),
  61. },
  62. 'lines': {
  63. 'value': self._render(
  64. "line.partner_id and line.partner_id.name"),
  65. },
  66. 'width': 36,
  67. },
  68. 'partner_ref': {
  69. 'header': {
  70. 'value': self._('Partner Reference'),
  71. },
  72. 'lines': {
  73. 'value': self._render(
  74. "line.partner_id and line.partner_id.ref"),
  75. },
  76. 'width': 36,
  77. },
  78. 'account': {
  79. 'header': {
  80. 'value': self._('Account'),
  81. },
  82. 'lines': {
  83. 'value': self._render(
  84. "line.account_id.code"),
  85. },
  86. 'width': 12,
  87. },
  88. 'date_maturity': {
  89. 'header': {
  90. 'value': self._('Maturity Date'),
  91. },
  92. 'lines': {
  93. 'value': self._render(
  94. "datetime.strptime(line.date_maturity,'%Y-%m-%d')"),
  95. 'format': self.format_tcell_date_left,
  96. },
  97. 'width': 13,
  98. },
  99. 'debit': {
  100. 'header': {
  101. 'value': self._('Debit'),
  102. 'format': self.format_theader_yellow_right,
  103. },
  104. 'lines': {
  105. 'value': self._render("line.debit"),
  106. 'format': self.format_tcell_amount_right,
  107. },
  108. 'totals': {
  109. 'type': 'formula',
  110. 'value': self._render("debit_formula"),
  111. 'format': self.format_theader_yellow_amount_right,
  112. },
  113. 'width': 18,
  114. },
  115. 'credit': {
  116. 'header': {
  117. 'value': self._('Credit'),
  118. 'format': self.format_theader_yellow_right,
  119. },
  120. 'lines': {
  121. 'value': self._render("line.credit"),
  122. 'format': self.format_tcell_amount_right,
  123. },
  124. 'totals': {
  125. 'type': 'formula',
  126. 'value': self._render("credit_formula"),
  127. 'format': self.format_theader_yellow_amount_right,
  128. },
  129. 'width': 18,
  130. },
  131. 'balance': {
  132. 'header': {
  133. 'value': self._('Balance'),
  134. 'format': self.format_theader_yellow_right,
  135. },
  136. 'lines': {
  137. 'value': self._render("line.balance"),
  138. 'format': self.format_tcell_amount_right,
  139. },
  140. 'totals': {
  141. 'type': 'formula',
  142. 'value': self._render("bal_formula"),
  143. 'format': self.format_theader_yellow_amount_right,
  144. },
  145. 'width': 18,
  146. },
  147. 'full_reconcile': {
  148. 'header': {
  149. 'value': self._('Rec.'),
  150. 'format': self.format_theader_yellow_center,
  151. },
  152. 'lines': {
  153. 'value': self._render(
  154. "line.full_reconcile_id "
  155. "and line.full_reconcile_id.name"),
  156. 'format': self.format_tcell_center,
  157. },
  158. 'width': 12,
  159. },
  160. 'reconcile_amount': {
  161. 'header': {
  162. 'value': self._('Reconcile Amount'),
  163. },
  164. 'lines': {
  165. 'value': self._render(
  166. "line.full_reconcile_id and line.balance or "
  167. "(sum(line.matched_credit_ids.mapped('amount')) - "
  168. "sum(line.matched_debit_ids.mapped('amount')))"),
  169. 'format': self.format_tcell_amount_right,
  170. },
  171. 'width': 12,
  172. },
  173. 'matched_debit_ids': {
  174. 'header': {
  175. 'value': self._('Matched Debits'),
  176. },
  177. 'lines': {
  178. 'value': self._render(
  179. "line.matched_debit_ids "
  180. "and str([x.debit_move_id.id "
  181. "for x in line.matched_debit_ids])"),
  182. },
  183. 'width': 20,
  184. },
  185. 'matched_credit_ids': {
  186. 'header': {
  187. 'value': self._('Matched Credits'),
  188. },
  189. 'lines': {
  190. 'value': self._render(
  191. "line.matched_credit_ids "
  192. "and str([x.credit_move_id.id "
  193. "for x in line.matched_credit_ids])"),
  194. },
  195. 'width': 20,
  196. },
  197. 'amount_currency': {
  198. 'header': {
  199. 'value': self._('Am. Currency'),
  200. 'format': self.format_theader_yellow_right,
  201. },
  202. 'lines': {
  203. 'value': self._render("line.amount_currency"),
  204. 'format': self.format_tcell_amount_right,
  205. },
  206. 'width': 18,
  207. },
  208. 'currency_name': {
  209. 'header': {
  210. 'value': self._('Curr.'),
  211. 'format': self.format_theader_yellow_center,
  212. },
  213. 'lines': {
  214. 'value': self._render(
  215. "line.currency_id and line.currency_id.name"),
  216. 'format': self.format_tcell_center,
  217. },
  218. 'width': 6,
  219. },
  220. 'journal': {
  221. 'header': {
  222. 'value': self._('Journal'),
  223. },
  224. 'lines': {
  225. 'value': self._render("line.journal_id.code"),
  226. },
  227. 'width': 12,
  228. },
  229. 'company_currency': {
  230. 'header': {
  231. 'value': self._('Comp. Curr.'),
  232. 'format': self.format_theader_yellow_center,
  233. },
  234. 'lines': {
  235. 'value': self._render(
  236. "line.company_id.currency_id.name"),
  237. 'format': self.format_tcell_center,
  238. },
  239. 'width': 10,
  240. },
  241. 'analytic_account': {
  242. 'header': {
  243. 'value': self._('Analytic Account Reference'),
  244. },
  245. 'lines': {
  246. 'value': self._render(
  247. "line.analytic_account_id "
  248. "and line.analytic_account_id.code"),
  249. },
  250. 'width': 36,
  251. },
  252. 'analytic_account_name': {
  253. 'header': {
  254. 'value': self._('Analytic Account'),
  255. },
  256. 'lines': {
  257. 'value': self._render(
  258. "line.analytic_account_id "
  259. "and line.analytic_account_id.name"),
  260. },
  261. 'width': 36,
  262. },
  263. 'product': {
  264. 'header': {
  265. 'value': self._('Product'),
  266. },
  267. 'lines': {
  268. 'value': self._render(
  269. "line.product_id and line.product_id.name"),
  270. },
  271. 'width': 36,
  272. },
  273. 'product_ref': {
  274. 'header': {
  275. 'value': self._('Product Reference'),
  276. },
  277. 'lines': {
  278. 'value': self._render(
  279. "line.product_id and line.product_id.default_code "
  280. "or ''"),
  281. },
  282. 'width': 36,
  283. },
  284. 'product_uom': {
  285. 'header': {
  286. 'value': self._('Unit of Measure'),
  287. },
  288. 'lines': {
  289. 'value': self._render(
  290. "line.product_uom_id and line.product_uom_id.name"),
  291. },
  292. 'width': 20,
  293. },
  294. 'quantity': {
  295. 'header': {
  296. 'value': self._('Qty'),
  297. 'format': self.format_theader_yellow_right,
  298. },
  299. 'lines': {
  300. 'value': self._render("line.quantity"),
  301. 'format': self.format_tcell_amount_right,
  302. },
  303. 'width': 8,
  304. },
  305. 'statement': {
  306. 'header': {
  307. 'value': self._('Statement'),
  308. },
  309. 'lines': {
  310. 'value': self._render(
  311. "line.statement_id and line.statement_id.name"),
  312. },
  313. 'width': 20,
  314. },
  315. 'invoice': {
  316. 'header': {
  317. 'value': self._('Invoice'),
  318. },
  319. 'lines': {
  320. 'value': self._render(
  321. "line.invoice_id and line.invoice_id.number"),
  322. },
  323. 'width': 20,
  324. },
  325. 'amount_residual': {
  326. 'header': {
  327. 'value': self._('Residual Amount'),
  328. 'format': self.format_theader_yellow_right,
  329. },
  330. 'lines': {
  331. 'value': self._render("line.amount_residual"),
  332. 'format': self.format_tcell_amount_right,
  333. },
  334. 'width': 18,
  335. },
  336. 'amount_residual_currency': {
  337. 'header': {
  338. 'value': self._('Res. Am. in Curr.'),
  339. 'format': self.format_theader_yellow_right,
  340. },
  341. 'lines': {
  342. 'value': self._render("line.amount_residual_currency"),
  343. 'format': self.format_tcell_amount_right,
  344. },
  345. 'width': 18,
  346. },
  347. 'narration': {
  348. 'header': {
  349. 'value': self._('Notes'),
  350. },
  351. 'lines': {
  352. 'value': self._render("line.move_id.narration or ''"),
  353. },
  354. 'width': 42,
  355. },
  356. 'blocked': {
  357. 'header': {
  358. 'value': self._('Lit.'),
  359. 'format': self.format_theader_yellow_center,
  360. },
  361. 'lines': {
  362. 'value': self._render("line.blocked and 'x' or ''"),
  363. 'format': self.format_tcell_center,
  364. },
  365. 'width': 4,
  366. },
  367. 'id': {
  368. 'header': {
  369. 'value': self._('Id'),
  370. 'format': self.format_theader_yellow_right,
  371. },
  372. 'lines': {
  373. 'value': self._render("line.id"),
  374. 'format': self.format_tcell_integer_right,
  375. },
  376. 'width': 12,
  377. },
  378. }
  379. col_specs.update(self.env['account.move.line']._report_xlsx_template())
  380. wanted_list = self.env['account.move.line']._report_xlsx_fields()
  381. title = self._("Journal Items")
  382. return [{
  383. 'ws_name': title,
  384. 'generate_ws_method': '_amls_export',
  385. 'title': title,
  386. 'wanted_list': wanted_list,
  387. 'col_specs': col_specs,
  388. }]
  389. def _amls_export(self, workbook, ws, ws_params, data, amls):
  390. ws.set_landscape()
  391. ws.fit_to_pages(1, 0)
  392. ws.set_header(self.xls_headers['standard'])
  393. ws.set_footer(self.xls_footers['standard'])
  394. self._set_column_width(ws, ws_params)
  395. row_pos = 0
  396. row_pos = self._write_ws_title(ws, row_pos, ws_params)
  397. row_pos = self._write_line(
  398. ws, row_pos, ws_params, col_specs_section='header',
  399. default_format=self.format_theader_yellow_left)
  400. ws.freeze_panes(row_pos, 0)
  401. wanted_list = ws_params['wanted_list']
  402. debit_pos = 'debit' in wanted_list and wanted_list.index('debit')
  403. credit_pos = 'credit' in wanted_list and wanted_list.index('credit')
  404. for line in amls:
  405. row_pos = self._write_line(
  406. ws, row_pos, ws_params, col_specs_section='lines',
  407. render_space={'line': line},
  408. default_format=self.format_tcell_left)
  409. aml_cnt = len(amls)
  410. debit_start = self._rowcol_to_cell(row_pos - aml_cnt, debit_pos)
  411. debit_stop = self._rowcol_to_cell(row_pos - 1, debit_pos)
  412. debit_formula = 'SUM(%s:%s)' % (debit_start, debit_stop)
  413. credit_start = self._rowcol_to_cell(row_pos - aml_cnt, credit_pos)
  414. credit_stop = self._rowcol_to_cell(row_pos - 1, credit_pos)
  415. credit_formula = 'SUM(%s:%s)' % (credit_start, credit_stop)
  416. debit_cell = self._rowcol_to_cell(row_pos, debit_pos)
  417. credit_cell = self._rowcol_to_cell(row_pos, credit_pos)
  418. bal_formula = debit_cell + '-' + credit_cell
  419. row_pos = self._write_line(
  420. ws, row_pos, ws_params, col_specs_section='totals',
  421. render_space={
  422. 'debit_formula': debit_formula,
  423. 'credit_formula': credit_formula,
  424. 'bal_formula': bal_formula,
  425. },
  426. default_format=self.format_theader_yellow_left)
  427. MoveLineXlsx('report.move.line.list.xls',
  428. 'account.move.line',
  429. parser=report_sxw.rml_parse)