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.

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