ob-dj-store 0.0.12__py3-none-any.whl → 0.0.12.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,4 @@
1
1
  import calendar
2
- import sys
3
2
  import typing
4
3
  from datetime import time, timedelta
5
4
 
@@ -7,7 +6,9 @@ from django.conf import settings
7
6
  from django.contrib.contenttypes.models import ContentType
8
7
  from django.contrib.gis.geos import Point
9
8
  from django.core.exceptions import ObjectDoesNotExist, ValidationError
9
+ from django.db import models
10
10
  from django.shortcuts import get_object_or_404
11
+ from django.utils.module_loading import import_string
11
12
  from django.utils.timezone import now
12
13
  from django.utils.translation import gettext_lazy as _
13
14
  from rest_framework import serializers
@@ -963,18 +964,25 @@ class GenericSerializer(serializers.Serializer):
963
964
  return serializer_class(context=context).to_representation(value)
964
965
 
965
966
  def get_serializer_for_instance(self, instance):
966
- serializer_class = instance.__class__.__name__ + "Serializer"
967
- if hasattr(sys.modules[__name__], serializer_class):
968
- return getattr(sys.modules[__name__], serializer_class)
969
- else:
970
- raise NameError(_(f"name '{serializer_class}' is not defined"))
967
+ serializer_class = instance.__class__.__name__
968
+ return import_string(
969
+ store_settings.FAVORITES_SERIALIZERS_PATHS[serializer_class]
970
+ )
971
+
972
+
973
+ def get_favorite_extras_models():
974
+ extras_list = []
975
+ for key, value in settings.FAVORITE_TYPES.items():
976
+ if "extras" in value:
977
+ extras_list.extend(value["extras"].keys())
978
+ return extras_list
971
979
 
972
980
 
973
981
  class FavoriteExtraSerializer(serializers.ModelSerializer):
974
982
  content_object = GenericSerializer(read_only=True)
975
983
  object_id = serializers.IntegerField(min_value=1, write_only=True)
976
984
  object_type = serializers.ChoiceField(
977
- write_only=True, choices=store_settings.EXTRA_FAVORITE_TYPES
985
+ write_only=True, choices=get_favorite_extras_models()
978
986
  )
979
987
 
980
988
  class Meta:
@@ -986,13 +994,23 @@ class FavoriteExtraSerializer(serializers.ModelSerializer):
986
994
  "object_type",
987
995
  )
988
996
 
997
+ def to_representation(self, instance):
998
+ data = super().to_representation(instance)
999
+ extras = get_favorite_extras_models()
1000
+ model_name = instance.content_type.model
1001
+ for extra in extras:
1002
+ if model_name == extra.lower():
1003
+ data["object_type"] = extra
1004
+ break
1005
+ return data
1006
+
989
1007
 
990
1008
  class FavoriteSerializer(serializers.ModelSerializer):
991
1009
  content_object = GenericSerializer(read_only=True)
992
1010
  extras = FavoriteExtraSerializer(many=True)
993
1011
  object_id = serializers.IntegerField(min_value=1, write_only=True)
994
1012
  object_type = serializers.ChoiceField(
995
- write_only=True, choices=store_settings.FAVORITE_TYPES
1013
+ write_only=True, choices=list(store_settings.FAVORITE_TYPES.keys())
996
1014
  )
997
1015
 
998
1016
  class Meta:
@@ -1009,63 +1027,87 @@ class FavoriteSerializer(serializers.ModelSerializer):
1009
1027
  "name": {"required": True},
1010
1028
  }
1011
1029
 
1030
+ def to_representation(self, instance):
1031
+ data = super().to_representation(instance)
1032
+ model_name = instance.content_type.model
1033
+ for favorite in store_settings.FAVORITE_TYPES.keys():
1034
+ if model_name == favorite.lower():
1035
+ data["object_type"] = favorite
1036
+ break
1037
+ return data
1038
+
1012
1039
  def _lookup_validation(self, data):
1013
- content_type = ContentType.objects.get_for_model(type(data["content_object"]))
1014
- extras_lookup_content_type = {}
1015
- for extra in data["extras"]:
1016
- content_type_extra = extra.model
1017
- extras_lookup_content_type[content_type_extra] = extra
1040
+ content_type = ContentType.objects.get_for_model(data["content_object"])
1018
1041
  queryset = Favorite.objects.filter(
1019
1042
  content_type=content_type,
1020
1043
  object_id=data["content_object"].id,
1021
1044
  user=self.context["request"].user,
1022
- )
1023
- for key in extras_lookup_content_type.keys():
1024
- queryset = queryset.filter(
1025
- extras__content_type=ContentType.objects.get_for_model(key),
1026
- extras__object_id__in=[
1027
- extra.id for extra in extras_lookup_content_type[key]
1028
- ],
1029
- )
1030
- if queryset.exists():
1045
+ ).prefetch_related("extras")
1046
+
1047
+ if not queryset.exists():
1048
+ return
1049
+
1050
+ for favorite in queryset:
1051
+ content_objects = [
1052
+ instance.content_object for instance in favorite.extras.all()
1053
+ ]
1054
+ if data["extras"] == content_objects:
1055
+ raise serializers.ValidationError(
1056
+ _(f"You cannot favorite the same item twice")
1057
+ )
1058
+
1059
+ def get_object(self, model: models.Model, id: int):
1060
+ try:
1061
+ object = model.objects.get(pk=id)
1062
+ return object
1063
+ except model.DoesNotExist:
1031
1064
  raise serializers.ValidationError(
1032
- _(f"You cannot favorite the same item twice")
1065
+ _(f"{model.__name__} with the id of {id} does not exist")
1033
1066
  )
1034
1067
 
1035
1068
  def validate(self, attrs):
1036
1069
  validated_data = super().validate(attrs)
1070
+ extras_data = {}
1037
1071
  name = validated_data["name"]
1038
1072
  object_type = validated_data["object_type"]
1039
- if object_type not in store_settings.FAVORITE_TYPES and hasattr(
1040
- sys.modules[__name__], object_type
1041
- ):
1042
- raise serializers.ValidationError(
1043
- _(f"Cannot resolve keyword '{object_type}' into an object type")
1044
- )
1045
- object_type_model = getattr(sys.modules[__name__], object_type)
1073
+ object_type_model = import_string(
1074
+ store_settings.FAVORITE_TYPES[object_type]["path"]
1075
+ )
1046
1076
  object_instance = get_object_or_404(
1047
1077
  object_type_model, pk=validated_data["object_id"]
1048
1078
  )
1049
- extras_data = {}
1050
- extras = []
1051
1079
  for extra in validated_data["extras"]:
1052
- extra_object_type = extra["object_type"]
1053
- if extra_object_type not in store_settings.EXTRA_FAVORITE_TYPES:
1080
+ if (
1081
+ extra["object_type"]
1082
+ not in store_settings.FAVORITE_TYPES[object_type]["extras"]
1083
+ ):
1054
1084
  raise serializers.ValidationError(
1055
- _(
1056
- f"Cannot resolve keyword '{extra_object_type}' into an object type"
1057
- )
1085
+ _(f"{extra['object_type']} Cannot be extra of {object_type}")
1058
1086
  )
1059
- extras_data.setdefault(extra_object_type, [])
1060
- extras_data[extra_object_type].append(extra["object_id"])
1061
- try:
1062
- for key in extras_data.keys():
1063
- model_class = getattr(sys.modules[__name__], key, None)
1064
- if model_class:
1065
- extras.append(model_class.objects.filter(id__in=extras_data[key]))
1066
- except ObjectDoesNotExist:
1067
- raise serializers.ValidationError(_("No matches the given query."))
1087
+ extra_object_type = extra["object_type"]
1088
+ extras_data.setdefault(
1089
+ extra_object_type,
1090
+ {
1091
+ "model": import_string(
1092
+ store_settings.FAVORITE_TYPES[object_type]["extras"][
1093
+ extra_object_type
1094
+ ]["path"]
1095
+ ),
1096
+ "ids": [],
1097
+ },
1098
+ )
1099
+ extras_data[extra_object_type]["ids"].append(extra["object_id"])
1068
1100
 
1101
+ extras = []
1102
+ for key, value in extras_data.items():
1103
+ type = store_settings.FAVORITE_TYPES[object_type]["extras"][key]["type"]
1104
+ if len(value["ids"]) > 1 and type == store_settings.SIGNLE_FAVORITE_EXTRA:
1105
+ raise serializers.ValidationError(_(f"Cannot set multiple {key}s"))
1106
+ for id in value["ids"]:
1107
+ extras.append(
1108
+ self.get_object(value["model"], id)
1109
+ ) # get objects of extras instead of ids
1110
+ extras = list(set(extras)) # remove duplicated extras
1069
1111
  validated_data = {
1070
1112
  "content_object": object_instance,
1071
1113
  "extras": extras,
@@ -44,13 +44,12 @@ class Favorite(DjangoModelCleanMixin, models.Model):
44
44
  )
45
45
  favorite.save()
46
46
  for extra in extras:
47
- for obj in extra:
48
- extra_content_type = ContentType.objects.get_for_model(type(obj))
49
- favorite.extras.create(
50
- content_type=extra_content_type,
51
- object_id=obj.id,
52
- content_object=obj,
53
- )
47
+ extra_content_type = ContentType.objects.get_for_model(type(extra))
48
+ favorite.extras.create(
49
+ content_type=extra_content_type,
50
+ object_id=extra.id,
51
+ content_object=extra,
52
+ )
54
53
  return favorite
55
54
 
56
55
 
@@ -40,6 +40,49 @@ def store_validation_settings(app_configs, **kwargs):
40
40
  )
41
41
  )
42
42
 
43
- if getattr(settings, "GIFT_PAYMENT_METHOD_PATH", None):
43
+ if hasattr(settings, "GIFT_PAYMENT_METHOD_PATH"):
44
44
  _path_validation(settings.GIFT_PAYMENT_METHOD_PATH)
45
+
46
+ # Favorite validation settings
47
+ if hasattr(settings, "FAVORITE_TYPES"):
48
+ for key, favorite in settings.FAVORITE_TYPES.items():
49
+ if not favorite.get("path"):
50
+ errors.append(
51
+ Error(
52
+ f"Model path should be set for {key}",
53
+ id="store_validation_settings_error",
54
+ )
55
+ )
56
+ else:
57
+ _path_validation(favorite["path"])
58
+ if favorite.get("extras", None):
59
+ for key_extra, extra in favorite["extras"].items():
60
+ if not extra.get("path", None):
61
+ errors.append(
62
+ Error(
63
+ f"Model path should be set for {key}",
64
+ id="store_validation_settings_error",
65
+ )
66
+ )
67
+ else:
68
+ _path_validation(extra["path"])
69
+ if extra.get("type", None) == None:
70
+ errors.append(
71
+ Error(
72
+ f"type must be set for {key_extra}",
73
+ id="store_validation_settings_error",
74
+ )
75
+ )
76
+ else:
77
+ if not (
78
+ hasattr(settings, "SIGNLE_FAVORITE_EXTRA")
79
+ and hasattr(settings, "MULTIPLE_FAVORITE_EXTRA")
80
+ ):
81
+ errors.append(
82
+ Error(
83
+ f"SIGNLE_FAVORITE_EXTRA and MULTIPLE_FAVORITE_EXTRA must be set",
84
+ id="store_validation_settings_error",
85
+ )
86
+ )
87
+
45
88
  return errors
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ob-dj-store
3
- Version: 0.0.12
3
+ Version: 0.0.12.2
4
4
  Summary: OBytes django application for managing ecommerce stores.
5
5
  Home-page: https://www.obytes.com/
6
6
  Author: OBytes
@@ -3,7 +3,7 @@ ob_dj_store/apis/stores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
3
3
  ob_dj_store/apis/stores/filters.py,sha256=18Sb8Id1mgCC0zAzTOQRfBaS7bkyD_sgM8_jAbf1ulE,6349
4
4
  ob_dj_store/apis/stores/urls.py,sha256=cPForgFpOgOGCUVAk6DZcZ7qOooMf1zpDIr1BA0L_8A,1593
5
5
  ob_dj_store/apis/stores/views.py,sha256=0MTOaEHAFR4nKKjOc_bdpo93sYHkp2JvkX7hRlK3GNs,31701
6
- ob_dj_store/apis/stores/rest/serializers/serializers.py,sha256=-w5KQ24UHGFI-Zp0ix3ALrjLiVaGpllOrOcu1em5fig,37731
6
+ ob_dj_store/apis/stores/rest/serializers/serializers.py,sha256=b3Gka1WflitjxN6Gp-8BD1gKlCouQDZtrZOt2crFd38,38966
7
7
  ob_dj_store/apis/tap/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  ob_dj_store/apis/tap/serializers.py,sha256=KPrBK4h2-fWvEVf6vOj2ww5-USV9WqpyYicIqoHIiXI,1065
9
9
  ob_dj_store/apis/tap/urls.py,sha256=bnOTv6an11kxpo_FdqlhsizlGPLVpNxBjCyKcf3_C9M,367
@@ -15,7 +15,7 @@ ob_dj_store/core/stores/admin_inlines.py,sha256=SLj8mMa-Sc3oP693R0W9c3Ocyk7eb34I
15
15
  ob_dj_store/core/stores/apps.py,sha256=ZadmEER_dNcQTH617b3fAsYZJSyRw0g46Kjp4eOAsOU,498
16
16
  ob_dj_store/core/stores/managers.py,sha256=6fCyTGgRnZshTri9UdEFlAPv3lKjyMllK0BG-OqUwOs,6804
17
17
  ob_dj_store/core/stores/receivers.py,sha256=PCe40N6S31fTiGGty94LC-CIUQsBoxRlZiTxxCaYlHU,3611
18
- ob_dj_store/core/stores/settings_validation.py,sha256=iz1VAYXZ5nU2L2NhhntKhaTkp_JzBzOvBqc-wAT_b7Y,1254
18
+ ob_dj_store/core/stores/settings_validation.py,sha256=T_gQ2WbQlG7lqu3XgqiCZ9mqfSN4tlijdRG7efcDmkA,3123
19
19
  ob_dj_store/core/stores/utils.py,sha256=_FwZEIwKdfj3CuYHCz3wKqq5TBb8xak7UiiCB1oggKc,1850
20
20
  ob_dj_store/core/stores/gateway/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  ob_dj_store/core/stores/gateway/tap/__init__.py,sha256=5Z6azpb6tmr1nRvKwQWzlYw9ruvw-9ZMBWRqEngDKTM,40
@@ -101,7 +101,7 @@ ob_dj_store/core/stores/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
101
101
  ob_dj_store/core/stores/models/__init__.py,sha256=fNB_sn6HM6EmTp_Z-Q7KXD8HDWVjG3qlayrWqvygvbw,1617
102
102
  ob_dj_store/core/stores/models/_address.py,sha256=qS5TQ9Z12zx_4CrrHvG8PoYVkdiOq_MtbKR14WKh3Hw,1661
103
103
  ob_dj_store/core/stores/models/_cart.py,sha256=qgjg5MXTMRIZRJJDx5BQ1pa9__ylfrnYMMRGbB2R53c,4555
104
- ob_dj_store/core/stores/models/_favorite.py,sha256=bpXlFBNK8jsQkZG1RiDAbNTNSoVP0NOUUxZI8c46QzI,2561
104
+ ob_dj_store/core/stores/models/_favorite.py,sha256=IA3p4u_-U0KcpofFMSkcuNWaI7C1hFkFdgMwQYYZGzw,2513
105
105
  ob_dj_store/core/stores/models/_feedback.py,sha256=eCUVgprNK5hSRKOS4M_pdR7QH2-rqhoYevlpykhCOLg,1472
106
106
  ob_dj_store/core/stores/models/_inventory.py,sha256=vAXSpCyUdYDIWgUEUUObQfhAcCcQO6j6zATrHf5dPuQ,3928
107
107
  ob_dj_store/core/stores/models/_order.py,sha256=lizkG-HEsxsC7Xasi5nnAtUnBL4riXezR48LblX-Zsk,8246
@@ -113,7 +113,7 @@ ob_dj_store/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
113
113
  ob_dj_store/utils/helpers.py,sha256=FtXXJOD2PILqZTyuf80bmf0KuWW64hxbJG6naJdxI5w,1607
114
114
  ob_dj_store/utils/model.py,sha256=DV7hOhTaZL3gh9sptts2jTUFlTArKG3i7oPioq9HLFE,303
115
115
  ob_dj_store/utils/utils.py,sha256=8UVAFB56qUSjJJ5f9vnermtw638gdFy4CFRCuMbns_M,1342
116
- ob_dj_store-0.0.12.dist-info/METADATA,sha256=krJMaAhSkUXwpHngiQUPwRwwJdey-Kdy2Yf1Cseafww,2825
117
- ob_dj_store-0.0.12.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
118
- ob_dj_store-0.0.12.dist-info/top_level.txt,sha256=CZG3G0ptTkzGnc0dFYN-ZD7YKdJBmm47bsmGwofD_lk,12
119
- ob_dj_store-0.0.12.dist-info/RECORD,,
116
+ ob_dj_store-0.0.12.2.dist-info/METADATA,sha256=ReVvSLpSZepJmFvkEIOo0tV9ZjtH9JoKpFvx3MDLg-Q,2827
117
+ ob_dj_store-0.0.12.2.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
118
+ ob_dj_store-0.0.12.2.dist-info/top_level.txt,sha256=CZG3G0ptTkzGnc0dFYN-ZD7YKdJBmm47bsmGwofD_lk,12
119
+ ob_dj_store-0.0.12.2.dist-info/RECORD,,