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.

377 lines
16 KiB

  1. # Copyright 2016-2017 Therp BV
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  3. from datetime import datetime, date, timedelta
  4. from dateutil.relativedelta import relativedelta
  5. from odoo import fields
  6. from odoo.exceptions import ValidationError
  7. from .test_partner_relation_common import TestPartnerRelationCommon
  8. class TestPartnerRelation(TestPartnerRelationCommon):
  9. post_install = True
  10. def test_selection_name_search(self):
  11. """Test wether we can find type selection on reverse name."""
  12. selection_types = self.selection_model.name_search(
  13. name=self.selection_person2company.name)
  14. self.assertTrue(selection_types)
  15. self.assertTrue(
  16. (self.selection_person2company.id,
  17. self.selection_person2company.name) in selection_types)
  18. def test_self_allowed(self):
  19. """Test creation of relation to same partner when type allows."""
  20. type_allow = self.type_model.create({
  21. 'name': 'allow',
  22. 'name_inverse': 'allow_inverse',
  23. 'contact_type_left': 'p',
  24. 'contact_type_right': 'p',
  25. 'allow_self': True})
  26. self.assertTrue(type_allow)
  27. reflexive_relation = self.relation_model.create({
  28. 'type_id': type_allow.id,
  29. 'left_partner_id': self.partner_01_person.id,
  30. 'right_partner_id': self.partner_01_person.id})
  31. self.assertTrue(reflexive_relation)
  32. def test_self_disallowed(self):
  33. """Test creating relation to same partner when disallowed.
  34. Attempt to create a relation of a partner to the same partner should
  35. raise an error when the type of relation explicitly disallows this.
  36. """
  37. type_disallow = self.type_model.create({
  38. 'name': 'disallow',
  39. 'name_inverse': 'disallow_inverse',
  40. 'contact_type_left': 'p',
  41. 'contact_type_right': 'p',
  42. 'allow_self': False})
  43. self.assertTrue(type_disallow)
  44. with self.assertRaises(ValidationError):
  45. self.relation_model.create({
  46. 'type_id': type_disallow.id,
  47. 'left_partner_id': self.partner_01_person.id,
  48. 'right_partner_id': self.partner_01_person.id})
  49. def test_self_disallowed_after_self_relation_created(self):
  50. """Test that allow_self can not be true if a reflexive relation already exists.
  51. If at least one reflexive relation exists for the given type,
  52. reflexivity can not be disallowed.
  53. """
  54. type_allow = self.type_model.create({
  55. 'name': 'allow',
  56. 'name_inverse': 'allow_inverse',
  57. 'contact_type_left': 'p',
  58. 'contact_type_right': 'p',
  59. 'allow_self': True})
  60. self.assertTrue(type_allow)
  61. reflexive_relation = self.relation_model.create({
  62. 'type_id': type_allow.id,
  63. 'left_partner_id': self.partner_01_person.id,
  64. 'right_partner_id': self.partner_01_person.id})
  65. self.assertTrue(reflexive_relation)
  66. with self.assertRaises(ValidationError):
  67. type_allow.allow_self = False
  68. def test_self_disallowed_with_delete_invalid_relations(self):
  69. """Test handle_invalid_onchange delete with allow_self disabled.
  70. When deactivating allow_self, if handle_invalid_onchange is set
  71. to delete, then existing reflexive relations are deleted.
  72. Non reflexive relations are not modified.
  73. """
  74. type_allow = self.type_model.create({
  75. 'name': 'allow',
  76. 'name_inverse': 'allow_inverse',
  77. 'contact_type_left': 'p',
  78. 'contact_type_right': 'p',
  79. 'allow_self': True,
  80. 'handle_invalid_onchange': 'delete',
  81. })
  82. reflexive_relation = self.relation_model.create({
  83. 'type_id': type_allow.id,
  84. 'left_partner_id': self.partner_01_person.id,
  85. 'right_partner_id': self.partner_01_person.id,
  86. })
  87. normal_relation = self.relation_model.create({
  88. 'type_id': type_allow.id,
  89. 'left_partner_id': self.partner_01_person.id,
  90. 'right_partner_id': self.partner_04_volunteer.id,
  91. })
  92. type_allow.allow_self = False
  93. self.assertFalse(reflexive_relation.exists())
  94. self.assertTrue(normal_relation.exists())
  95. def test_self_disallowed_with_end_invalid_relations(self):
  96. """Test handle_invalid_onchange delete with allow_self disabled.
  97. When deactivating allow_self, if handle_invalid_onchange is set
  98. to end, then active reflexive relations are ended.
  99. Non reflexive relations are not modified.
  100. Reflexive relations with an end date prior to the current date
  101. are not modified.
  102. """
  103. type_allow = self.type_model.create({
  104. 'name': 'allow',
  105. 'name_inverse': 'allow_inverse',
  106. 'contact_type_left': 'p',
  107. 'contact_type_right': 'p',
  108. 'allow_self': True,
  109. 'handle_invalid_onchange': 'end',
  110. })
  111. reflexive_relation = self.relation_model.create({
  112. 'type_id': type_allow.id,
  113. 'left_partner_id': self.partner_01_person.id,
  114. 'right_partner_id': self.partner_01_person.id,
  115. 'date_start': '2000-01-02',
  116. })
  117. past_reflexive_relation = self.relation_model.create({
  118. 'type_id': type_allow.id,
  119. 'left_partner_id': self.partner_01_person.id,
  120. 'right_partner_id': self.partner_01_person.id,
  121. 'date_end': '2000-01-01',
  122. })
  123. normal_relation = self.relation_model.create({
  124. 'type_id': type_allow.id,
  125. 'left_partner_id': self.partner_01_person.id,
  126. 'right_partner_id': self.partner_04_volunteer.id,
  127. })
  128. type_allow.allow_self = False
  129. self.assertEqual(reflexive_relation.date_end, fields.Date.today())
  130. self.assertEqual(past_reflexive_relation.date_end, date(2000, 1, 1))
  131. self.assertFalse(normal_relation.date_end)
  132. def test_self_disallowed_with_future_reflexive_relation(self):
  133. """Test future reflexive relations are deleted.
  134. If handle_invalid_onchange is set to end, then deactivating
  135. reflexivity will delete invalid relations in the future.
  136. """
  137. type_allow = self.type_model.create({
  138. 'name': 'allow',
  139. 'name_inverse': 'allow_inverse',
  140. 'contact_type_left': 'p',
  141. 'contact_type_right': 'p',
  142. 'allow_self': True,
  143. 'handle_invalid_onchange': 'end',
  144. })
  145. future_reflexive_relation = self.relation_model.create({
  146. 'type_id': type_allow.id,
  147. 'left_partner_id': self.partner_01_person.id,
  148. 'right_partner_id': self.partner_01_person.id,
  149. 'date_start': datetime.now() + timedelta(1),
  150. })
  151. type_allow.allow_self = False
  152. self.assertFalse(future_reflexive_relation.exists())
  153. def test_self_default(self):
  154. """Test default not to allow relation with same partner.
  155. Attempt to create a relation of a partner to the same partner
  156. raise an error when the type of relation does not explicitly allow
  157. this.
  158. """
  159. type_default = self.type_model.create({
  160. 'name': 'default',
  161. 'name_inverse': 'default_inverse',
  162. 'contact_type_left': 'p',
  163. 'contact_type_right': 'p'})
  164. self.assertTrue(type_default)
  165. with self.assertRaises(ValidationError):
  166. self.relation_model.create({
  167. 'type_id': type_default.id,
  168. 'left_partner_id': self.partner_01_person.id,
  169. 'right_partner_id': self.partner_01_person.id})
  170. def test_self_mixed(self):
  171. """Test creation of relation with wrong types.
  172. Trying to create a relation between partners with an inappropiate
  173. type should raise an error.
  174. """
  175. with self.assertRaises(ValidationError):
  176. self.relation_model.create({
  177. 'type_id': self.type_company2person.id,
  178. 'left_partner_id': self.partner_01_person.id,
  179. 'right_partner_id': self.partner_02_company.id})
  180. def test_symmetric(self):
  181. """Test creating symmetric relation."""
  182. # Start out with non symmetric relation:
  183. type_symmetric = self.type_model.create({
  184. 'name': 'not yet symmetric',
  185. 'name_inverse': 'the other side of not symmetric',
  186. 'is_symmetric': False,
  187. 'contact_type_left': False,
  188. 'contact_type_right': 'p'})
  189. # not yet symmetric relation should result in two records in
  190. # selection:
  191. selection_symmetric = self.selection_model.search([
  192. ('type_id', '=', type_symmetric.id)])
  193. self.assertEqual(len(selection_symmetric), 2)
  194. # Now change to symmetric and test name and inverse name:
  195. with self.env.do_in_draft():
  196. type_symmetric.write({
  197. 'name': 'sym',
  198. 'is_symmetric': True})
  199. self.assertEqual(type_symmetric.is_symmetric, True)
  200. self.assertEqual(
  201. type_symmetric.name_inverse,
  202. type_symmetric.name)
  203. self.assertEqual(
  204. type_symmetric.contact_type_right,
  205. type_symmetric.contact_type_left)
  206. # now update the database:
  207. type_symmetric.write({
  208. 'name': type_symmetric.name,
  209. 'is_symmetric': type_symmetric.is_symmetric,
  210. 'name_inverse': type_symmetric.name_inverse,
  211. 'contact_type_right': type_symmetric.contact_type_right})
  212. # symmetric relation should result in only one record in
  213. # selection:
  214. selection_symmetric = self.selection_model.search([
  215. ('type_id', '=', type_symmetric.id)])
  216. self.assertEqual(len(selection_symmetric), 1)
  217. relation = self.relation_all_model.create({
  218. 'type_selection_id': selection_symmetric.id,
  219. 'this_partner_id': self.partner_02_company.id,
  220. 'other_partner_id': self.partner_01_person.id})
  221. partners = self.partner_model.search([
  222. ('search_relation_type_id', '=', relation.type_selection_id.id)])
  223. self.assertTrue(self.partner_01_person in partners)
  224. self.assertTrue(self.partner_02_company in partners)
  225. def test_category_domain(self):
  226. """Test check on category in relations."""
  227. # Check on left side:
  228. with self.assertRaises(ValidationError):
  229. self.relation_model.create({
  230. 'type_id': self.type_ngo2volunteer.id,
  231. 'left_partner_id': self.partner_02_company.id,
  232. 'right_partner_id': self.partner_04_volunteer.id})
  233. # Check on right side:
  234. with self.assertRaises(ValidationError):
  235. self.relation_model.create({
  236. 'type_id': self.type_ngo2volunteer.id,
  237. 'left_partner_id': self.partner_03_ngo.id,
  238. 'right_partner_id': self.partner_01_person.id})
  239. def test_relation_type_change(self):
  240. """Test change in relation type conditions."""
  241. # First create a relation type having no particular conditions.
  242. (type_school2student,
  243. school2student,
  244. school2student_inverse) = \
  245. self._create_relation_type_selection({
  246. 'name': 'school has student',
  247. 'name_inverse': 'studies at school'})
  248. # Second create relations based on those conditions.
  249. partner_school = self.partner_model.create({
  250. 'name': 'Test School',
  251. 'is_company': True,
  252. 'ref': 'TS'})
  253. partner_bart = self.partner_model.create({
  254. 'name': 'Bart Simpson',
  255. 'is_company': False,
  256. 'ref': 'BS'})
  257. partner_lisa = self.partner_model.create({
  258. 'name': 'Lisa Simpson',
  259. 'is_company': False,
  260. 'ref': 'LS'})
  261. relation_school2bart = self.relation_all_model.create({
  262. 'this_partner_id': partner_school.id,
  263. 'type_selection_id': school2student.id,
  264. 'other_partner_id': partner_bart.id})
  265. self.assertTrue(relation_school2bart)
  266. relation_school2lisa = self.relation_all_model.create({
  267. 'this_partner_id': partner_school.id,
  268. 'type_selection_id': school2student.id,
  269. 'other_partner_id': partner_lisa.id})
  270. self.assertTrue(relation_school2lisa)
  271. relation_bart2lisa = self.relation_all_model.create({
  272. 'this_partner_id': partner_bart.id,
  273. 'type_selection_id': school2student.id,
  274. 'other_partner_id': partner_lisa.id})
  275. self.assertTrue(relation_bart2lisa)
  276. # Third creata a category and make it a condition for the
  277. # relation type.
  278. # - Test restriction
  279. # - Test ignore
  280. category_student = self.category_model.create({'name': 'Student'})
  281. with self.assertRaises(ValidationError):
  282. type_school2student.write({
  283. 'partner_category_right': category_student.id})
  284. self.assertFalse(type_school2student.partner_category_right.id)
  285. type_school2student.write({
  286. 'handle_invalid_onchange': 'ignore',
  287. 'partner_category_right': category_student.id})
  288. self.assertEqual(
  289. type_school2student.partner_category_right.id,
  290. category_student.id)
  291. # Fourth make company type a condition for left partner
  292. # - Test ending
  293. # - Test deletion
  294. partner_bart.write({
  295. 'category_id': [(4, category_student.id)]})
  296. partner_lisa.write({
  297. 'category_id': [(4, category_student.id)]})
  298. # Future student to be deleted by end action:
  299. partner_homer = self.partner_model.create({
  300. 'name': 'Homer Simpson',
  301. 'is_company': False,
  302. 'ref': 'HS',
  303. 'category_id': [(4, category_student.id)]})
  304. relation_lisa2homer = self.relation_all_model.create({
  305. 'this_partner_id': partner_lisa.id,
  306. 'type_selection_id': school2student.id,
  307. 'other_partner_id': partner_homer.id,
  308. 'date_start': date.today() + relativedelta(months=+6)})
  309. self.assertTrue(relation_lisa2homer)
  310. type_school2student.write({
  311. 'handle_invalid_onchange': 'end',
  312. 'contact_type_left': 'c'})
  313. self.assertEqual(
  314. relation_bart2lisa.date_end,
  315. fields.Date.today())
  316. self.assertFalse(relation_lisa2homer.exists())
  317. type_school2student.write({
  318. 'handle_invalid_onchange': 'delete',
  319. 'contact_type_left': 'c',
  320. 'contact_type_right': 'p'})
  321. self.assertFalse(relation_bart2lisa.exists())
  322. def test_relation_type_unlink(self):
  323. """Test delete of relation type, including deleting relations."""
  324. # First create a relation type having restrict particular conditions.
  325. type_model = self.env['res.partner.relation.type']
  326. relation_model = self.env['res.partner.relation']
  327. partner_model = self.env['res.partner']
  328. type_school2student = type_model.create({
  329. 'name': 'school has student',
  330. 'name_inverse': 'studies at school',
  331. 'handle_invalid_onchange': 'delete'})
  332. # Second create relation based on those conditions.
  333. partner_school = partner_model.create({
  334. 'name': 'Test School',
  335. 'is_company': True,
  336. 'ref': 'TS'})
  337. partner_bart = partner_model.create({
  338. 'name': 'Bart Simpson',
  339. 'is_company': False,
  340. 'ref': 'BS'})
  341. relation_school2bart = relation_model.create({
  342. 'left_partner_id': partner_school.id,
  343. 'type_id': type_school2student.id,
  344. 'right_partner_id': partner_bart.id})
  345. # Delete type. Relations with type should also cease to exist:
  346. type_school2student.unlink()
  347. self.assertFalse(relation_school2bart.exists())