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.

401 lines
14 KiB

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