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.

378 lines
13 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2019 ACSONE SA/NV
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. import mock
  5. from contextlib import contextmanager
  6. import odoo.tests.common as common
  7. class TestOnchangeHelper(common.TransactionCase):
  8. def setUp(self):
  9. super(TestOnchangeHelper, self).setUp()
  10. self.Category = self.env["test_onchange_helper.category"]
  11. self.Message = self.env["test_onchange_helper.message"]
  12. self.Discussion = self.env["test_onchange_helper.discussion"]
  13. @contextmanager
  14. def assertNoOrmWrite(self, model):
  15. with mock.patch.object(
  16. model.__class__, "create"
  17. ) as mocked_create, mock.patch.object(
  18. model.__class__, "write"
  19. ) as mocked_write:
  20. yield
  21. mocked_create.assert_not_called()
  22. mocked_write.assert_not_called()
  23. def test_play_onhanges_no_recompute(self):
  24. # play_onchanges must not trigger recomputes except if an onchange
  25. # method access a computed field.
  26. # changing 'discussion' should recompute 'name'
  27. values = {"name": "Cat Name"}
  28. self.env.invalidate_all()
  29. with self.assertNoOrmWrite(self.Category):
  30. result = self.Category.play_onchanges(values, ["name"])
  31. self.assertNotIn("computed_display_name", result)
  32. def test_play_onchanges_many2one_new_record(self):
  33. root = self.Category.create({"name": "root"})
  34. values = {"name": "test", "parent": root.id, "root_categ": False}
  35. self.env.invalidate_all()
  36. with self.assertNoOrmWrite(self.Category):
  37. result = self.Category.play_onchanges(values, "parent")
  38. self.assertIn("root_categ", result)
  39. self.assertEqual(result["root_categ"], root.id)
  40. values.update(result)
  41. values["parent"] = False
  42. self.env.invalidate_all()
  43. with self.assertNoOrmWrite(self.Category):
  44. result = self.Category.play_onchanges(values, "parent")
  45. # since the root_categ is already False into values the field is not
  46. # changed by the onchange
  47. self.assertNotIn("root_categ", result)
  48. def test_play_onchanges_many2one_existing_record(self):
  49. root = self.Category.create({"name": "root"})
  50. values = {"name": "test", "parent": root.id, "root_categ": False}
  51. self.env.invalidate_all()
  52. with self.assertNoOrmWrite(self.Category):
  53. result = self.Category.play_onchanges(values, "parent")
  54. self.assertIn("root_categ", result)
  55. self.assertEqual(result["root_categ"], root.id)
  56. # create child catefory
  57. values.update(result)
  58. child = self.Category.create(values)
  59. self.assertEqual(root.id, child.root_categ.id)
  60. # since the parent is set to False and the root_categ
  61. values = {"parent": False}
  62. self.env.invalidate_all()
  63. with self.assertNoOrmWrite(child):
  64. result = child.play_onchanges(values, "parent")
  65. self.assertIn("root_categ", result)
  66. self.assertEqual(result["root_categ"], False)
  67. def test_play_onchange_one2many_new_record(self):
  68. """ test the effect of play_onchanges() on one2many fields on new
  69. record"""
  70. BODY = "What a beautiful day!"
  71. USER = self.env.user
  72. # create an independent message
  73. message = self.Message.create({"body": BODY})
  74. # modify discussion name
  75. values = {
  76. "name": "Foo",
  77. "categories": [],
  78. "moderator": False,
  79. "participants": [],
  80. "messages": [
  81. (4, message.id),
  82. (
  83. 0,
  84. 0,
  85. {
  86. "name": "[%s] %s" % ("", USER.name),
  87. "body": BODY,
  88. "author": USER.id,
  89. "important": False,
  90. },
  91. ),
  92. ],
  93. }
  94. self.env.invalidate_all()
  95. with self.assertNoOrmWrite(self.Discussion):
  96. result = self.Discussion.play_onchanges(values, "name")
  97. self.assertIn("messages", result)
  98. self.assertItemsEqual(
  99. result["messages"],
  100. [
  101. (5,),
  102. (
  103. 1,
  104. message.id,
  105. {
  106. "name": "[%s] %s" % ("Foo", USER.name),
  107. "body": "not last dummy message",
  108. "author": message.author.id,
  109. "important": message.important,
  110. },
  111. ),
  112. (
  113. 0,
  114. 0,
  115. {
  116. "name": "[%s] %s" % ("Foo", USER.name),
  117. "body": "not last dummy message",
  118. "author": USER.id,
  119. "important": False,
  120. },
  121. ),
  122. (
  123. 0,
  124. 0,
  125. {
  126. "name": "[%s] %s" % ("Foo", USER.name),
  127. "body": "dummy message",
  128. "author": USER.id,
  129. "important": True,
  130. },
  131. ),
  132. ],
  133. )
  134. self.assertIn("important_messages", result)
  135. self.assertItemsEqual(
  136. result["important_messages"],
  137. [
  138. (5,),
  139. (
  140. 0,
  141. 0,
  142. {
  143. "author": USER.id,
  144. "body": "dummy message",
  145. "important": True,
  146. },
  147. ),
  148. ],
  149. )
  150. def test_play_onchange_one2many_existing_record(self):
  151. """ test the effect of play_onchanges() on one2many fields on existing
  152. record"""
  153. BODY = "What a beautiful day!"
  154. USER = self.env.user
  155. # create an independent message
  156. message = self.Message.create({"body": BODY})
  157. # modify discussion name
  158. values = {
  159. "name": "Foo",
  160. "categories": [],
  161. "moderator": False,
  162. "participants": [],
  163. "messages": [
  164. (4, message.id),
  165. (
  166. 0,
  167. 0,
  168. {
  169. "name": "[%s] %s" % ("", USER.name),
  170. "body": BODY,
  171. "author": USER.id,
  172. "important": False,
  173. },
  174. ),
  175. ],
  176. }
  177. discussion = self.Discussion.create(values)
  178. values = {"name": "New foo"}
  179. with self.assertNoOrmWrite(discussion):
  180. result = discussion.play_onchanges(values, "name")
  181. self.assertIn("messages", result)
  182. self.assertItemsEqual(
  183. result["messages"],
  184. [
  185. (5,),
  186. (
  187. 1,
  188. discussion.messages[0].id,
  189. {
  190. "name": "[%s] %s" % ("New foo", USER.name),
  191. "body": "not last dummy message",
  192. "author": message.author.id,
  193. "important": message.important,
  194. "discussion": discussion.id,
  195. },
  196. ),
  197. (
  198. 1,
  199. discussion.messages[1].id,
  200. {
  201. "name": "[%s] %s" % ("New foo", USER.name),
  202. "body": "not last dummy message",
  203. "author": USER.id,
  204. "important": False,
  205. "discussion": discussion.id,
  206. },
  207. ),
  208. (
  209. 0,
  210. 0,
  211. {
  212. "name": "[%s] %s" % ("New foo", USER.name),
  213. "body": "dummy message",
  214. "author": USER.id,
  215. "important": True,
  216. "discussion": discussion.id,
  217. },
  218. ),
  219. ],
  220. )
  221. self.assertIn("important_messages", result)
  222. self.assertItemsEqual(
  223. result["important_messages"],
  224. [
  225. (5,),
  226. (
  227. 0,
  228. 0,
  229. {
  230. "author": USER.id,
  231. "body": "dummy message",
  232. "important": True,
  233. "discussion": discussion.id,
  234. },
  235. ),
  236. ],
  237. )
  238. def test_onchange_specific(self):
  239. """test that only the id is added if a new item is added to an
  240. existing relation"""
  241. discussion = self.env.ref("test_onchange_helper.discussion_demo_0")
  242. demo = self.env.ref("base.user_demo")
  243. # first remove demo user from participants
  244. discussion.participants -= demo
  245. self.assertNotIn(demo, discussion.participants)
  246. # check that demo_user is added to participants when set as moderator
  247. values = {
  248. "name": discussion.name,
  249. "moderator": demo.id,
  250. "categories": [(4, cat.id) for cat in discussion.categories],
  251. "messages": [(4, msg.id) for msg in discussion.messages],
  252. "participants": [(4, usr.id) for usr in discussion.participants],
  253. }
  254. self.env.invalidate_all()
  255. with self.assertNoOrmWrite(discussion):
  256. result = discussion.play_onchanges(values, "moderator")
  257. self.assertIn("participants", result)
  258. self.assertItemsEqual(
  259. result["participants"],
  260. [(5,)] + [(4, user.id) for user in discussion.participants + demo],
  261. )
  262. def test_onchange_one2many_value(self):
  263. """ test that the values provided for a one2many field inside are used
  264. by the play_onchanges """
  265. discussion = self.env.ref("test_onchange_helper.discussion_demo_0")
  266. demo = self.env.ref("base.user_demo")
  267. self.assertEqual(len(discussion.messages), 3)
  268. messages = [(4, msg.id) for msg in discussion.messages]
  269. messages[0] = (1, messages[0][1], {"body": "test onchange"})
  270. values = {
  271. "name": discussion.name,
  272. "moderator": demo.id,
  273. "categories": [(4, cat.id) for cat in discussion.categories],
  274. "messages": messages,
  275. "participants": [(4, usr.id) for usr in discussion.participants],
  276. "message_concat": False,
  277. }
  278. with self.assertNoOrmWrite(discussion):
  279. result = discussion.play_onchanges(values, "messages")
  280. self.assertIn("message_concat", result)
  281. self.assertEqual(
  282. result["message_concat"],
  283. "\n".join(
  284. ["%s:%s" % (m.name, m.body) for m in discussion.messages]
  285. ),
  286. )
  287. def test_onchange_one2many_line(self):
  288. """ test that changes on a field used as first position into the
  289. related path of a related field will trigger the onchange also on the
  290. related field """
  291. partner = self.env.ref("base.res_partner_1")
  292. multi = self.env["test_onchange_helper.multi"].create(
  293. {"partner": partner.id}
  294. )
  295. line = multi.lines.create({"multi": multi.id})
  296. values = multi._convert_to_write(
  297. {key: multi[key] for key in ("partner", "lines")}
  298. )
  299. self.assertEqual(
  300. values, {"partner": partner.id, "lines": [(6, 0, [line.id])]}
  301. )
  302. # modify 'partner'
  303. # -> set 'partner' on all lines
  304. # -> recompute 'name' (related on partner)
  305. # -> set 'name' on all lines
  306. partner = self.env.ref("base.res_partner_2")
  307. values = {
  308. "partner": partner.id,
  309. "lines": [
  310. (6, 0, [line.id]),
  311. (0, 0, {"name": False, "partner": False}),
  312. ],
  313. }
  314. self.env.invalidate_all()
  315. with self.assertNoOrmWrite(multi):
  316. result = multi.play_onchanges(values, "partner")
  317. self.assertEqual(
  318. result,
  319. {
  320. "name": partner.name,
  321. "lines": [
  322. (5,),
  323. (
  324. 1,
  325. line.id,
  326. {
  327. "name": partner.name,
  328. "partner": partner.id,
  329. "multi": multi.id,
  330. },
  331. ),
  332. (
  333. 0,
  334. 0,
  335. {
  336. "name": partner.name,
  337. "partner": partner.id,
  338. "multi": multi.id,
  339. },
  340. ),
  341. ],
  342. },
  343. )