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.

444 lines
15 KiB

  1. # Author: Julien Coux
  2. # Copyright 2016 Camptocamp SA
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. import logging
  5. from odoo.tests import common
  6. from odoo.tools import test_reports
  7. _logger = logging.getLogger(__name__)
  8. class AbstractTest(common.TransactionCase):
  9. """Common technical tests for all reports."""
  10. at_install = False
  11. post_install = True
  12. accounts = {}
  13. def with_context(self, *args, **kwargs):
  14. context = dict(args[0] if args else self.env.context, **kwargs)
  15. self.env = self.env(context=context)
  16. return self
  17. def _chart_template_create(self):
  18. transfer_account_id = self.env["account.account.template"].create(
  19. {
  20. "code": "000",
  21. "name": "Liquidity Transfers",
  22. "reconcile": True,
  23. "user_type_id": self.ref("account.data_account_type_current_assets"),
  24. }
  25. )
  26. self.chart = self.env["account.chart.template"].create(
  27. {
  28. "name": "Test COA",
  29. "code_digits": 4,
  30. "bank_account_code_prefix": 1014,
  31. "cash_account_code_prefix": 1014,
  32. "currency_id": self.ref("base.USD"),
  33. "transfer_account_code_prefix": "000",
  34. }
  35. )
  36. transfer_account_id.update(
  37. {"chart_template_id": self.chart.id,}
  38. )
  39. self.env["ir.model.data"].create(
  40. {
  41. "res_id": transfer_account_id.id,
  42. "model": transfer_account_id._name,
  43. "name": "Liquidity Transfers",
  44. }
  45. )
  46. act = self.env["account.account.template"].create(
  47. {
  48. "code": "001",
  49. "name": "Expenses",
  50. "user_type_id": self.ref("account.data_account_type_expenses"),
  51. "chart_template_id": self.chart.id,
  52. "reconcile": True,
  53. }
  54. )
  55. self.env["ir.model.data"].create(
  56. {"res_id": act.id, "model": act._name, "name": "expenses",}
  57. )
  58. act = self.env["account.account.template"].create(
  59. {
  60. "code": "002",
  61. "name": "Product Sales",
  62. "user_type_id": self.ref("account.data_account_type_revenue"),
  63. "chart_template_id": self.chart.id,
  64. "reconcile": True,
  65. }
  66. )
  67. self.env["ir.model.data"].create(
  68. {"res_id": act.id, "model": act._name, "name": "sales",}
  69. )
  70. act = self.env["account.account.template"].create(
  71. {
  72. "code": "003",
  73. "name": "Account Receivable",
  74. "user_type_id": self.ref("account.data_account_type_receivable"),
  75. "chart_template_id": self.chart.id,
  76. "reconcile": True,
  77. }
  78. )
  79. self.env["ir.model.data"].create(
  80. {"res_id": act.id, "model": act._name, "name": "receivable",}
  81. )
  82. act = self.env["account.account.template"].create(
  83. {
  84. "code": "004",
  85. "name": "Account Payable",
  86. "user_type_id": self.ref("account.data_account_type_payable"),
  87. "chart_template_id": self.chart.id,
  88. "reconcile": True,
  89. }
  90. )
  91. self.env["ir.model.data"].create(
  92. {"res_id": act.id, "model": act._name, "name": "payable",}
  93. )
  94. def _add_chart_of_accounts(self):
  95. self.company = self.env["res.company"].create({"name": "Spanish test company",})
  96. self.env.ref("base.group_multi_company").write(
  97. {"users": [(4, self.env.uid)],}
  98. )
  99. self.env.user.write(
  100. {"company_ids": [(4, self.company.id)], "company_id": self.company.id,}
  101. )
  102. self.with_context(company_id=self.company.id, force_company=self.company.id)
  103. self.chart.try_loading_for_current_company()
  104. self.revenue = self.env["account.account"].search(
  105. [("user_type_id", "=", self.ref("account.data_account_type_revenue"))],
  106. limit=1,
  107. )
  108. self.expense = self.env["account.account"].search(
  109. [("user_type_id", "=", self.ref("account.data_account_type_expenses"))],
  110. limit=1,
  111. )
  112. self.receivable = self.env["account.account"].search(
  113. [("user_type_id", "=", self.ref("account.data_account_type_receivable"))],
  114. limit=1,
  115. )
  116. self.payable = self.env["account.account"].search(
  117. [("user_type_id", "=", self.ref("account.data_account_type_payable"))],
  118. limit=1,
  119. )
  120. return True
  121. def _journals_create(self):
  122. self.journal_sale = self.env["account.journal"].create(
  123. {
  124. "company_id": self.company.id,
  125. "name": "Test journal for sale",
  126. "type": "sale",
  127. "code": "TSALE",
  128. "default_debit_account_id": self.revenue.id,
  129. "default_credit_account_id": self.revenue.id,
  130. }
  131. )
  132. self.journal_purchase = self.env["account.journal"].create(
  133. {
  134. "company_id": self.company.id,
  135. "name": "Test journal for purchase",
  136. "type": "purchase",
  137. "code": "TPUR",
  138. "default_debit_account_id": self.expense.id,
  139. "default_credit_account_id": self.expense.id,
  140. }
  141. )
  142. return True
  143. def _invoice_create(self):
  144. self.partner = self.env["res.partner"].create(
  145. {
  146. "name": "Test partner",
  147. "company_id": self.company.id,
  148. "property_account_receivable_id": self.receivable.id,
  149. "property_account_payable_id": self.payable.id,
  150. }
  151. )
  152. # customer invoice
  153. customer_invoice_lines = [
  154. (
  155. 0,
  156. False,
  157. {
  158. "name": "Test description #1",
  159. "account_id": self.revenue.id,
  160. "quantity": 1.0,
  161. "price_unit": 100.0,
  162. },
  163. ),
  164. (
  165. 0,
  166. False,
  167. {
  168. "name": "Test description #2",
  169. "account_id": self.revenue.id,
  170. "quantity": 2.0,
  171. "price_unit": 25.0,
  172. },
  173. ),
  174. ]
  175. self.invoice_out = self.env["account.invoice"].create(
  176. {
  177. "partner_id": self.partner.id,
  178. "type": "out_invoice",
  179. "invoice_line_ids": customer_invoice_lines,
  180. "account_id": self.partner.property_account_receivable_id.id,
  181. "journal_id": self.journal_sale.id,
  182. }
  183. )
  184. self.invoice_out.action_invoice_open()
  185. # vendor bill
  186. vendor_invoice_lines = [
  187. (
  188. 0,
  189. False,
  190. {
  191. "name": "Test description #1",
  192. "account_id": self.revenue.id,
  193. "quantity": 1.0,
  194. "price_unit": 100.0,
  195. },
  196. ),
  197. (
  198. 0,
  199. False,
  200. {
  201. "name": "Test description #2",
  202. "account_id": self.revenue.id,
  203. "quantity": 2.0,
  204. "price_unit": 25.0,
  205. },
  206. ),
  207. ]
  208. self.invoice_in = self.env["account.invoice"].create(
  209. {
  210. "partner_id": self.partner.id,
  211. "type": "in_invoice",
  212. "invoice_line_ids": vendor_invoice_lines,
  213. "account_id": self.partner.property_account_payable_id.id,
  214. "journal_id": self.journal_purchase.id,
  215. }
  216. )
  217. self.invoice_in.action_invoice_open()
  218. def setUp(self):
  219. super(AbstractTest, self).setUp()
  220. self.with_context()
  221. self._chart_template_create()
  222. self._add_chart_of_accounts()
  223. self._journals_create()
  224. self._invoice_create()
  225. self.model = self._getReportModel()
  226. self.qweb_report_name = self._getQwebReportName()
  227. self.xlsx_report_name = self._getXlsxReportName()
  228. self.xlsx_action_name = self._getXlsxReportActionName()
  229. self.report_title = self._getReportTitle()
  230. self.base_filters = self._getBaseFilters()
  231. self.additional_filters = self._getAdditionalFiltersToBeTested()
  232. self.report = self.model.create(self.base_filters)
  233. self.report.compute_data_for_report()
  234. def test_html(self):
  235. test_reports.try_report(
  236. self.env.cr,
  237. self.env.uid,
  238. self.qweb_report_name,
  239. [self.report.id],
  240. report_type="qweb-html",
  241. )
  242. def test_qweb(self):
  243. test_reports.try_report(
  244. self.env.cr,
  245. self.env.uid,
  246. self.qweb_report_name,
  247. [self.report.id],
  248. report_type="qweb-pdf",
  249. )
  250. def test_xlsx(self):
  251. test_reports.try_report(
  252. self.env.cr,
  253. self.env.uid,
  254. self.xlsx_report_name,
  255. [self.report.id],
  256. report_type="xlsx",
  257. )
  258. def test_print(self):
  259. self.report.print_report("qweb")
  260. self.report.print_report("xlsx")
  261. def test_02_generation_report_html(self):
  262. """Check if report HTML is correctly generated"""
  263. # Check if returned report action is correct
  264. report_type = "qweb-html"
  265. report_action = self.report.print_report(report_type)
  266. self.assertDictContainsSubset(
  267. {
  268. "type": "ir.actions.report",
  269. "report_name": self.qweb_report_name,
  270. "report_type": "qweb-html",
  271. },
  272. report_action,
  273. )
  274. # Check if report template is correct
  275. report = self.env["ir.actions.report"].search(
  276. [
  277. ("report_name", "=", self.qweb_report_name),
  278. ("report_type", "=", report_type),
  279. ],
  280. limit=1,
  281. )
  282. self.assertEqual(report.report_type, "qweb-html")
  283. rep = report.render(self.report.ids, {})
  284. self.assertTrue(self.report_title.encode("utf8") in rep[0])
  285. self.assertTrue(self.report.account_ids[0].name.encode("utf8") in rep[0])
  286. def test_04_compute_data(self):
  287. """Check that the SQL queries work with all filters options"""
  288. for filters in [{}] + self.additional_filters:
  289. current_filter = self.base_filters.copy()
  290. current_filter.update(filters)
  291. report = self.model.create(current_filter)
  292. report.compute_data_for_report()
  293. self.assertGreaterEqual(len(report.account_ids), 1)
  294. # Same filters with only one account
  295. current_filter = self.base_filters.copy()
  296. current_filter.update(filters)
  297. report_accounts = report.account_ids.filtered("account_id")
  298. current_filter.update(
  299. {"filter_account_ids": [(6, 0, report_accounts[0].account_id.ids)],}
  300. )
  301. report2 = self.model.create(current_filter)
  302. report2.compute_data_for_report()
  303. self.assertEqual(len(report2.account_ids), 1)
  304. self.assertEqual(report2.account_ids.name, report_accounts[0].name)
  305. if self._partner_test_is_possible(filters):
  306. # Same filters with only one partner
  307. report_partner_ids = report.account_ids.mapped("partner_ids")
  308. partner_ids = report_partner_ids.mapped("partner_id")
  309. current_filter = self.base_filters.copy()
  310. current_filter.update(filters)
  311. current_filter.update(
  312. {"filter_partner_ids": [(6, 0, partner_ids[0].ids)],}
  313. )
  314. report3 = self.model.create(current_filter)
  315. report3.compute_data_for_report()
  316. self.assertGreaterEqual(len(report3.account_ids), 1)
  317. report_partner_ids3 = report3.account_ids.mapped("partner_ids")
  318. partner_ids3 = report_partner_ids3.mapped("partner_id")
  319. self.assertEqual(len(partner_ids3), 1)
  320. self.assertEqual(partner_ids3.name, partner_ids[0].name)
  321. # Same filters with only one partner and one account
  322. report_partner_ids = report3.account_ids.mapped("partner_ids")
  323. report_account_id = report_partner_ids.filtered(lambda p: p.partner_id)[
  324. 0
  325. ].report_account_id
  326. current_filter = self.base_filters.copy()
  327. current_filter.update(filters)
  328. current_filter.update(
  329. {
  330. "filter_account_ids": [
  331. (6, 0, report_account_id.account_id.ids)
  332. ],
  333. "filter_partner_ids": [(6, 0, partner_ids[0].ids)],
  334. }
  335. )
  336. report4 = self.model.create(current_filter)
  337. report4.compute_data_for_report()
  338. self.assertEqual(len(report4.account_ids), 1)
  339. self.assertEqual(
  340. report4.account_ids.name, report_account_id.account_id.name
  341. )
  342. report_partner_ids4 = report4.account_ids.mapped("partner_ids")
  343. partner_ids4 = report_partner_ids4.mapped("partner_id")
  344. self.assertEqual(len(partner_ids4), 1)
  345. self.assertEqual(partner_ids4.name, partner_ids[0].name)
  346. def _partner_test_is_possible(self, filters):
  347. """
  348. :return:
  349. a boolean to indicate if partner test is possible
  350. with current filters
  351. """
  352. return True
  353. def _getReportModel(self):
  354. """
  355. :return: the report model name
  356. """
  357. raise NotImplementedError()
  358. def _getQwebReportName(self):
  359. """
  360. :return: the qweb report name
  361. """
  362. raise NotImplementedError()
  363. def _getXlsxReportName(self):
  364. """
  365. :return: the xlsx report name
  366. """
  367. raise NotImplementedError()
  368. def _getXlsxReportActionName(self):
  369. """
  370. :return: the xlsx report action name
  371. """
  372. raise NotImplementedError()
  373. def _getReportTitle(self):
  374. """
  375. :return: the report title displayed into the report
  376. """
  377. raise NotImplementedError()
  378. def _getBaseFilters(self):
  379. """
  380. :return: the minimum required filters to generate report
  381. """
  382. raise NotImplementedError()
  383. def _getAdditionalFiltersToBeTested(self):
  384. """
  385. :return: the additional filters to generate report variants
  386. """
  387. raise NotImplementedError()