ob-dj-store 0.0.11.3__py3-none-any.whl → 0.0.11.10__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.
- ob_dj_store/apis/stores/filters.py +33 -18
- ob_dj_store/apis/stores/rest/serializers/serializers.py +129 -53
- ob_dj_store/apis/stores/urls.py +3 -3
- ob_dj_store/apis/stores/views.py +182 -42
- ob_dj_store/core/stores/admin.py +8 -3
- ob_dj_store/core/stores/admin_inlines.py +4 -4
- ob_dj_store/core/stores/gateway/tap/models.py +1 -1
- ob_dj_store/core/stores/gateway/tap/utils.py +4 -4
- ob_dj_store/core/stores/managers.py +8 -6
- ob_dj_store/core/stores/migrations/0056_auto_20230213_2224.py +33 -0
- ob_dj_store/core/stores/migrations/0057_auto_20230214_1724.py +37 -0
- ob_dj_store/core/stores/migrations/0058_attributechoice_is_default.py +18 -0
- ob_dj_store/core/stores/migrations/0059_auto_20230217_2006.py +41 -0
- ob_dj_store/core/stores/migrations/0060_alter_orderitem_product_variant.py +24 -0
- ob_dj_store/core/stores/migrations/0061_auto_20230223_1435.py +28 -0
- ob_dj_store/core/stores/migrations/0062_auto_20230226_2005.py +43 -0
- ob_dj_store/core/stores/migrations/0063_alter_store_payment_methods.py +23 -0
- ob_dj_store/core/stores/migrations/0064_auto_20230228_1814.py +24 -0
- ob_dj_store/core/stores/migrations/0065_auto_20230228_1932.py +34 -0
- ob_dj_store/core/stores/models/_favorite.py +4 -1
- ob_dj_store/core/stores/models/_order.py +4 -2
- ob_dj_store/core/stores/models/_payment.py +31 -11
- ob_dj_store/core/stores/models/_product.py +22 -13
- ob_dj_store/core/stores/models/_store.py +15 -6
- ob_dj_store/core/stores/models/_wallet.py +41 -8
- ob_dj_store/core/stores/receivers.py +79 -4
- ob_dj_store/core/stores/utils.py +12 -6
- ob_dj_store/utils/helpers.py +8 -2
- ob_dj_store/utils/utils.py +43 -3
- {ob_dj_store-0.0.11.3.dist-info → ob_dj_store-0.0.11.10.dist-info}/METADATA +1 -1
- {ob_dj_store-0.0.11.3.dist-info → ob_dj_store-0.0.11.10.dist-info}/RECORD +33 -23
- {ob_dj_store-0.0.11.3.dist-info → ob_dj_store-0.0.11.10.dist-info}/WHEEL +0 -0
- {ob_dj_store-0.0.11.3.dist-info → ob_dj_store-0.0.11.10.dist-info}/top_level.txt +0 -0
@@ -5,10 +5,12 @@ from django.utils.timezone import now
|
|
5
5
|
from django_filters import rest_framework as filters
|
6
6
|
from rest_framework.exceptions import ValidationError
|
7
7
|
|
8
|
+
from config import settings as store_settings
|
8
9
|
from ob_dj_store.core.stores.models import (
|
9
10
|
Category,
|
10
11
|
Favorite,
|
11
12
|
Order,
|
13
|
+
PaymentMethod,
|
12
14
|
Product,
|
13
15
|
ProductVariant,
|
14
16
|
Store,
|
@@ -72,7 +74,6 @@ class StoreFilter(filters.FilterSet):
|
|
72
74
|
class ProductFilter(filters.FilterSet):
|
73
75
|
"""Product filters"""
|
74
76
|
|
75
|
-
store = filters.CharFilter(method="by_store")
|
76
77
|
category = filters.CharFilter(method="by_category")
|
77
78
|
|
78
79
|
class Meta:
|
@@ -80,20 +81,9 @@ class ProductFilter(filters.FilterSet):
|
|
80
81
|
fields = [
|
81
82
|
"is_featured",
|
82
83
|
"type",
|
83
|
-
"store",
|
84
84
|
"category",
|
85
85
|
]
|
86
86
|
|
87
|
-
def by_store(self, queryset, name, value):
|
88
|
-
return queryset.prefetch_related(
|
89
|
-
Prefetch(
|
90
|
-
"products",
|
91
|
-
queryset=Product.objects.filter(
|
92
|
-
product_variants__inventories__store=value
|
93
|
-
),
|
94
|
-
)
|
95
|
-
).filter(product_variants__inventories__store=value)
|
96
|
-
|
97
87
|
def by_category(self, queryset, name, value):
|
98
88
|
return queryset.filter(category__name__iexact=value)
|
99
89
|
|
@@ -123,22 +113,25 @@ class CategoryFilter(filters.FilterSet):
|
|
123
113
|
|
124
114
|
def by_store(self, queryset, name, value):
|
125
115
|
return (
|
126
|
-
queryset.
|
116
|
+
queryset.filter(
|
117
|
+
subcategories__products__product_variants__inventories__store=value
|
118
|
+
)
|
119
|
+
.prefetch_related(
|
127
120
|
Prefetch(
|
128
121
|
"subcategories",
|
129
|
-
queryset=Category.objects.
|
130
|
-
|
131
|
-
),
|
122
|
+
queryset=Category.objects.filter(
|
123
|
+
products__product_variants__inventories__store=value
|
124
|
+
).distinct(),
|
132
125
|
),
|
133
126
|
Prefetch(
|
134
127
|
"subcategories__products",
|
135
128
|
queryset=Product.objects.filter(
|
136
129
|
product_variants__inventories__store=value,
|
137
130
|
is_active=True,
|
138
|
-
),
|
131
|
+
).distinct(),
|
139
132
|
),
|
133
|
+
"subcategories__products__images",
|
140
134
|
)
|
141
|
-
.filter(subcategories__products__product_variants__inventories__store=value)
|
142
135
|
.distinct()
|
143
136
|
)
|
144
137
|
|
@@ -184,3 +177,25 @@ class FavoriteFilter(filters.FilterSet):
|
|
184
177
|
content_type=content_type,
|
185
178
|
object_id__in=products_ids,
|
186
179
|
)
|
180
|
+
|
181
|
+
|
182
|
+
class PaymentMethodFilter(filters.FilterSet):
|
183
|
+
store = filters.CharFilter(method="by_store")
|
184
|
+
is_digital = filters.BooleanFilter(method="by_digital")
|
185
|
+
|
186
|
+
class Meta:
|
187
|
+
models = PaymentMethod
|
188
|
+
|
189
|
+
def by_store(self, queryset, name, value):
|
190
|
+
return queryset.filter(stores=value)
|
191
|
+
|
192
|
+
def by_digital(self, queryset, name, value):
|
193
|
+
if value:
|
194
|
+
return queryset.filter(
|
195
|
+
payment_provider__in=[
|
196
|
+
store_settings.TAP_CREDIT_CARD,
|
197
|
+
store_settings.TAP_KNET,
|
198
|
+
store_settings.TAP_ALL,
|
199
|
+
]
|
200
|
+
)
|
201
|
+
return queryset
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import calendar
|
2
|
+
import sys
|
2
3
|
import typing
|
3
4
|
from datetime import time, timedelta
|
4
5
|
|
@@ -38,6 +39,7 @@ from ob_dj_store.core.stores.models import (
|
|
38
39
|
ShippingMethod,
|
39
40
|
Store,
|
40
41
|
Tax,
|
42
|
+
Wallet,
|
41
43
|
)
|
42
44
|
from ob_dj_store.core.stores.models._inventory import Inventory
|
43
45
|
from ob_dj_store.core.stores.utils import distance
|
@@ -50,6 +52,7 @@ class AttributeChoiceSerializer(serializers.ModelSerializer):
|
|
50
52
|
"id",
|
51
53
|
"name",
|
52
54
|
"price",
|
55
|
+
"is_default",
|
53
56
|
)
|
54
57
|
|
55
58
|
|
@@ -68,19 +71,22 @@ class AttributeSerializer(serializers.ModelSerializer):
|
|
68
71
|
class InventoryValidationMixin:
|
69
72
|
def validate(self, attrs: typing.Dict) -> typing.Dict:
|
70
73
|
validated_data = super().validate(attrs)
|
71
|
-
|
72
|
-
|
73
|
-
raise serializers.ValidationError(_("Quantity must be greater than 0."))
|
74
|
-
# validate quantity in inventory
|
74
|
+
inventory = None
|
75
|
+
try:
|
75
76
|
inventory = validated_data["product_variant"].inventories.get(
|
76
77
|
store=validated_data["store"]
|
77
78
|
)
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
except:
|
80
|
+
raise serializers.ValidationError(_("Product has no inventory"))
|
81
|
+
if validated_data["quantity"] < 1:
|
82
|
+
raise serializers.ValidationError(_("Quantity must be greater than 0."))
|
83
|
+
# validate quantity in inventory
|
84
|
+
if not inventory.is_uncountable:
|
85
|
+
stock_quantity = inventory.quantity
|
86
|
+
if validated_data["quantity"] > stock_quantity:
|
87
|
+
raise serializers.ValidationError(
|
88
|
+
_("Quantity is greater than the stock quantity.")
|
89
|
+
)
|
84
90
|
return validated_data
|
85
91
|
|
86
92
|
|
@@ -283,7 +289,7 @@ class OrderSerializer(serializers.ModelSerializer):
|
|
283
289
|
if payment_method:
|
284
290
|
if payment_method.payment_provider == store_settings.WALLET:
|
285
291
|
try:
|
286
|
-
wallet = user.wallets.get(
|
292
|
+
wallet = user.wallets.get(currency=attrs["store"].currency)
|
287
293
|
except ObjectDoesNotExist:
|
288
294
|
raise serializers.ValidationError(
|
289
295
|
{
|
@@ -397,6 +403,8 @@ class ProductAttributeSerializer(serializers.ModelSerializer):
|
|
397
403
|
"is_mandatory",
|
398
404
|
"attribute_choices",
|
399
405
|
"type",
|
406
|
+
"min",
|
407
|
+
"max",
|
400
408
|
)
|
401
409
|
|
402
410
|
|
@@ -427,6 +435,8 @@ class ProductVariantSerializer(serializers.ModelSerializer):
|
|
427
435
|
|
428
436
|
class CartItemSerializer(InventoryValidationMixin, serializers.ModelSerializer):
|
429
437
|
image = serializers.SerializerMethodField()
|
438
|
+
inventory_quantity = serializers.SerializerMethodField()
|
439
|
+
is_uncountable = serializers.SerializerMethodField()
|
430
440
|
|
431
441
|
class Meta:
|
432
442
|
model = CartItem
|
@@ -442,6 +452,8 @@ class CartItemSerializer(InventoryValidationMixin, serializers.ModelSerializer):
|
|
442
452
|
"extra_infos",
|
443
453
|
"attribute_choices_total_price",
|
444
454
|
"image",
|
455
|
+
"inventory_quantity",
|
456
|
+
"is_uncountable",
|
445
457
|
)
|
446
458
|
extra_kwargs = {
|
447
459
|
"store": {
|
@@ -449,6 +461,16 @@ class CartItemSerializer(InventoryValidationMixin, serializers.ModelSerializer):
|
|
449
461
|
},
|
450
462
|
}
|
451
463
|
|
464
|
+
def get_inventory_quantity(self, obj):
|
465
|
+
if obj.inventory:
|
466
|
+
return obj.inventory.quantity
|
467
|
+
return None
|
468
|
+
|
469
|
+
def get_is_uncountable(self, obj):
|
470
|
+
if obj.inventory:
|
471
|
+
return obj.inventory.is_uncountable
|
472
|
+
return None
|
473
|
+
|
452
474
|
def validate(self, attrs: typing.Dict) -> typing.Dict:
|
453
475
|
return super(CartItemSerializer, self).validate(attrs)
|
454
476
|
|
@@ -515,9 +537,16 @@ class CartSerializer(serializers.ModelSerializer):
|
|
515
537
|
cart_item.save()
|
516
538
|
return instance
|
517
539
|
|
540
|
+
def to_representation(self, instance):
|
541
|
+
data = super().to_representation(instance)
|
542
|
+
stores = Store.objects.filter(store_items__cart=instance)
|
543
|
+
data["store"] = StoreSerializer(stores, many=True, context=self.context).data
|
544
|
+
return data
|
545
|
+
|
518
546
|
|
519
547
|
class ProductMediaSerializer(serializers.ModelSerializer):
|
520
|
-
|
548
|
+
image_thumbnail_medium = serializers.ImageField(read_only=True)
|
549
|
+
image_thumbnail_small = serializers.ImageField(read_only=True)
|
521
550
|
|
522
551
|
class Meta:
|
523
552
|
model = ProductMedia
|
@@ -525,7 +554,8 @@ class ProductMediaSerializer(serializers.ModelSerializer):
|
|
525
554
|
"id",
|
526
555
|
"is_primary",
|
527
556
|
"image",
|
528
|
-
"
|
557
|
+
"image_thumbnail_small",
|
558
|
+
"image_thumbnail_medium",
|
529
559
|
"order_value",
|
530
560
|
)
|
531
561
|
|
@@ -574,8 +604,8 @@ class ProductSerializer(FavoriteMixin, serializers.ModelSerializer):
|
|
574
604
|
return data
|
575
605
|
|
576
606
|
|
577
|
-
class ProductListSerializer(
|
578
|
-
|
607
|
+
class ProductListSerializer(serializers.ModelSerializer):
|
608
|
+
product_images = ProductMediaSerializer(many=True, source="images")
|
579
609
|
|
580
610
|
class Meta:
|
581
611
|
model = Product
|
@@ -585,15 +615,14 @@ class ProductListSerializer(ProductSerializer):
|
|
585
615
|
"slug",
|
586
616
|
"description",
|
587
617
|
"product_images",
|
588
|
-
"product_variants",
|
589
618
|
"type",
|
590
|
-
"default_variant",
|
591
619
|
)
|
592
620
|
|
593
621
|
|
594
622
|
class SubCategorySerializer(serializers.ModelSerializer):
|
595
623
|
products = ProductListSerializer(many=True)
|
596
|
-
|
624
|
+
image_thumbnail_medium = serializers.ImageField(read_only=True)
|
625
|
+
image_thumbnail_small = serializers.ImageField(read_only=True)
|
597
626
|
|
598
627
|
class Meta:
|
599
628
|
model = Category
|
@@ -604,12 +633,13 @@ class SubCategorySerializer(serializers.ModelSerializer):
|
|
604
633
|
"is_active",
|
605
634
|
"products",
|
606
635
|
"image",
|
607
|
-
"
|
636
|
+
"image_thumbnail_medium",
|
637
|
+
"image_thumbnail_small",
|
638
|
+
"parent",
|
608
639
|
)
|
609
640
|
|
610
641
|
def to_representation(self, instance):
|
611
642
|
data = super().to_representation(instance)
|
612
|
-
data["parent_id"] = instance.parent.id if instance.parent else None
|
613
643
|
return data
|
614
644
|
|
615
645
|
|
@@ -627,6 +657,9 @@ class CategorySerializer(serializers.ModelSerializer):
|
|
627
657
|
"is_active",
|
628
658
|
"subcategories",
|
629
659
|
"parent",
|
660
|
+
"image",
|
661
|
+
"image_thumbnail_medium",
|
662
|
+
"image_thumbnail_small",
|
630
663
|
)
|
631
664
|
|
632
665
|
|
@@ -765,9 +798,7 @@ class StoreSerializer(FavoriteMixin, serializers.ModelSerializer):
|
|
765
798
|
|
766
799
|
def get_is_closed(self, obj):
|
767
800
|
current_time = now()
|
768
|
-
current_op_hour = obj.
|
769
|
-
weekday=current_time.weekday() + 1
|
770
|
-
).first()
|
801
|
+
current_op_hour = obj.current_opening_hours
|
771
802
|
if current_op_hour:
|
772
803
|
return (
|
773
804
|
not current_op_hour.from_hour
|
@@ -781,10 +812,11 @@ class StoreSerializer(FavoriteMixin, serializers.ModelSerializer):
|
|
781
812
|
in_range_method = obj.shipping_methods.filter(
|
782
813
|
type=ShippingMethod.ShippingType.DELIVERY
|
783
814
|
).exists()
|
784
|
-
if
|
815
|
+
if not in_range_method:
|
816
|
+
return True
|
817
|
+
if user_location and obj.poly:
|
785
818
|
long, lat = user_location.split(",")
|
786
819
|
return obj.poly.contains(Point(float(long), float(lat)))
|
787
|
-
return False
|
788
820
|
|
789
821
|
def get_opening_hours(self, obj):
|
790
822
|
opening_hours = sorted(
|
@@ -838,9 +870,7 @@ class StoreSerializer(FavoriteMixin, serializers.ModelSerializer):
|
|
838
870
|
return PhoneContactSerializer(phone_contacts, many=True).data
|
839
871
|
|
840
872
|
def get_current_day_opening_hours(self, obj):
|
841
|
-
current_opening_hours = obj.
|
842
|
-
weekday=now().weekday() + 1
|
843
|
-
).first()
|
873
|
+
current_opening_hours = obj.current_opening_hours
|
844
874
|
op_hour = {}
|
845
875
|
if current_opening_hours:
|
846
876
|
op_hour["from_hour"] = current_opening_hours.from_hour.strftime("%I:%M%p")
|
@@ -851,15 +881,7 @@ class StoreSerializer(FavoriteMixin, serializers.ModelSerializer):
|
|
851
881
|
return op_hour
|
852
882
|
|
853
883
|
def to_representation(self, instance):
|
854
|
-
|
855
|
-
view = self.context.get("view")
|
856
|
-
if view:
|
857
|
-
if view.action != "retrieve":
|
858
|
-
return data
|
859
|
-
data["inventories"] = InventorySerializer(
|
860
|
-
instance.inventories.all(), many=True
|
861
|
-
).data
|
862
|
-
return data
|
884
|
+
return super().to_representation(instance)
|
863
885
|
|
864
886
|
|
865
887
|
class PaymentMethodSerializer(serializers.ModelSerializer):
|
@@ -899,17 +921,27 @@ class StoreListSerializer(serializers.ModelSerializer):
|
|
899
921
|
|
900
922
|
|
901
923
|
class GenericSerializer(serializers.Serializer):
|
924
|
+
"""
|
925
|
+
A generic serializer that automatically selects the appropriate serializer
|
926
|
+
for a given instance.
|
927
|
+
|
928
|
+
The `to_representation` method uses the `get_serializer_for_instance` method
|
929
|
+
to determine which serializer to use for a given instance. If the serializer
|
930
|
+
class is found, it returns the representation of the instance using that
|
931
|
+
serializer. Otherwise, it raises a `NameError`.
|
932
|
+
"""
|
933
|
+
|
902
934
|
def to_representation(self, value):
|
903
935
|
context = self.context
|
904
936
|
serializer_class = self.get_serializer_for_instance(value)
|
905
937
|
return serializer_class(context=context).to_representation(value)
|
906
938
|
|
907
939
|
def get_serializer_for_instance(self, instance):
|
908
|
-
|
909
|
-
|
910
|
-
return
|
911
|
-
|
912
|
-
raise NameError(_(f"name '{
|
940
|
+
serializer_class = instance.__class__.__name__ + "Serializer"
|
941
|
+
if hasattr(sys.modules[__name__], serializer_class):
|
942
|
+
return getattr(sys.modules[__name__], serializer_class)
|
943
|
+
else:
|
944
|
+
raise NameError(_(f"name '{serializer_class}' is not defined"))
|
913
945
|
|
914
946
|
|
915
947
|
class FavoriteExtraSerializer(serializers.ModelSerializer):
|
@@ -945,7 +977,11 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
945
977
|
"extras",
|
946
978
|
"object_id",
|
947
979
|
"object_type",
|
980
|
+
"name",
|
948
981
|
)
|
982
|
+
extra_kwargs = {
|
983
|
+
"name": {"required": True},
|
984
|
+
}
|
949
985
|
|
950
986
|
def _lookup_validation(self, data):
|
951
987
|
content_type = ContentType.objects.get_for_model(type(data["content_object"]))
|
@@ -956,6 +992,7 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
956
992
|
queryset = Favorite.objects.filter(
|
957
993
|
content_type=content_type,
|
958
994
|
object_id=data["content_object"].id,
|
995
|
+
user=self.context["request"].user,
|
959
996
|
)
|
960
997
|
for key in extras_lookup_content_type.keys():
|
961
998
|
queryset = queryset.filter(
|
@@ -971,13 +1008,17 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
971
1008
|
|
972
1009
|
def validate(self, attrs):
|
973
1010
|
validated_data = super().validate(attrs)
|
1011
|
+
name = validated_data["name"]
|
974
1012
|
object_type = validated_data["object_type"]
|
975
|
-
if object_type not in store_settings.FAVORITE_TYPES
|
1013
|
+
if object_type not in store_settings.FAVORITE_TYPES and hasattr(
|
1014
|
+
sys.modules[__name__], object_type
|
1015
|
+
):
|
976
1016
|
raise serializers.ValidationError(
|
977
1017
|
_(f"Cannot resolve keyword '{object_type}' into an object type")
|
978
1018
|
)
|
1019
|
+
object_type_model = getattr(sys.modules[__name__], object_type)
|
979
1020
|
object_instance = get_object_or_404(
|
980
|
-
|
1021
|
+
object_type_model, pk=validated_data["object_id"]
|
981
1022
|
)
|
982
1023
|
extras_data = {}
|
983
1024
|
extras = []
|
@@ -993,24 +1034,59 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
993
1034
|
extras_data[extra_object_type].append(extra["object_id"])
|
994
1035
|
try:
|
995
1036
|
for key in extras_data.keys():
|
996
|
-
model_class =
|
997
|
-
|
1037
|
+
model_class = getattr(sys.modules[__name__], key, None)
|
1038
|
+
if model_class:
|
1039
|
+
extras.append(model_class.objects.filter(id__in=extras_data[key]))
|
998
1040
|
except ObjectDoesNotExist:
|
999
1041
|
raise serializers.ValidationError(_("No matches the given query."))
|
1000
|
-
except NameError as e:
|
1001
|
-
raise NameError(e)
|
1002
1042
|
|
1003
1043
|
validated_data = {
|
1004
1044
|
"content_object": object_instance,
|
1005
1045
|
"extras": extras,
|
1046
|
+
"name": name,
|
1006
1047
|
}
|
1007
1048
|
self._lookup_validation(validated_data)
|
1008
1049
|
return validated_data
|
1009
1050
|
|
1010
1051
|
def create(self, validated_data):
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1052
|
+
try:
|
1053
|
+
favorite = Favorite.add_favorite(
|
1054
|
+
content_object=validated_data["content_object"],
|
1055
|
+
user=self.context["request"].user,
|
1056
|
+
name=validated_data["name"],
|
1057
|
+
extras=validated_data["extras"],
|
1058
|
+
)
|
1059
|
+
except ValidationError as e:
|
1060
|
+
raise serializers.ValidationError(detail=e.message_dict)
|
1016
1061
|
return favorite
|
1062
|
+
|
1063
|
+
|
1064
|
+
class WalletSerializer(serializers.ModelSerializer):
|
1065
|
+
class Meta:
|
1066
|
+
model = Wallet
|
1067
|
+
fields = ["id", "user", "balance", "name", "image", "image_thumbnail_medium"]
|
1068
|
+
extra_kwargs = {
|
1069
|
+
"user": {"read_only": True},
|
1070
|
+
"image_thumbnail_medium": {"read_only": True},
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
|
1074
|
+
class WalletTopUpSerializer(serializers.Serializer):
|
1075
|
+
amount = serializers.DecimalField(
|
1076
|
+
max_digits=10, decimal_places=2, min_value=1, required=True
|
1077
|
+
)
|
1078
|
+
payment_method = serializers.PrimaryKeyRelatedField(
|
1079
|
+
queryset=PaymentMethod.objects.filter(
|
1080
|
+
payment_provider__in=[
|
1081
|
+
store_settings.TAP_CREDIT_CARD,
|
1082
|
+
store_settings.TAP_KNET,
|
1083
|
+
store_settings.TAP_ALL,
|
1084
|
+
]
|
1085
|
+
),
|
1086
|
+
required=True,
|
1087
|
+
)
|
1088
|
+
|
1089
|
+
def top_up_wallet(self, wallet):
|
1090
|
+
amount = self.validated_data["amount"]
|
1091
|
+
payment_method = self.validated_data["payment_method"]
|
1092
|
+
return wallet.top_up_wallet(amount=amount, payment_method=payment_method)
|
ob_dj_store/apis/stores/urls.py
CHANGED
@@ -16,6 +16,7 @@ from ob_dj_store.apis.stores.views import (
|
|
16
16
|
TaxViewSet,
|
17
17
|
TransactionsViewSet,
|
18
18
|
VariantView,
|
19
|
+
WalletViewSet,
|
19
20
|
)
|
20
21
|
|
21
22
|
app_name = "stores"
|
@@ -28,9 +29,6 @@ stores_router.register(r"order", OrderView, basename="order")
|
|
28
29
|
stores_router.register(r"product", ProductView, basename="product")
|
29
30
|
stores_router.register(r"variant", VariantView, basename="variant")
|
30
31
|
stores_router.register(r"inventory", InventoryView, basename="inventory")
|
31
|
-
stores_router.register(
|
32
|
-
r"payment-method", PaymentMethodViewSet, basename="payment-method"
|
33
|
-
)
|
34
32
|
stores_router.register(
|
35
33
|
r"shipping-method", ShippingMethodViewSet, basename="shipping-method"
|
36
34
|
)
|
@@ -40,6 +38,8 @@ router.register(r"transaction", TransactionsViewSet, basename="transaction")
|
|
40
38
|
router.register(r"cart", CartView, basename="cart")
|
41
39
|
router.register(r"cart-item", CartItemView, basename="cart-item")
|
42
40
|
router.register(r"favorite", FavoriteViewSet, basename="favorite")
|
41
|
+
router.register(r"wallet", WalletViewSet, basename="wallet")
|
42
|
+
router.register(r"payment-method", PaymentMethodViewSet, basename="payment-method")
|
43
43
|
urlpatterns = [
|
44
44
|
path(r"", include(router.urls)),
|
45
45
|
path(r"", include(stores_router.urls)),
|