diff --git a/partner_tier_validation/models/res_partner.py b/partner_tier_validation/models/res_partner.py index 909085098..9c251a958 100644 --- a/partner_tier_validation/models/res_partner.py +++ b/partner_tier_validation/models/res_partner.py @@ -15,40 +15,36 @@ class ResPartner(models.Model): _tier_validation_manual_config = False @api.model - def _tier_revalidation_fields(self, values): + def _partner_tier_revalidation_fields(self, values): """ Changing some Partner fields forces Tier Validation to be reevaluated. Out of the box these are is_company and parent_id. Other can be added extending this method. """ - return ["is_company", "parent_id"] - - @api.model - def _get_confirmed_stage(self): - return self.env["res.partner.stage"].search( - [("state", "in", self._state_to)], limit=1 - ) - - @api.model - def create(self, vals): - new = super().create(vals) - # Contact not requiring validation - # are created in confirmed state - if not new.need_validation: - confirmed_stage = self._get_confirmed_stage() - new.stage_id = confirmed_stage - return new + # IDEA: make it a System Parameter? + return [ + "company_type", + "parent_id", + "vat", + "state_id", + "country_id", + "property_account_position_id", + "property_account_receivable_id", + "property_account_payable_id", + ] def write(self, vals): - # Signal state transition by adding to vals + # Changing certain fields requires a new validation process + revalidate_fields = self._partner_tier_revalidation_fields(vals) + if any(x in revalidate_fields for x in vals.keys()): + vals["stage_id"] = self._get_default_stage_id().id + # Tier Validation does not work with Stages, only States :-( + # Workaround is to signal state transition adding it to the write values if "stage_id" in vals: stage_id = vals.get("stage_id") stage = self.env["res.partner.stage"].browse(stage_id) vals["state"] = stage.state - # Changing certain fields required new validation process - revalidate_fields = self._tier_revalidation_fields(vals) - if any(x in revalidate_fields for x in vals.keys()): - self.mapped("review_ids").unlink() - vals["state"] = "draft" - self.request_validation() - return super().write(vals) + res = super().write(vals) + if "stage_id" in vals: + self.restart_validation() + return res diff --git a/partner_tier_validation/readme/CONFIGURATION.rst b/partner_tier_validation/readme/CONFIGURATION.rst index f2c56d72e..12f37af2d 100644 --- a/partner_tier_validation/readme/CONFIGURATION.rst +++ b/partner_tier_validation/readme/CONFIGURATION.rst @@ -3,8 +3,22 @@ A default validation rule is provided out of the box, that can be used as a starting point fot this configuration. This configuration is done at -*Settings > Technical > Tier Validations > Tier Definition*. +*Settings / Technical / Tier Validations / Tier Definition*. -Note that, since Contacts start as archived records, -the *Definition Domain* must include ``"|",["active","=",True],["active","=",False]``. -Otherwise the validation rule won't apply correctly in new records. +Also relevant is the configuration on the default Stage +for new Contacts/Partners. +This can be set at *Contacts / Configuration / Contact Stage*, +setting the "Default Sate" field on the appropriate Stage record. + +Changing some fields will trigger a new request for validation. +This list of fields can be customized extending ``_partner_tier_revalidation_fields``. +By default these fields are: + +- Company Type (Individual or Company) +- Parent Company +- Tax ID +- State +- Country +- Fiscal Position +- Account Receivable +- Account Payable diff --git a/partner_tier_validation/readme/USAGE.rst b/partner_tier_validation/readme/USAGE.rst index 40016f54a..fb81ae01d 100644 --- a/partner_tier_validation/readme/USAGE.rst +++ b/partner_tier_validation/readme/USAGE.rst @@ -1,3 +1,8 @@ +Before using, check Contact Stages configuration, +to ensure that the default stage has the "Related State" field +set to "To Approve". +For example, having the "Draft" stage the default ensures this. + A regular user creates a new Contact and sends it for approval: #. Create a Contact triggering at least one "Tier Definition". diff --git a/partner_tier_validation/tests/test_tier_validation.py b/partner_tier_validation/tests/test_tier_validation.py index 56420cfcf..1a556b576 100644 --- a/partner_tier_validation/tests/test_tier_validation.py +++ b/partner_tier_validation/tests/test_tier_validation.py @@ -10,18 +10,25 @@ class TestPartnerTierValidation(common.SavepointCase): @classmethod def setUpClass(cls): super().setUpClass() - # Get res partner model - cls.partner_model = cls.env.ref("base.model_res_partner") - # Create users - group_ids = cls.env.ref("base.group_system").ids - group_ids.append(cls.env.ref("base.group_partner_manager").id) - cls.test_user_1 = cls.env["res.users"].create( + group_user = cls.env.ref("base.group_user") + group_contacts = cls.env.ref("base.group_partner_manager") + group_approver = cls.env.ref("base.group_no_one") + User = cls.env["res.users"] + cls.user_employee = User.create( + { + "name": "Employee", + "login": "empl1", + "email": "empl1@example.com", + "groups_id": (group_user | group_contacts).ids, + } + ) + cls.user_approver = User.create( { - "name": "John", - "login": "test1", - "groups_id": [(6, 0, group_ids)], - "email": "test@example.com", + "name": "Approver", + "login": "aprov1", + "email": "approv1@example.com", + "groups_id": (group_user | group_contacts | group_approver).ids, } ) @@ -29,13 +36,20 @@ class TestPartnerTierValidation(common.SavepointCase): cls.TierDefinition = cls.env["tier.definition"] cls.TierDefinition.create( { - "model_id": cls.partner_model.id, + "model_id": cls.env.ref("base.model_res_partner").id, "review_type": "individual", - "reviewer_id": cls.test_user_1.id, + "reviewer_id": cls.user_approver.id, "definition_domain": "[('is_company','=',True)]", } ) + # Setup Contact Stages: draft is the default + Stage = cls.env["res.partner.stage"] + Stage.search([("is_default", "=", True)]).write({"is_default": False}) + cls.stage_draft = Stage.search([("state", "=", "draft")], limit=1) + cls.stage_draft.is_default = True + cls.stage_confirmed = Stage.search([("state", "=", "confirmed")], limit=1) + def test_tier_validation_model_name(self): self.assertIn( "res.partner", self.TierDefinition._get_tier_validation_model_names() @@ -45,31 +59,37 @@ class TestPartnerTierValidation(common.SavepointCase): """ Case where new Contact requires validation """ - contact = self.env["res.partner"].create( - {"name": "Company for test", "company_type": "company"} - ) - # Since contact need validation, it should be inactive + Partner = self.env["res.partner"] + contact_vals = {"name": "Company for test", "company_type": "company"} + contact = Partner.with_user(self.user_employee).create(contact_vals) self.assertEqual(contact.state, "draft") # Assert an error shows if trying to make it active with self.assertRaises(ValidationError): - contact.write({"state": "confirmed"}) + contact.write({"stage_id": self.stage_confirmed.id}) # Request and validate partner contact.request_validation() - contact.with_user(self.test_user_1).validate_tier() - contact.with_user(self.test_user_1).write({"state": "confirmed"}) + contact.with_user(self.user_approver).validate_tier() + contact.with_user(self.user_approver).write( + {"stage_id": self.stage_confirmed.id} + ) self.assertEqual(contact.state, "confirmed") # Change company type to retrigger validation - contact.write({"company_type": "person", "is_company": False}) - self.assertEqual(contact.state, "draft") + contact.write({"company_type": "person"}) + self.assertEqual( + contact.state, "draft", "Change company type sets back to draft" + ) def test_no_validation_res_partner(self): """ Case where new Contact does not require validation """ - contact = self.env["res.partner"].create( - {"name": "Person for test", "company_type": "person"} - ) + Partner = self.env["res.partner"] + contact_vals = {"name": "Company for test", "company_type": "person"} + contact = Partner.with_user(self.user_employee).create(contact_vals) + self.assertEqual(contact.state, "draft") + # Can move to confirmed state without approval + contact.write({"stage_id": self.stage_confirmed.id}) self.assertEqual(contact.state, "confirmed")