class ShopProductSerializer(TranslatableModelSerializer): orderable = serializers.SerializerMethodField() visibility = EnumField(enum=ShopProductVisibility) visibility_limit = EnumField(enum=ProductVisibility) translations = TranslatedFieldsField(shared_model=ShopProduct, required=False) class Meta: model = ShopProduct fields = "__all__" extra_kwargs = { "visibility_groups": {"required": False}, "shipping_methods": {"required": False}, "suppliers": {"required": False}, "payment_methods": {"required": False}, "categories": {"required": False}, } def get_orderable(self, shop_product): customer = self.context["request"].customer quantity = shop_product.minimum_purchase_quantity supplier = shop_product.get_supplier(customer, quantity) try: return shop_product.is_orderable(supplier=supplier, customer=customer, quantity=quantity) except: return False
class SavedAddressSerializer(serializers.ModelSerializer): role = EnumField(SavedAddressRole) status = EnumField(SavedAddressStatus) address = AddressSerializer() class Meta: model = SavedAddress exclude = ()
class AttributeSerializer(TranslatableModelSerializer): translations = TranslatedFieldsField(shared_model=Attribute) type = EnumField(enum=AttributeType) visibility_mode = EnumField(enum=AttributeVisibility) class Meta: fields = "__all__" model = Attribute
class CategorySerializer(TranslatableModelSerializer): translations = TranslatedFieldsField(shared_model=Category) status = EnumField(CategoryStatus) visibility = EnumField(CategoryVisibility) class Meta: model = Category exclude = ("image", )
class OrderSerializer(serializers.ModelSerializer): payment_status = EnumField(PaymentStatus) shipping_status = EnumField(ShippingStatus) billing_address = AddressSerializer() shipping_address = AddressSerializer() lines = OrderLineSerializer(many=True) class Meta: model = Order exclude = ()
class CategorySerializer(TranslatableModelSerializer): translations = TranslatedFieldsField(shared_model=Category) status = EnumField(CategoryStatus) visibility = EnumField(CategoryVisibility) image = serializers.SerializerMethodField() class Meta: model = Category exclude = ("shops",) def get_image(self, category): if category.image: return self.context["request"].build_absolute_uri(category.image.url)
class ShopSerializer(TranslatableModelSerializer): translations = TranslatedFieldsField(shared_model=Shop) status = EnumField(ShopStatus) class Meta: model = Shop exclude = ("logo", "favicon")
class ShopSerializer(TranslatableModelSerializer): translations = TranslatedFieldsField(shared_model=Shop) status = EnumField(ShopStatus) logo = serializers.SerializerMethodField() favicon = serializers.SerializerMethodField() contact_address = AddressSerializer(read_only=True) distance = serializers.SerializerMethodField() options = serializers.JSONField(binary=False, required=False) class Meta: model = Shop kwargs = { "modified_on": {"read_only": True}, "created_on": {"read_only": True}, } exclude = ("identifier",) def to_representation(self, instance): data = super(ShopSerializer, self).to_representation(instance) data["currency"] = CurrencySerializer(Currency.objects.get(code=instance.currency), context=self.context).data return data def get_logo(self, shop): if shop.logo: return self.context["request"].build_absolute_uri(shop.logo.url) def get_favicon(self, shop): if shop.favicon: return self.context["request"].build_absolute_uri(shop.favicon.url) def get_distance(self, shop): return getattr(shop, 'distance', 0)
class PersonContactSerializer(ContactSerializer): gender = EnumField(Gender, required=False) class Meta(ContactSerializer.Meta): model = PersonContact extra_kwargs = { "created_on": {"read_only": True} }
class GDPRPersonContactSerializer(ContactSerializer): gender = EnumField(Gender) user = UserSerializer() log_entries = PersonContactLogEntrySerializer(many=True) company_memberships = GDPRCompanyContactSerializer(many=True) class Meta: model = PersonContact exclude = ("polymorphic_ctype", )
class ProductLinkVariationVariableSerializer(serializers.Serializer): product = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all(), required=False) hash = serializers.CharField(max_length=40, min_length=40, required=True) status = EnumField(enum=ProductVariationLinkStatus, required=False) def validate(self, data): if self.context["request"].method in ("PUT", "POST") and not data.get("product"): raise serializers.ValidationError("`product` is required for this method.") return data
class ProductSerializer(TranslatableModelSerializer): translations = TranslatedFieldsField(shared_model=Product) shop_products = ShopProductSubsetSerializer(many=True, read_only=True) primary_image = ProductMediaSerializer(read_only=True) media = ProductMediaSerializer(read_only=True, many=True) stock_behavior = EnumField(enum=StockBehavior) shipping_mode = EnumField(enum=ShippingMode) attributes = ProductAttributeSerializer(many=True, read_only=True) package_content = serializers.SerializerMethodField() variation_children = serializers.PrimaryKeyRelatedField(many=True, read_only=True) variation_variables = serializers.PrimaryKeyRelatedField(many=True, read_only=True) variation_results = serializers.SerializerMethodField() class Meta: fields = "__all__" model = Product extra_kwargs = { "mode": { "read_only": True }, "variation_parent": { "read_only": True }, "created_on": { "read_only": True }, "modified_on": { "read_only": True }, "deleted_on": { "read_only": True } } def get_package_content(self, product): return ProductPackageLinkSerializer( ProductPackageLink.objects.filter(parent=product), many=True).data def get_variation_results(self, product): return ProductVariationVariableResultSerializer( product).data["combinations"]
class CategorySerializer(TranslatableModelSerializer): translations = TranslatedFieldsField(shared_model=Category) status = EnumField(CategoryStatus) visibility = EnumField(CategoryVisibility) image = serializers.SerializerMethodField() def __init__(self, *args, **kwargs): super(CategorySerializer, self).__init__(*args, **kwargs) request = self.context.get("request") if request.method == "POST": self.fields["image"] = Base64FileField(required=False, write_only=True) self.fields["image_path"] = serializers.CharField(required=False, write_only=True) elif request.method == "GET": self.fields["image"] = serializers.SerializerMethodField() def create(self, validated_data): if "image_path" in validated_data: validated_data.pop("image_path") return super(CategorySerializer, self).create(validated_data) def validate(self, data): if data.get("image") and data.get("image_path"): data["image"] = filer_image_from_upload(self.context["request"], path=data["image_path"], upload_data=data["image"]) elif data.get("image"): raise serializers.ValidationError( "Path is required when sending a Category image.") return data def get_image(self, category): if category.image: return self.context["request"].build_absolute_uri( category.image.url) class Meta: model = Category fields = '__all__'
class ProductMediaSerializer(TranslatableModelSerializer): kind = EnumField(enum=ProductMediaKind) translations = TranslatedFieldsField(shared_model=ProductMedia) file = serializers.SerializerMethodField() class Meta: model = ProductMedia extra_kwargs = {"product": {"read_only": True}} exclude = ("identifier", ) def get_file(self, product_media): if product_media.file: return self.context["request"].build_absolute_uri( product_media.file.url)
class BasketLineSerializer(serializers.Serializer): product = BasketProductSerializer(required=False) image = serializers.SerializerMethodField() text = serializers.CharField() sku = serializers.CharField() quantity = serializers.DecimalField( max_digits=FORMATTED_DECIMAL_FIELD_MAX_DIGITS, decimal_places=FORMATTED_DECIMAL_FIELD_DECIMAL_PLACES) price = serializers.DecimalField( max_digits=FORMATTED_DECIMAL_FIELD_MAX_DIGITS, decimal_places=FORMATTED_DECIMAL_FIELD_DECIMAL_PLACES) base_price = serializers.DecimalField( max_digits=FORMATTED_DECIMAL_FIELD_MAX_DIGITS, decimal_places=FORMATTED_DECIMAL_FIELD_DECIMAL_PLACES) discount_amount = serializers.DecimalField( max_digits=FORMATTED_DECIMAL_FIELD_MAX_DIGITS, decimal_places=FORMATTED_DECIMAL_FIELD_DECIMAL_PLACES) type = EnumField(OrderLineType) shop = serializers.SerializerMethodField() shop_product = serializers.SerializerMethodField() line_id = serializers.CharField() def get_image(self, line): """ Return simply the primary image URL """ if not line.product: return primary_image = line.product.primary_image # no image found if not primary_image: # check for variation parent image if not line.product.variation_parent or not line.product.variation_parent.primary_image: return primary_image = line.product.variation_parent.primary_image if primary_image.external_url: return primary_image.external_url else: return self.context["request"].build_absolute_uri( primary_image.file.url) def get_shop_product(self, line): return line.shop_product.id if line.product else None def get_shop(self, line): return line.shop.id if line.shop else None
class BasketBaseLineSerializer(BaseLineSerializerMixin, serializers.Serializer): product = BasketProductSerializer(required=False) image = serializers.SerializerMethodField() text = serializers.CharField() sku = serializers.CharField() can_delete = serializers.BooleanField() can_change_quantity = serializers.BooleanField() supplier = serializers.IntegerField(source="supplier.id") type = EnumField(OrderLineType) shop = serializers.SerializerMethodField() shop_product = serializers.SerializerMethodField() line_id = serializers.CharField() def get_image(self, line): """ Return simply the primary image URL """ if not line.product: return primary_image = line.product.primary_image # no image found if not primary_image: # check for variation parent image if not line.product.variation_parent or not line.product.variation_parent.primary_image: return primary_image = line.product.variation_parent.primary_image if primary_image.external_url: return primary_image.external_url else: return self.context["request"].build_absolute_uri( primary_image.file.url) def get_shop_product(self, line): return line.shop_product.id if line.product else None def get_shop(self, line): return line.shop.id if line.shop else None
class ContactSerializer(serializers.ModelSerializer): default_shipping_address = AddressSerializer(required=False) default_billing_address = AddressSerializer(required=False) gender = EnumField(Gender, required=False) name = serializers.CharField(required=False) class Meta: model = PersonContact exclude = [ "identifier", "tax_group", "polymorphic_ctype", "account_manager" ] extra_kwargs = {"created_on": {"read_only": True}} def update_address(self, instance, field_name, validated_address_data): if not validated_address_data: return None contact_address = getattr(instance, field_name) if contact_address: MutableAddress.objects.filter(pk=contact_address.pk).update( **validated_address_data) contact_address.refresh_from_db() else: address = MutableAddress(**validated_address_data) address.save() setattr(instance, field_name, address) instance.save() def update(self, instance, validated_data): default_shipping_address = validated_data.pop( "default_shipping_address", None) default_billing_address = validated_data.pop("default_billing_address", None) instance = super(ContactSerializer, self).update(instance, validated_data) self.update_address(instance, "default_shipping_address", default_shipping_address) self.update_address(instance, "default_billing_address", default_billing_address) return instance
class OrderLineSerializer(serializers.ModelSerializer): type = EnumField(OrderLineType) class Meta: model = OrderLine exclude = ()
class ProductSerializer(TranslatableModelSerializer): translations = TranslatedFieldsField(shared_model=Product) shop_products = ShopProductSubsetSerializer(many=True, required=False) primary_image = ProductMediaSerializer(read_only=True) media = ProductMediaSerializer(read_only=True, many=True) stock_behavior = EnumField(enum=StockBehavior) shipping_mode = EnumField(enum=ShippingMode) attributes = ProductAttributeSerializer(many=True, required=False) package_content = serializers.SerializerMethodField() variation_children = serializers.PrimaryKeyRelatedField(many=True, read_only=True) variation_variables = serializers.PrimaryKeyRelatedField(many=True, read_only=True) variation_results = serializers.SerializerMethodField() class Meta: fields = "__all__" model = Product extra_kwargs = { "mode": {"read_only": True}, "variation_parent": {"read_only": True}, "created_on": {"read_only": True}, "modified_on": {"read_only": True}, "deleted_on": {"read_only": True} } def get_package_content(self, product): return ProductPackageLinkSerializer(ProductPackageLink.objects.filter(parent=product), many=True).data def get_variation_results(self, product): return ProductVariationVariableResultSerializer(product).data["combinations"] def create(self, validated_data): nested = self._pop_nested_objects(validated_data) instance = super(ProductSerializer, self).create(validated_data) self._handle_nested_structures(instance, nested) return instance def update(self, instance, validated_data): nested = self._pop_nested_objects(validated_data) super(ProductSerializer, self).update(instance, validated_data) self._handle_nested_structures(instance, nested) return instance def _pop_nested_objects(self, validated_data): return { field: validated_data.pop(field, None) for field in ['attributes', 'shop_products'] } def _handle_nested_structures(self, product, nested): attributes = nested['attributes'] shop_products = nested['shop_products'] if not self.partial: if attributes is not None: product.attributes.all().delete() if shop_products is not None: product.shop_products.all().delete() if attributes: for attribute_data in attributes: self._handle_attribute_value(product, attribute_data) if shop_products: for shop_product_data in shop_products: self._handle_shop_product(product, shop_product_data) def _handle_attribute_value(self, product, data): attr = data["attribute"] # type: shuup.core.models.Attribute if attr.is_stringy and attr.is_translated: translations = data.get('translations') if not self.partial or translations is None: product.clear_attribute_value(attr.identifier) for (lang, lang_data) in (translations or {}).items(): value = lang_data["translated_string_value"] product.set_attribute_value(attr.identifier, value, language=lang) elif attr.is_stringy: product.set_attribute_value(attr.identifier, data["untranslated_string_value"]) elif attr.is_numeric: product.set_attribute_value(attr.identifier, data["numeric_value"]) elif attr.is_temporal: product.set_attribute_value(attr.identifier, data["datetime_value"]) def _handle_shop_product(self, product, data): shop = data.pop('shop') m2m_data = [ (field, data.pop(field, None)) for field in ['suppliers', 'categories', 'visibility_groups', 'shipping_methods', 'payment_methods'] ] (shop_product, created) = ShopProduct.objects.get_or_create( product=product, shop=shop, defaults=data) if not created: for (field, value) in data.items(): setattr(shop_product, field, value) shop_product.save() for (field, values) in m2m_data: if values is None: continue field_objects = getattr(shop_product, field) field_objects.clear() for value in values: field_objects.add(value) return shop_product
class ContactLogEntrySerializer(serializers.ModelSerializer): kind = EnumField(LogEntryKind) class Meta: model = ContactGroupLogEntry exclude = ()
class StockAdjustmentSerializer(serializers.Serializer): type = EnumField(StockAdjustmentType, default=StockAdjustmentType.INVENTORY) product = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all_except_deleted()) delta = FormattedDecimalField()