partner-contact/partner_multi_relation/tests/test_partner_relation.py
2021-05-26 13:31:53 +02:00

458 lines
17 KiB
Python

# Copyright 2016-2017 Therp BV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from datetime import date, datetime, timedelta
from dateutil.relativedelta import relativedelta
from flectra import fields
from flectra.exceptions import ValidationError
from .test_partner_relation_common import TestPartnerRelationCommon
class TestPartnerRelation(TestPartnerRelationCommon):
post_install = True
def test_selection_name_search(self):
"""Test wether we can find type selection on reverse name."""
selection_types = self.selection_model.name_search(
name=self.selection_person2company.name
)
self.assertTrue(selection_types)
self.assertTrue(
(self.selection_person2company.id, self.selection_person2company.name)
in selection_types
)
def test_self_allowed(self):
"""Test creation of relation to same partner when type allows."""
type_allow = self.type_model.create(
{
"name": "allow",
"name_inverse": "allow_inverse",
"contact_type_left": "p",
"contact_type_right": "p",
"allow_self": True,
}
)
self.assertTrue(type_allow)
reflexive_relation = self.relation_model.create(
{
"type_id": type_allow.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_01_person.id,
}
)
self.assertTrue(reflexive_relation)
def test_self_disallowed(self):
"""Test creating relation to same partner when disallowed.
Attempt to create a relation of a partner to the same partner should
raise an error when the type of relation explicitly disallows this.
"""
type_disallow = self.type_model.create(
{
"name": "disallow",
"name_inverse": "disallow_inverse",
"contact_type_left": "p",
"contact_type_right": "p",
"allow_self": False,
}
)
self.assertTrue(type_disallow)
with self.assertRaises(ValidationError):
self.relation_model.create(
{
"type_id": type_disallow.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_01_person.id,
}
)
def test_self_disallowed_after_self_relation_created(self):
"""Test that allow_self can not be true if a reflexive relation already exists.
If at least one reflexive relation exists for the given type,
reflexivity can not be disallowed.
"""
type_allow = self.type_model.create(
{
"name": "allow",
"name_inverse": "allow_inverse",
"contact_type_left": "p",
"contact_type_right": "p",
"allow_self": True,
}
)
self.assertTrue(type_allow)
reflexive_relation = self.relation_model.create(
{
"type_id": type_allow.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_01_person.id,
}
)
self.assertTrue(reflexive_relation)
with self.assertRaises(ValidationError):
type_allow.allow_self = False
def test_self_disallowed_with_delete_invalid_relations(self):
"""Test handle_invalid_onchange delete with allow_self disabled.
When deactivating allow_self, if handle_invalid_onchange is set
to delete, then existing reflexive relations are deleted.
Non reflexive relations are not modified.
"""
type_allow = self.type_model.create(
{
"name": "allow",
"name_inverse": "allow_inverse",
"contact_type_left": "p",
"contact_type_right": "p",
"allow_self": True,
"handle_invalid_onchange": "delete",
}
)
reflexive_relation = self.relation_model.create(
{
"type_id": type_allow.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_01_person.id,
}
)
normal_relation = self.relation_model.create(
{
"type_id": type_allow.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_04_volunteer.id,
}
)
type_allow.allow_self = False
self.assertFalse(reflexive_relation.exists())
self.assertTrue(normal_relation.exists())
def test_self_disallowed_with_end_invalid_relations(self):
"""Test handle_invalid_onchange delete with allow_self disabled.
When deactivating allow_self, if handle_invalid_onchange is set
to end, then active reflexive relations are ended.
Non reflexive relations are not modified.
Reflexive relations with an end date prior to the current date
are not modified.
"""
type_allow = self.type_model.create(
{
"name": "allow",
"name_inverse": "allow_inverse",
"contact_type_left": "p",
"contact_type_right": "p",
"allow_self": True,
"handle_invalid_onchange": "end",
}
)
reflexive_relation = self.relation_model.create(
{
"type_id": type_allow.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_01_person.id,
"date_start": "2000-01-02",
}
)
past_reflexive_relation = self.relation_model.create(
{
"type_id": type_allow.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_01_person.id,
"date_end": "2000-01-01",
}
)
normal_relation = self.relation_model.create(
{
"type_id": type_allow.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_04_volunteer.id,
}
)
type_allow.allow_self = False
self.assertEqual(reflexive_relation.date_end, fields.Date.today())
self.assertEqual(past_reflexive_relation.date_end, date(2000, 1, 1))
self.assertFalse(normal_relation.date_end)
def test_self_disallowed_with_future_reflexive_relation(self):
"""Test future reflexive relations are deleted.
If handle_invalid_onchange is set to end, then deactivating
reflexivity will delete invalid relations in the future.
"""
type_allow = self.type_model.create(
{
"name": "allow",
"name_inverse": "allow_inverse",
"contact_type_left": "p",
"contact_type_right": "p",
"allow_self": True,
"handle_invalid_onchange": "end",
}
)
future_reflexive_relation = self.relation_model.create(
{
"type_id": type_allow.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_01_person.id,
"date_start": datetime.now() + timedelta(1),
}
)
type_allow.allow_self = False
self.assertFalse(future_reflexive_relation.exists())
def test_self_default(self):
"""Test default not to allow relation with same partner.
Attempt to create a relation of a partner to the same partner
raise an error when the type of relation does not explicitly allow
this.
"""
type_default = self.type_model.create(
{
"name": "default",
"name_inverse": "default_inverse",
"contact_type_left": "p",
"contact_type_right": "p",
}
)
self.assertTrue(type_default)
with self.assertRaises(ValidationError):
self.relation_model.create(
{
"type_id": type_default.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_01_person.id,
}
)
def test_self_mixed(self):
"""Test creation of relation with wrong types.
Trying to create a relation between partners with an inappropiate
type should raise an error.
"""
with self.assertRaises(ValidationError):
self.relation_model.create(
{
"type_id": self.type_company2person.id,
"left_partner_id": self.partner_01_person.id,
"right_partner_id": self.partner_02_company.id,
}
)
def test_symmetric(self):
"""Test creating symmetric relation."""
# Start out with non symmetric relation:
type_symmetric = self.type_model.create(
{
"name": "not yet symmetric",
"name_inverse": "the other side of not symmetric",
"is_symmetric": False,
"contact_type_left": False,
"contact_type_right": "p",
}
)
# not yet symmetric relation should result in two records in
# selection:
selection_symmetric = self.selection_model.search(
[("type_id", "=", type_symmetric.id)]
)
self.assertEqual(len(selection_symmetric), 2)
# Now change to symmetric and test name and inverse name:
type_symmetric.write({"name": "sym", "is_symmetric": True})
self.assertEqual(type_symmetric.is_symmetric, True)
self.assertEqual(type_symmetric.name_inverse, type_symmetric.name)
self.assertEqual(
type_symmetric.contact_type_right, type_symmetric.contact_type_left
)
# now update the database:
type_symmetric.write(
{
"name": type_symmetric.name,
"is_symmetric": type_symmetric.is_symmetric,
"name_inverse": type_symmetric.name_inverse,
"contact_type_right": type_symmetric.contact_type_right,
}
)
type_symmetric.flush()
# symmetric relation should result in only one record in
# selection:
selection_symmetric = self.selection_model.search(
[("type_id", "=", type_symmetric.id)]
)
self.assertEqual(len(selection_symmetric), 1)
relation = self.relation_all_model.create(
{
"type_selection_id": selection_symmetric.id,
"this_partner_id": self.partner_02_company.id,
"other_partner_id": self.partner_01_person.id,
}
)
partners = self.partner_model.search(
[("search_relation_type_id", "=", relation.type_selection_id.id)]
)
self.assertTrue(self.partner_01_person in partners)
self.assertTrue(self.partner_02_company in partners)
def test_category_domain(self):
"""Test check on category in relations."""
# Check on left side:
with self.assertRaises(ValidationError):
self.relation_model.create(
{
"type_id": self.type_ngo2volunteer.id,
"left_partner_id": self.partner_02_company.id,
"right_partner_id": self.partner_04_volunteer.id,
}
)
# Check on right side:
with self.assertRaises(ValidationError):
self.relation_model.create(
{
"type_id": self.type_ngo2volunteer.id,
"left_partner_id": self.partner_03_ngo.id,
"right_partner_id": self.partner_01_person.id,
}
)
def test_relation_type_change(self):
"""Test change in relation type conditions."""
# First create a relation type having no particular conditions.
(
type_school2student,
school2student,
school2student_inverse,
) = self._create_relation_type_selection(
{"name": "school has student", "name_inverse": "studies at school"}
)
# Second create relations based on those conditions.
partner_school = self.partner_model.create(
{"name": "Test School", "is_company": True, "ref": "TS"}
)
partner_bart = self.partner_model.create(
{"name": "Bart Simpson", "is_company": False, "ref": "BS"}
)
partner_lisa = self.partner_model.create(
{"name": "Lisa Simpson", "is_company": False, "ref": "LS"}
)
relation_school2bart = self.relation_all_model.create(
{
"this_partner_id": partner_school.id,
"type_selection_id": school2student.id,
"other_partner_id": partner_bart.id,
}
)
self.assertTrue(relation_school2bart)
relation_school2lisa = self.relation_all_model.create(
{
"this_partner_id": partner_school.id,
"type_selection_id": school2student.id,
"other_partner_id": partner_lisa.id,
}
)
self.assertTrue(relation_school2lisa)
relation_bart2lisa = self.relation_all_model.create(
{
"this_partner_id": partner_bart.id,
"type_selection_id": school2student.id,
"other_partner_id": partner_lisa.id,
}
)
self.assertTrue(relation_bart2lisa)
# Third creata a category and make it a condition for the
# relation type.
# - Test restriction
# - Test ignore
category_student = self.category_model.create({"name": "Student"})
with self.assertRaises(ValidationError):
type_school2student.write({"partner_category_right": category_student.id})
self.assertFalse(type_school2student.partner_category_right.id)
type_school2student.write(
{
"handle_invalid_onchange": "ignore",
"partner_category_right": category_student.id,
}
)
self.assertEqual(
type_school2student.partner_category_right.id, category_student.id
)
# Fourth make company type a condition for left partner
# - Test ending
# - Test deletion
partner_bart.write({"category_id": [(4, category_student.id)]})
partner_lisa.write({"category_id": [(4, category_student.id)]})
# Future student to be deleted by end action:
partner_homer = self.partner_model.create(
{
"name": "Homer Simpson",
"is_company": False,
"ref": "HS",
"category_id": [(4, category_student.id)],
}
)
relation_lisa2homer = self.relation_all_model.create(
{
"this_partner_id": partner_lisa.id,
"type_selection_id": school2student.id,
"other_partner_id": partner_homer.id,
"date_start": date.today() + relativedelta(months=+6),
}
)
self.assertTrue(relation_lisa2homer)
type_school2student.write(
{"handle_invalid_onchange": "end", "contact_type_left": "c"}
)
self.assertEqual(relation_bart2lisa.date_end, fields.Date.today())
self.assertFalse(relation_lisa2homer.exists())
type_school2student.write(
{
"handle_invalid_onchange": "delete",
"contact_type_left": "c",
"contact_type_right": "p",
}
)
self.assertFalse(relation_bart2lisa.exists())
def test_relation_type_unlink(self):
"""Test delete of relation type, including deleting relations."""
# First create a relation type having restrict particular conditions.
type_model = self.env["res.partner.relation.type"]
relation_model = self.env["res.partner.relation"]
partner_model = self.env["res.partner"]
type_school2student = type_model.create(
{
"name": "school has student",
"name_inverse": "studies at school",
"handle_invalid_onchange": "delete",
}
)
# Second create relation based on those conditions.
partner_school = partner_model.create(
{"name": "Test School", "is_company": True, "ref": "TS"}
)
partner_bart = partner_model.create(
{"name": "Bart Simpson", "is_company": False, "ref": "BS"}
)
relation_school2bart = relation_model.create(
{
"left_partner_id": partner_school.id,
"type_id": type_school2student.id,
"right_partner_id": partner_bart.id,
}
)
# Delete type. Relations with type should also cease to exist:
type_school2student.unlink()
self.assertFalse(relation_school2bart.exists())