labd / commercetools-python-sdk

Commercetools Python SDK
https://commercetools-python-sdk.readthedocs.io/en/latest/
MIT License
17 stars 16 forks source link

Testing: Add constraintAttribute validation #131

Open qdegraaf opened 3 years ago

qdegraaf commented 3 years ago

The testing backend currently allows having attribute values that don't match the constraint of that attribute, e.g. having two different values for two variants of the same product for an attribute that has the SAME_FOR_ALL constraint.

The real commercetools API gives a nice error message like:

commercetools.exceptions.CommercetoolsError: The value '"Some Other value"' is not valid for field 'anAttributeWithASameForAllConstraint'. Allowed values are: "Some value". The value of the attribute must be the same across all variants.

It would be nice if we had similar validation in the testing backend. In quick half-pseudocode something like:

   def validate_constrained_attribute(
        variants: List[models.ProductVariantDraft], attr: ProductAttribute
    ):
        constraint_type = attr.constraint
        if constraint_type == models.AttributeConstraintEnum.SAME_FOR_ALL:
            flat_attributes = [
                item
                for sublist in [var.attributes for var in variants]
                for item in sublist
            ]
            # check if all values for the attribute across all variants are the same:
            values = [a.value for a in flat_attributes if a.name == attr.name]
            if not values:
                return

            unique_values = some form of set depending on attribute type
            if len(unique_values) != 1:
                raise ValidationError(
                    "Some complete error message"
                )
            else:
                return
        elif constraint_type == models.AttributeConstraintEnum.UNIQUE:
            flat_attributes = [
                item
                for sublist in [var.attributes for var in variants]
                for item in sublist
            ]
            # check if all values for the attribute across all variants are different:
            values = [a.value for a in flat_attributes if a.name == attr.name]
            if not values:
                return

            unique_values = some form of set depending on attribute type
            if len(unique_values) != len(values):
                raise ValidationError(
                    "Some complete error message"
                )
            else:
                return
        elif constraint_type == models.AttributeConstraintEnum.COMBINATION_UNIQUE:
            # this will probably be a little more convoluted
        else:
            raise ValidationError(
                "Could not recognize constrained attribute type: %s", attr.constraint
            )