ob-dj-store 0.0.11.8__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 +25 -0
- ob_dj_store/apis/stores/rest/serializers/serializers.py +51 -7
- ob_dj_store/apis/stores/urls.py +3 -3
- ob_dj_store/apis/stores/views.py +92 -31
- ob_dj_store/core/stores/admin.py +6 -6
- 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/managers.py +1 -3
- 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 +2 -0
- ob_dj_store/core/stores/models/_payment.py +31 -11
- ob_dj_store/core/stores/models/_product.py +3 -5
- ob_dj_store/core/stores/models/_store.py +9 -8
- ob_dj_store/core/stores/models/_wallet.py +41 -8
- ob_dj_store/core/stores/receivers.py +62 -8
- ob_dj_store/core/stores/utils.py +14 -6
- ob_dj_store/utils/helpers.py +7 -1
- ob_dj_store/utils/utils.py +3 -2
- {ob_dj_store-0.0.11.8.dist-info → ob_dj_store-0.0.11.10.dist-info}/METADATA +1 -1
- {ob_dj_store-0.0.11.8.dist-info → ob_dj_store-0.0.11.10.dist-info}/RECORD +26 -22
- {ob_dj_store-0.0.11.8.dist-info → ob_dj_store-0.0.11.10.dist-info}/WHEEL +0 -0
- {ob_dj_store-0.0.11.8.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,
|
@@ -128,6 +130,7 @@ class CategoryFilter(filters.FilterSet):
|
|
128
130
|
is_active=True,
|
129
131
|
).distinct(),
|
130
132
|
),
|
133
|
+
"subcategories__products__images",
|
131
134
|
)
|
132
135
|
.distinct()
|
133
136
|
)
|
@@ -174,3 +177,25 @@ class FavoriteFilter(filters.FilterSet):
|
|
174
177
|
content_type=content_type,
|
175
178
|
object_id__in=products_ids,
|
176
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
|
@@ -39,6 +39,7 @@ from ob_dj_store.core.stores.models import (
|
|
39
39
|
ShippingMethod,
|
40
40
|
Store,
|
41
41
|
Tax,
|
42
|
+
Wallet,
|
42
43
|
)
|
43
44
|
from ob_dj_store.core.stores.models._inventory import Inventory
|
44
45
|
from ob_dj_store.core.stores.utils import distance
|
@@ -288,7 +289,7 @@ class OrderSerializer(serializers.ModelSerializer):
|
|
288
289
|
if payment_method:
|
289
290
|
if payment_method.payment_provider == store_settings.WALLET:
|
290
291
|
try:
|
291
|
-
wallet = user.wallets.get(
|
292
|
+
wallet = user.wallets.get(currency=attrs["store"].currency)
|
292
293
|
except ObjectDoesNotExist:
|
293
294
|
raise serializers.ValidationError(
|
294
295
|
{
|
@@ -603,7 +604,9 @@ class ProductSerializer(FavoriteMixin, serializers.ModelSerializer):
|
|
603
604
|
return data
|
604
605
|
|
605
606
|
|
606
|
-
class ProductListSerializer(
|
607
|
+
class ProductListSerializer(serializers.ModelSerializer):
|
608
|
+
product_images = ProductMediaSerializer(many=True, source="images")
|
609
|
+
|
607
610
|
class Meta:
|
608
611
|
model = Product
|
609
612
|
fields = (
|
@@ -974,7 +977,11 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
974
977
|
"extras",
|
975
978
|
"object_id",
|
976
979
|
"object_type",
|
980
|
+
"name",
|
977
981
|
)
|
982
|
+
extra_kwargs = {
|
983
|
+
"name": {"required": True},
|
984
|
+
}
|
978
985
|
|
979
986
|
def _lookup_validation(self, data):
|
980
987
|
content_type = ContentType.objects.get_for_model(type(data["content_object"]))
|
@@ -1001,6 +1008,7 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
1001
1008
|
|
1002
1009
|
def validate(self, attrs):
|
1003
1010
|
validated_data = super().validate(attrs)
|
1011
|
+
name = validated_data["name"]
|
1004
1012
|
object_type = validated_data["object_type"]
|
1005
1013
|
if object_type not in store_settings.FAVORITE_TYPES and hasattr(
|
1006
1014
|
sys.modules[__name__], object_type
|
@@ -1035,14 +1043,50 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
1035
1043
|
validated_data = {
|
1036
1044
|
"content_object": object_instance,
|
1037
1045
|
"extras": extras,
|
1046
|
+
"name": name,
|
1038
1047
|
}
|
1039
1048
|
self._lookup_validation(validated_data)
|
1040
1049
|
return validated_data
|
1041
1050
|
|
1042
1051
|
def create(self, validated_data):
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
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)
|
1048
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)),
|
ob_dj_store/apis/stores/views.py
CHANGED
@@ -26,6 +26,7 @@ from ob_dj_store.apis.stores.filters import (
|
|
26
26
|
FavoriteFilter,
|
27
27
|
InventoryFilter,
|
28
28
|
OrderFilter,
|
29
|
+
PaymentMethodFilter,
|
29
30
|
ProductFilter,
|
30
31
|
StoreFilter,
|
31
32
|
VariantFilter,
|
@@ -47,6 +48,8 @@ from ob_dj_store.apis.stores.rest.serializers.serializers import (
|
|
47
48
|
ShippingMethodSerializer,
|
48
49
|
StoreSerializer,
|
49
50
|
TaxSerializer,
|
51
|
+
WalletSerializer,
|
52
|
+
WalletTopUpSerializer,
|
50
53
|
)
|
51
54
|
from ob_dj_store.core.stores.models import (
|
52
55
|
Cart,
|
@@ -62,6 +65,7 @@ from ob_dj_store.core.stores.models import (
|
|
62
65
|
ShippingMethod,
|
63
66
|
Store,
|
64
67
|
Tax,
|
68
|
+
Wallet,
|
65
69
|
)
|
66
70
|
from ob_dj_store.core.stores.models._inventory import Inventory
|
67
71
|
|
@@ -188,29 +192,6 @@ class StoreView(
|
|
188
192
|
serializer = self.get_serializer(page, many=True)
|
189
193
|
return self.get_paginated_response(serializer.data)
|
190
194
|
|
191
|
-
@swagger_auto_schema(
|
192
|
-
operation_summary="Add or Remove Store from Favorites",
|
193
|
-
operation_description="""
|
194
|
-
Add or Remove Store from Favorites
|
195
|
-
""",
|
196
|
-
tags=[
|
197
|
-
"Store",
|
198
|
-
],
|
199
|
-
)
|
200
|
-
@action(
|
201
|
-
detail=True,
|
202
|
-
methods=["GET"],
|
203
|
-
url_path="favorite",
|
204
|
-
)
|
205
|
-
def favorite(self, request, *args, **kwargs):
|
206
|
-
instance = self.get_object()
|
207
|
-
try:
|
208
|
-
Favorite.objects.favorite_for_user(instance, request.user).delete()
|
209
|
-
except Favorite.DoesNotExist:
|
210
|
-
Favorite.add_favorite(instance, request.user)
|
211
|
-
serializer = StoreSerializer(instance=instance, context={"request": request})
|
212
|
-
return Response(serializer.data)
|
213
|
-
|
214
195
|
@swagger_auto_schema(
|
215
196
|
operation_summary="Retrieve count of store's products",
|
216
197
|
operation_description="""
|
@@ -674,6 +655,9 @@ class CategoryViewSet(
|
|
674
655
|
filterset_class = CategoryFilter
|
675
656
|
lookup_value_regex = "[0-9]+"
|
676
657
|
|
658
|
+
def get_queryset(self):
|
659
|
+
return super().get_queryset().prefetch_related("products__images")
|
660
|
+
|
677
661
|
def get_object(self):
|
678
662
|
store_id = self.request.query_params.get("store", None)
|
679
663
|
instance_pk = self.kwargs["pk"]
|
@@ -699,6 +683,7 @@ class CategoryViewSet(
|
|
699
683
|
"products",
|
700
684
|
queryset=product_queryset.distinct(),
|
701
685
|
),
|
686
|
+
"subcategories__products__images",
|
702
687
|
).get(pk=instance_pk)
|
703
688
|
except Category.DoesNotExist:
|
704
689
|
raise Http404("No Category matches the given query.")
|
@@ -800,14 +785,9 @@ class PaymentMethodViewSet(
|
|
800
785
|
permission_classes = [
|
801
786
|
permissions.IsAuthenticated,
|
802
787
|
]
|
803
|
-
queryset = PaymentMethod.objects.
|
804
|
-
|
805
|
-
|
806
|
-
try:
|
807
|
-
store = Store.objects.get(pk=self.kwargs["store_pk"])
|
808
|
-
except ObjectDoesNotExist:
|
809
|
-
raise ValidationError(_(f"Store does not Exist"))
|
810
|
-
return store.payment_methods.filter(is_active=True)
|
788
|
+
queryset = PaymentMethod.objects.filter(is_active=True)
|
789
|
+
filterset_class = PaymentMethodFilter
|
790
|
+
lookup_value_regex = "[0-9]+"
|
811
791
|
|
812
792
|
@swagger_auto_schema(
|
813
793
|
operation_summary="List Payment Methods",
|
@@ -949,3 +929,84 @@ class FavoriteViewSet(
|
|
949
929
|
)
|
950
930
|
def destroy(self, request, *args, **kwargs):
|
951
931
|
return super().destroy(request, *args, **kwargs)
|
932
|
+
|
933
|
+
|
934
|
+
class WalletViewSet(
|
935
|
+
mixins.ListModelMixin,
|
936
|
+
mixins.RetrieveModelMixin,
|
937
|
+
mixins.UpdateModelMixin,
|
938
|
+
viewsets.GenericViewSet,
|
939
|
+
):
|
940
|
+
queryset = Wallet.objects.all()
|
941
|
+
serializer_class = WalletSerializer
|
942
|
+
permission_classes = [
|
943
|
+
permissions.IsAuthenticated,
|
944
|
+
]
|
945
|
+
|
946
|
+
def get_queryset(self):
|
947
|
+
return Wallet.objects.filter(user=self.request.user)
|
948
|
+
|
949
|
+
@swagger_auto_schema(
|
950
|
+
operation_summary="Get User Wallet",
|
951
|
+
operation_description="""
|
952
|
+
Get User Wallet
|
953
|
+
""",
|
954
|
+
tags=[
|
955
|
+
"Wallet",
|
956
|
+
],
|
957
|
+
)
|
958
|
+
def retrieve(
|
959
|
+
self, request: Request, *args: typing.Any, **kwargs: typing.Any
|
960
|
+
) -> Response:
|
961
|
+
return super().retrieve(request=request, *args, **kwargs)
|
962
|
+
|
963
|
+
@swagger_auto_schema(
|
964
|
+
operation_summary="Update user wallet",
|
965
|
+
operation_description="""
|
966
|
+
Update a wallet
|
967
|
+
""",
|
968
|
+
tags=[
|
969
|
+
"Wallet",
|
970
|
+
],
|
971
|
+
)
|
972
|
+
def partial_update(self, request: Request, *args: typing.Any, **kwargs: typing.Any):
|
973
|
+
return super().partial_update(request, *args, **kwargs)
|
974
|
+
|
975
|
+
@swagger_auto_schema(
|
976
|
+
operation_summary="List User Wallets",
|
977
|
+
operation_description="""
|
978
|
+
List User Wallets
|
979
|
+
""",
|
980
|
+
tags=[
|
981
|
+
"Wallet",
|
982
|
+
],
|
983
|
+
)
|
984
|
+
def list(
|
985
|
+
self, request: Request, *args: typing.Any, **kwargs: typing.Any
|
986
|
+
) -> Response:
|
987
|
+
return super().list(request=request, *args, **kwargs)
|
988
|
+
|
989
|
+
@swagger_auto_schema(
|
990
|
+
operation_summary="top up a wallet",
|
991
|
+
operation_description="""
|
992
|
+
top up a user wallet with tap payment
|
993
|
+
""",
|
994
|
+
tags=[
|
995
|
+
"Wallet",
|
996
|
+
],
|
997
|
+
)
|
998
|
+
@action(
|
999
|
+
methods=["POST"],
|
1000
|
+
detail=True,
|
1001
|
+
url_path="top-up",
|
1002
|
+
url_name="top-up",
|
1003
|
+
serializer_class=WalletTopUpSerializer,
|
1004
|
+
)
|
1005
|
+
def top_up_wallet(
|
1006
|
+
self, request: Request, *args: typing.Any, **kwargs: typing.Any
|
1007
|
+
) -> Response:
|
1008
|
+
serializer = self.get_serializer(data=request.data)
|
1009
|
+
serializer.is_valid(raise_exception=True)
|
1010
|
+
instance = self.get_object()
|
1011
|
+
payment_url = serializer.top_up_wallet(instance)
|
1012
|
+
return Response({"payment_url": payment_url}, status=status.HTTP_200_OK)
|
ob_dj_store/core/stores/admin.py
CHANGED
@@ -104,12 +104,6 @@ class CategoryAdmin(admin.ModelAdmin):
|
|
104
104
|
"is_active",
|
105
105
|
]
|
106
106
|
|
107
|
-
def save_model(self, request, obj, form, change) -> None:
|
108
|
-
from ob_dj_store.core.stores.receivers import create_media_thumbnails
|
109
|
-
|
110
|
-
create_media_thumbnails(None, obj, None)
|
111
|
-
return super().save_model(request, obj, form, change)
|
112
|
-
|
113
107
|
|
114
108
|
class ProductVariantAdmin(admin.ModelAdmin):
|
115
109
|
inlines = [
|
@@ -122,6 +116,9 @@ class ProductVariantAdmin(admin.ModelAdmin):
|
|
122
116
|
]
|
123
117
|
search_fields = ["name", "product__name", "sku"]
|
124
118
|
|
119
|
+
def get_queryset(self, request):
|
120
|
+
return super().get_queryset(request).prefetch_related("inventories")
|
121
|
+
|
125
122
|
|
126
123
|
class ProductAdmin(admin.ModelAdmin):
|
127
124
|
list_display = ["id", "name", "category", "type", "is_active"]
|
@@ -249,6 +246,9 @@ class InventoryAdmin(admin.ModelAdmin):
|
|
249
246
|
"is_uncountable",
|
250
247
|
]
|
251
248
|
|
249
|
+
def get_queryset(self, request):
|
250
|
+
return super().get_queryset(request).prefetch_related("store")
|
251
|
+
|
252
252
|
|
253
253
|
class TaxAdmin(admin.ModelAdmin):
|
254
254
|
list_display = [
|
@@ -22,10 +22,10 @@ class InventoryInlineAdmin(admin.TabularInline):
|
|
22
22
|
extra = 1
|
23
23
|
|
24
24
|
def get_queryset(self, request):
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
"variant",
|
25
|
+
return (
|
26
|
+
super()
|
27
|
+
.get_queryset(request)
|
28
|
+
.select_related("variant", "store", "variant__product")
|
29
29
|
)
|
30
30
|
|
31
31
|
|
@@ -6,7 +6,6 @@ from django.db import models
|
|
6
6
|
from django.utils.translation import gettext_lazy as _
|
7
7
|
|
8
8
|
from config import settings
|
9
|
-
from ob_dj_store.core.stores.utils import get_country_by_currency
|
10
9
|
|
11
10
|
|
12
11
|
class ActiveMixin:
|
@@ -77,8 +76,7 @@ class PaymentManager(models.Manager):
|
|
77
76
|
return instance
|
78
77
|
elif gateway == settings.WALLET:
|
79
78
|
try:
|
80
|
-
|
81
|
-
wallet = kwargs["user"].wallets.get(country=country)
|
79
|
+
wallet = kwargs["user"].wallets.get(currency=currency)
|
82
80
|
except ObjectDoesNotExist:
|
83
81
|
raise ValidationError({"wallet": _("Wallet Not Found")})
|
84
82
|
WalletTransaction.objects.create(
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Generated by Django 3.2.8 on 2023-02-26 17:05
|
2
|
+
|
3
|
+
from django.conf import settings
|
4
|
+
from django.db import migrations, models
|
5
|
+
|
6
|
+
import ob_dj_store.core.stores.utils
|
7
|
+
|
8
|
+
|
9
|
+
class Migration(migrations.Migration):
|
10
|
+
|
11
|
+
dependencies = [
|
12
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
13
|
+
("stores", "0061_auto_20230223_1435"),
|
14
|
+
]
|
15
|
+
|
16
|
+
operations = [
|
17
|
+
migrations.AddField(
|
18
|
+
model_name="store",
|
19
|
+
name="currency",
|
20
|
+
field=models.CharField(
|
21
|
+
default="KWD",
|
22
|
+
max_length=3,
|
23
|
+
validators=[ob_dj_store.core.stores.utils.validate_currency],
|
24
|
+
),
|
25
|
+
),
|
26
|
+
migrations.AddField(
|
27
|
+
model_name="wallet",
|
28
|
+
name="currency",
|
29
|
+
field=models.CharField(
|
30
|
+
default="KWD",
|
31
|
+
max_length=3,
|
32
|
+
validators=[ob_dj_store.core.stores.utils.validate_currency],
|
33
|
+
),
|
34
|
+
),
|
35
|
+
migrations.AlterUniqueTogether(
|
36
|
+
name="wallet",
|
37
|
+
unique_together={("user", "currency")},
|
38
|
+
),
|
39
|
+
migrations.RemoveField(
|
40
|
+
model_name="wallet",
|
41
|
+
name="country",
|
42
|
+
),
|
43
|
+
]
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Generated by Django 3.2.8 on 2023-02-27 11:15
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
("stores", "0062_auto_20230226_2005"),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AlterField(
|
14
|
+
model_name="store",
|
15
|
+
name="payment_methods",
|
16
|
+
field=models.ManyToManyField(
|
17
|
+
blank=True,
|
18
|
+
help_text="Payment methods within the store",
|
19
|
+
related_name="stores",
|
20
|
+
to="stores.PaymentMethod",
|
21
|
+
),
|
22
|
+
),
|
23
|
+
]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Generated by Django 3.2.8 on 2023-02-28 15:14
|
2
|
+
|
3
|
+
from django.conf import settings
|
4
|
+
from django.db import migrations, models
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
|
9
|
+
dependencies = [
|
10
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
11
|
+
("stores", "0063_alter_store_payment_methods"),
|
12
|
+
]
|
13
|
+
|
14
|
+
operations = [
|
15
|
+
migrations.AddField(
|
16
|
+
model_name="favorite",
|
17
|
+
name="name",
|
18
|
+
field=models.CharField(blank=True, max_length=200, null=True),
|
19
|
+
),
|
20
|
+
migrations.AlterUniqueTogether(
|
21
|
+
name="favorite",
|
22
|
+
unique_together={("name", "user")},
|
23
|
+
),
|
24
|
+
]
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Generated by Django 3.2.8 on 2023-02-28 16:32
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
import ob_dj_store.utils.helpers
|
6
|
+
|
7
|
+
|
8
|
+
class Migration(migrations.Migration):
|
9
|
+
|
10
|
+
dependencies = [
|
11
|
+
("stores", "0064_auto_20230228_1814"),
|
12
|
+
]
|
13
|
+
|
14
|
+
operations = [
|
15
|
+
migrations.AddField(
|
16
|
+
model_name="wallet",
|
17
|
+
name="image",
|
18
|
+
field=models.ImageField(
|
19
|
+
blank=True,
|
20
|
+
null=True,
|
21
|
+
upload_to=ob_dj_store.utils.helpers.wallet_media_upload_to,
|
22
|
+
),
|
23
|
+
),
|
24
|
+
migrations.AddField(
|
25
|
+
model_name="wallet",
|
26
|
+
name="image_thumbnail_medium",
|
27
|
+
field=models.ImageField(blank=True, null=True, upload_to="wallets/"),
|
28
|
+
),
|
29
|
+
migrations.AddField(
|
30
|
+
model_name="wallet",
|
31
|
+
name="name",
|
32
|
+
field=models.CharField(blank=True, max_length=200, null=True),
|
33
|
+
),
|
34
|
+
]
|
@@ -16,6 +16,7 @@ class Favorite(DjangoModelCleanMixin, models.Model):
|
|
16
16
|
user = models.ForeignKey(
|
17
17
|
get_user_model(), related_name="favorites", on_delete=models.CASCADE
|
18
18
|
)
|
19
|
+
name = models.CharField(max_length=200, null=True, blank=True)
|
19
20
|
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
20
21
|
content_object = GenericForeignKey("content_type", "object_id")
|
21
22
|
object_id = models.PositiveIntegerField()
|
@@ -26,18 +27,20 @@ class Favorite(DjangoModelCleanMixin, models.Model):
|
|
26
27
|
class Meta:
|
27
28
|
verbose_name = _("favorite")
|
28
29
|
verbose_name_plural = _("favorites")
|
30
|
+
unique_together = (("name", "user"),)
|
29
31
|
|
30
32
|
def __str__(self):
|
31
33
|
return f"{self.user} favorites {self.content_object}"
|
32
34
|
|
33
35
|
@classmethod
|
34
|
-
def add_favorite(cls, content_object, user, extras=[]):
|
36
|
+
def add_favorite(cls, content_object, user, name, extras=[]):
|
35
37
|
content_type = ContentType.objects.get_for_model(type(content_object))
|
36
38
|
favorite = Favorite(
|
37
39
|
user=user,
|
38
40
|
content_type=content_type,
|
39
41
|
object_id=content_object.pk,
|
40
42
|
content_object=content_object,
|
43
|
+
name=name,
|
41
44
|
)
|
42
45
|
favorite.save()
|
43
46
|
for extra in extras:
|
@@ -119,6 +119,8 @@ class Order(DjangoModelCleanMixin, models.Model):
|
|
119
119
|
|
120
120
|
@property
|
121
121
|
def total_amount(self):
|
122
|
+
if self.type_of_order == Order.OrderType.WALLET.value:
|
123
|
+
return Decimal(self.extra_infos["amount"])
|
122
124
|
amount = Decimal(
|
123
125
|
sum(map(lambda item: Decimal(item.total_amount) or 0, self.items.all()))
|
124
126
|
)
|
@@ -110,17 +110,36 @@ class Payment(models.Model):
|
|
110
110
|
return f"Payment (PK={self.pk})"
|
111
111
|
|
112
112
|
def mark_paid(self):
|
113
|
+
"""
|
114
|
+
mark payment and orders as paid then perform post payment actions
|
115
|
+
if wallet fill up we add wallet transaction to the user
|
116
|
+
if physical order we decrease the quantity from inventory and delete items from cart
|
117
|
+
"""
|
118
|
+
from ob_dj_store.core.stores.models._wallet import WalletTransaction
|
119
|
+
|
113
120
|
self.status = self.PaymentStatus.SUCCESS
|
114
|
-
orders =
|
115
|
-
|
116
|
-
|
121
|
+
orders = self.orders.all()
|
122
|
+
if orders[0].type_of_order == Order.OrderType.WALLET.value:
|
123
|
+
order = orders[0]
|
124
|
+
currency = order.extra_infos["currency"]
|
125
|
+
wallet = self.user.wallets.get(currency=currency)
|
126
|
+
WalletTransaction.objects.create(
|
127
|
+
wallet=wallet,
|
128
|
+
amount=self.amount, # TODO: cunfused about how we hundle if he want to fill up other currency
|
129
|
+
type=WalletTransaction.TYPE.CREDIT,
|
130
|
+
)
|
117
131
|
order.status = Order.OrderStatus.PAID
|
118
|
-
for item in order.items.all():
|
119
|
-
if item.inventory:
|
120
|
-
item.inventory.decrease(item.quantity)
|
121
132
|
order.save()
|
122
|
-
|
123
|
-
|
133
|
+
else:
|
134
|
+
cart = self.user.cart
|
135
|
+
for order in orders:
|
136
|
+
order.status = Order.OrderStatus.PAID
|
137
|
+
for item in order.items.all():
|
138
|
+
if item.inventory:
|
139
|
+
item.inventory.decrease(item.quantity)
|
140
|
+
order.save()
|
141
|
+
items = order.store.store_items.filter(cart=cart)
|
142
|
+
items.delete()
|
124
143
|
self.payment_post_at = timezone.now()
|
125
144
|
self.save()
|
126
145
|
|
@@ -130,14 +149,15 @@ class Payment(models.Model):
|
|
130
149
|
|
131
150
|
@property
|
132
151
|
def total_payment(self):
|
152
|
+
orders = self.orders.all()
|
133
153
|
sum_orders = Decimal(
|
134
|
-
sum(map(lambda order: Decimal(order.total_amount) or 0,
|
154
|
+
sum(map(lambda order: Decimal(order.total_amount) or 0, orders))
|
135
155
|
)
|
136
156
|
if self.payment_tax.rate == Tax.Rates.PERCENTAGE:
|
137
157
|
perc = Decimal(sum_orders * self.payment_tax.value / 100)
|
138
|
-
return sum_orders + perc
|
158
|
+
return round(sum_orders + perc, 3)
|
139
159
|
|
140
|
-
return sum_orders +
|
160
|
+
return round(sum_orders + self.payment_tax.value, 3)
|
141
161
|
|
142
162
|
@property
|
143
163
|
def type_of_order(self):
|
@@ -319,8 +319,6 @@ class ProductMedia(DjangoModelCleanMixin, models.Model):
|
|
319
319
|
verbose_name = _("product media")
|
320
320
|
verbose_name_plural = _("Product medias")
|
321
321
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
create_media_thumbnails(None, self, None)
|
326
|
-
return super().save(**kwargs)
|
322
|
+
@property
|
323
|
+
def name(self):
|
324
|
+
return f"{self.product.name}_{self.order_value}"
|
@@ -12,7 +12,7 @@ from ob_dj_store.core.stores.managers import (
|
|
12
12
|
ShippingMethodManager,
|
13
13
|
StoreManager,
|
14
14
|
)
|
15
|
-
from ob_dj_store.core.stores.utils import
|
15
|
+
from ob_dj_store.core.stores.utils import validate_currency
|
16
16
|
from ob_dj_store.utils.helpers import store_media_upload_to
|
17
17
|
from ob_dj_store.utils.model import DjangoModelCleanMixin
|
18
18
|
|
@@ -114,7 +114,7 @@ class Store(DjangoModelCleanMixin, models.Model):
|
|
114
114
|
)
|
115
115
|
payment_methods = models.ManyToManyField(
|
116
116
|
PaymentMethod,
|
117
|
-
related_name="
|
117
|
+
related_name="stores",
|
118
118
|
blank=True,
|
119
119
|
help_text=_("Payment methods within the store"),
|
120
120
|
)
|
@@ -137,6 +137,13 @@ class Store(DjangoModelCleanMixin, models.Model):
|
|
137
137
|
help_text=_("This is the min price to get a free delivery"),
|
138
138
|
)
|
139
139
|
image = models.ImageField(upload_to=store_media_upload_to, null=True, blank=True)
|
140
|
+
currency = models.CharField(
|
141
|
+
max_length=3,
|
142
|
+
default="KWD",
|
143
|
+
validators=[
|
144
|
+
validate_currency,
|
145
|
+
],
|
146
|
+
)
|
140
147
|
|
141
148
|
created_at = models.DateTimeField(auto_now_add=True)
|
142
149
|
updated_at = models.DateTimeField(auto_now=True)
|
@@ -150,12 +157,6 @@ class Store(DjangoModelCleanMixin, models.Model):
|
|
150
157
|
def __str__(self) -> typing.Text:
|
151
158
|
return f"Store {self.name} (PK={self.pk})"
|
152
159
|
|
153
|
-
@property
|
154
|
-
def currency(self):
|
155
|
-
if self.address:
|
156
|
-
return get_currency_by_country(self.address.country.name)
|
157
|
-
return None
|
158
|
-
|
159
160
|
@property
|
160
161
|
def current_opening_hours(self):
|
161
162
|
return next(
|
@@ -6,10 +6,11 @@ from django.conf import settings
|
|
6
6
|
from django.db import models
|
7
7
|
from django.db.models.functions import Coalesce
|
8
8
|
from django.utils.translation import gettext_lazy as _
|
9
|
-
from django_countries.fields import CountryField
|
10
9
|
|
11
10
|
from ob_dj_store.core.stores.managers import WalletTransactionManager
|
12
|
-
from ob_dj_store.core.stores.
|
11
|
+
from ob_dj_store.core.stores.models._store import PaymentMethod
|
12
|
+
from ob_dj_store.core.stores.utils import validate_currency
|
13
|
+
from ob_dj_store.utils.helpers import wallet_media_upload_to
|
13
14
|
|
14
15
|
logger = logging.getLogger(__name__)
|
15
16
|
|
@@ -20,7 +21,21 @@ class Wallet(models.Model):
|
|
20
21
|
on_delete=models.CASCADE,
|
21
22
|
related_name="wallets",
|
22
23
|
)
|
23
|
-
|
24
|
+
name = models.CharField(max_length=200, null=True, blank=True)
|
25
|
+
image = models.ImageField(upload_to=wallet_media_upload_to, null=True, blank=True)
|
26
|
+
image_thumbnail_medium = models.ImageField(
|
27
|
+
upload_to="wallets/", null=True, blank=True
|
28
|
+
)
|
29
|
+
currency = models.CharField(
|
30
|
+
max_length=3,
|
31
|
+
default="KWD",
|
32
|
+
validators=[
|
33
|
+
validate_currency,
|
34
|
+
],
|
35
|
+
)
|
36
|
+
|
37
|
+
class Meta:
|
38
|
+
unique_together = ("user", "currency")
|
24
39
|
|
25
40
|
def __str__(self) -> typing.Text:
|
26
41
|
return f"Wallet(PK={self.pk})"
|
@@ -48,11 +63,29 @@ class Wallet(models.Model):
|
|
48
63
|
)
|
49
64
|
return query["balance"]
|
50
65
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
66
|
+
def top_up_wallet(self, amount: Decimal, payment_method: PaymentMethod):
|
67
|
+
from ob_dj_store.core.stores.models import Order, Payment
|
68
|
+
|
69
|
+
user = self.user
|
70
|
+
order = Order.objects.create(
|
71
|
+
customer=user,
|
72
|
+
payment_method=payment_method,
|
73
|
+
extra_infos={
|
74
|
+
"is_wallet_fill_up": True,
|
75
|
+
"amount": str(amount),
|
76
|
+
"currency": self.currency,
|
77
|
+
},
|
78
|
+
)
|
79
|
+
payment = Payment.objects.create(
|
80
|
+
orders=[
|
81
|
+
order,
|
82
|
+
],
|
83
|
+
user=user,
|
84
|
+
currency=self.currency,
|
85
|
+
method=payment_method,
|
86
|
+
amount=amount,
|
87
|
+
)
|
88
|
+
return payment.payment_url
|
56
89
|
|
57
90
|
|
58
91
|
class WalletTransaction(models.Model):
|
@@ -1,9 +1,16 @@
|
|
1
1
|
from django.conf import settings
|
2
|
-
from django.db.models.signals import post_save
|
2
|
+
from django.db.models.signals import post_save, pre_save
|
3
3
|
from django.dispatch import receiver
|
4
4
|
|
5
5
|
from config import settings as store_settings
|
6
|
-
from ob_dj_store.core.stores.models import
|
6
|
+
from ob_dj_store.core.stores.models import (
|
7
|
+
Cart,
|
8
|
+
Category,
|
9
|
+
Order,
|
10
|
+
OrderHistory,
|
11
|
+
ProductMedia,
|
12
|
+
Wallet,
|
13
|
+
)
|
7
14
|
from ob_dj_store.utils.utils import resize_image
|
8
15
|
|
9
16
|
|
@@ -17,8 +24,8 @@ def create_customer_cart_and_wallet_handler(sender, instance, created, **kwargs)
|
|
17
24
|
return
|
18
25
|
cart = Cart(customer=instance)
|
19
26
|
cart.save()
|
20
|
-
|
21
|
-
|
27
|
+
for currency in store_settings.WALLET_CURRENCIES:
|
28
|
+
instance.wallets.create(currency=currency)
|
22
29
|
|
23
30
|
|
24
31
|
# add receiver to ProductVariant to create inventory
|
@@ -37,19 +44,66 @@ def create_order_history_handler(sender, instance, created, **kwargs):
|
|
37
44
|
|
38
45
|
|
39
46
|
@receiver(
|
40
|
-
|
47
|
+
pre_save,
|
41
48
|
sender=Category,
|
42
49
|
dispatch_uid="create_category_thumbnails",
|
43
50
|
)
|
44
|
-
def
|
51
|
+
def create_category_thumbnails(sender, instance, **kwargs):
|
52
|
+
medium_dim = getattr(store_settings, "THUMBNAIL_MEDIUM_DIMENSIONS", None)
|
53
|
+
small_dim = getattr(store_settings, "THUMBNAIL_SMALL_DIMENSIONS", None)
|
54
|
+
if instance.image:
|
55
|
+
if medium_dim:
|
56
|
+
instance.image_thumbnail_medium = resize_image(
|
57
|
+
instance.image,
|
58
|
+
dim=medium_dim,
|
59
|
+
size_name="medium",
|
60
|
+
image_name=instance.name,
|
61
|
+
)
|
62
|
+
if small_dim:
|
63
|
+
instance.image_thumbnail_small = resize_image(
|
64
|
+
instance.image,
|
65
|
+
dim=small_dim,
|
66
|
+
size_name="small",
|
67
|
+
image_name=instance.name,
|
68
|
+
)
|
69
|
+
|
70
|
+
|
71
|
+
@receiver(
|
72
|
+
pre_save,
|
73
|
+
sender=ProductMedia,
|
74
|
+
dispatch_uid="create_product_media_thumbnails",
|
75
|
+
)
|
76
|
+
def create_product_media_thumbnails(sender, instance, **kwargs):
|
45
77
|
medium_dim = getattr(store_settings, "THUMBNAIL_MEDIUM_DIMENSIONS", None)
|
46
78
|
small_dim = getattr(store_settings, "THUMBNAIL_SMALL_DIMENSIONS", None)
|
47
79
|
if instance.image:
|
48
80
|
if medium_dim:
|
49
81
|
instance.image_thumbnail_medium = resize_image(
|
50
|
-
instance.image,
|
82
|
+
instance.image,
|
83
|
+
dim=medium_dim,
|
84
|
+
size_name="medium",
|
85
|
+
image_name=instance.name,
|
51
86
|
)
|
52
87
|
if small_dim:
|
53
88
|
instance.image_thumbnail_small = resize_image(
|
54
|
-
instance.image,
|
89
|
+
instance.image,
|
90
|
+
dim=small_dim,
|
91
|
+
size_name="small",
|
92
|
+
image_name=instance.name,
|
55
93
|
)
|
94
|
+
|
95
|
+
|
96
|
+
@receiver(
|
97
|
+
pre_save,
|
98
|
+
sender=Wallet,
|
99
|
+
dispatch_uid="create_wallet_thumbnails",
|
100
|
+
)
|
101
|
+
def create_wallet_thumbnails(sender, instance, **kwargs):
|
102
|
+
medium_dim = getattr(store_settings, "THUMBNAIL_MEDIUM_DIMENSIONS", None)
|
103
|
+
if instance.image and medium_dim:
|
104
|
+
instance.image_thumbnail_medium = resize_image(
|
105
|
+
instance.image,
|
106
|
+
dim=medium_dim,
|
107
|
+
size_name="medium",
|
108
|
+
image_name=f"{instance.currency}_{instance.user.username}",
|
109
|
+
)
|
ob_dj_store/core/stores/utils.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
import math
|
2
2
|
|
3
3
|
import pycountry
|
4
|
+
from django.core.exceptions import ValidationError
|
5
|
+
from django.utils.translation import gettext_lazy as _
|
4
6
|
|
5
7
|
|
6
8
|
def get_data_dict(instance):
|
@@ -53,13 +55,19 @@ def distance(origin, destination):
|
|
53
55
|
|
54
56
|
def get_currency_by_country(country):
|
55
57
|
country = pycountry.countries.get(name=country)
|
56
|
-
|
57
|
-
|
58
|
-
return pycountry.currencies.get(numeric=country.numeric).alpha_3
|
58
|
+
currency = pycountry.currencies.get(numeric=country.numeric)
|
59
|
+
return currency.alpha_3
|
59
60
|
|
60
61
|
|
61
62
|
def get_country_by_currency(currency):
|
62
63
|
currency = pycountry.currencies.get(alpha_3=currency)
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
country = pycountry.countries.get(numeric=currency.numeric)
|
65
|
+
return country.alpha_2
|
66
|
+
|
67
|
+
|
68
|
+
def validate_currency(value):
|
69
|
+
if not pycountry.currencies.get(alpha_3=value):
|
70
|
+
raise ValidationError(
|
71
|
+
_("%(value)s is not a currency"),
|
72
|
+
params={"value": value},
|
73
|
+
)
|
ob_dj_store/utils/helpers.py
CHANGED
@@ -19,7 +19,7 @@ def import_class_from_string(serializer_class_name):
|
|
19
19
|
|
20
20
|
def product_media_upload_to(instance, filename):
|
21
21
|
ext = filename.split(".")[-1]
|
22
|
-
return f"product_media/{instance.product.
|
22
|
+
return f"product_media/{instance.product.name}_{instance.order_value}_{int(now().timestamp())}.{ext}"
|
23
23
|
|
24
24
|
|
25
25
|
def category_media_upload_to(instance, filename):
|
@@ -32,3 +32,9 @@ def store_media_upload_to(instance, filename):
|
|
32
32
|
ext = filename.split(".")[-1]
|
33
33
|
if instance:
|
34
34
|
return f"store_media/{instance.name}_{int(now().timestamp())}.{ext}"
|
35
|
+
|
36
|
+
|
37
|
+
def wallet_media_upload_to(instance, filename):
|
38
|
+
ext = filename.split(".")[-1]
|
39
|
+
if instance:
|
40
|
+
return f"wallets/{instance.currency}_{instance.user.username}_{int(now().timestamp())}.{ext}"
|
ob_dj_store/utils/utils.py
CHANGED
@@ -3,13 +3,14 @@ import os
|
|
3
3
|
from io import BytesIO
|
4
4
|
|
5
5
|
from django.core.files.uploadedfile import InMemoryUploadedFile
|
6
|
+
from django.utils.timezone import now
|
6
7
|
from PIL import Image, UnidentifiedImageError
|
7
8
|
from pilkit.processors import ResizeToFill
|
8
9
|
|
9
10
|
logger = logging.getLogger(__name__)
|
10
11
|
|
11
12
|
|
12
|
-
def resize_image(image, dim: dict, size_name: str):
|
13
|
+
def resize_image(image, dim: dict, size_name: str, image_name: str):
|
13
14
|
try:
|
14
15
|
img = Image.open(image)
|
15
16
|
except UnidentifiedImageError as e:
|
@@ -34,7 +35,7 @@ def resize_image(image, dim: dict, size_name: str):
|
|
34
35
|
new_image = InMemoryUploadedFile(
|
35
36
|
output,
|
36
37
|
"ImageField",
|
37
|
-
f"{
|
38
|
+
f"{image_name}_{int(now().timestamp())}_{size_name}.{img_format.lower()}",
|
38
39
|
content_type,
|
39
40
|
output.__sizeof__(),
|
40
41
|
None,
|
@@ -1,28 +1,28 @@
|
|
1
1
|
ob_dj_store/apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
ob_dj_store/apis/stores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
ob_dj_store/apis/stores/filters.py,sha256=
|
4
|
-
ob_dj_store/apis/stores/urls.py,sha256=
|
5
|
-
ob_dj_store/apis/stores/views.py,sha256=
|
6
|
-
ob_dj_store/apis/stores/rest/serializers/serializers.py,sha256=
|
3
|
+
ob_dj_store/apis/stores/filters.py,sha256=s4US_TysnIgdT8pue_1jlG3V33WhYmCymXK3DuC0rqY,5746
|
4
|
+
ob_dj_store/apis/stores/urls.py,sha256=cPForgFpOgOGCUVAk6DZcZ7qOooMf1zpDIr1BA0L_8A,1593
|
5
|
+
ob_dj_store/apis/stores/views.py,sha256=zoEgQg3qKVlhhHPj96_UoNE-B8Pf8NK4AuUEmTwOhgg,29833
|
6
|
+
ob_dj_store/apis/stores/rest/serializers/serializers.py,sha256=43c_0NyKVZDfmI32f2DR3m6i0G2y3G_yxZEuJBvdAL4,36402
|
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
|
10
10
|
ob_dj_store/apis/tap/views.py,sha256=VnVquybTHlJquxsC0RNTy20dtLXalchO0SlGjSDaBng,2666
|
11
11
|
ob_dj_store/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
ob_dj_store/core/stores/__init__.py,sha256=-izNGrxNn_nn3IQXd5pkuES9lSF-AHYb14yhNPozYCI,65
|
13
|
-
ob_dj_store/core/stores/admin.py,sha256=
|
14
|
-
ob_dj_store/core/stores/admin_inlines.py,sha256=
|
13
|
+
ob_dj_store/core/stores/admin.py,sha256=4um-O_30xpnfcZHe_sNOyvSTnqLSbeExA2E1QppLEZQ,7354
|
14
|
+
ob_dj_store/core/stores/admin_inlines.py,sha256=SLj8mMa-Sc3oP693R0W9c3Ocyk7eb34IyXbC4E6LL8M,1557
|
15
15
|
ob_dj_store/core/stores/apps.py,sha256=i6D2lcqlluP6FwJSBpekf7BQVzQURwSy_Y97SgqWTkM,434
|
16
|
-
ob_dj_store/core/stores/managers.py,sha256=
|
17
|
-
ob_dj_store/core/stores/receivers.py,sha256=
|
16
|
+
ob_dj_store/core/stores/managers.py,sha256=cDr8TtPxayLwTFNgFs9I87ZXh7ssqM-yAmvEcN9a5LU,6359
|
17
|
+
ob_dj_store/core/stores/receivers.py,sha256=5AYMW8ul5htJPp4gBwRAH1VyT5ugZvDMJmed2sostBM,3194
|
18
18
|
ob_dj_store/core/stores/settings_validation.py,sha256=s9BPEdyCL2aslZwZGLAWEvJBzXlUo0p2TbC1_0E_SDo,327
|
19
|
-
ob_dj_store/core/stores/utils.py,sha256=
|
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
|
22
22
|
ob_dj_store/core/stores/gateway/tap/admin.py,sha256=Jzt50VacsSaxJb-ly4sJ0F4NOujixlS4_3DgkdU0JSk,384
|
23
23
|
ob_dj_store/core/stores/gateway/tap/apps.py,sha256=kWwPjuAJeEmEasVDzUbvRsGaQWL-aYe4JDHNLvCVXPs,212
|
24
24
|
ob_dj_store/core/stores/gateway/tap/managers.py,sha256=nJkKPzd_bgTttmZERiWWHiQW0WWcfSHUxNkOKmyrjDY,830
|
25
|
-
ob_dj_store/core/stores/gateway/tap/models.py,sha256=
|
25
|
+
ob_dj_store/core/stores/gateway/tap/models.py,sha256=11SYWK-I7NyrJUQAJeTp3jzO94jwWNm_y5QZXd4UFkA,3456
|
26
26
|
ob_dj_store/core/stores/gateway/tap/utils.py,sha256=DB-UVxQT3Sdb17g5PF5a9Ghy6GgKADxcJWt1MxPmlt4,2493
|
27
27
|
ob_dj_store/core/stores/gateway/tap/migrations/0001_initial.py,sha256=_303R1R2tVVdPSMtwpuLUxvWbxQ2BML1Gsd-VhfnZEM,4808
|
28
28
|
ob_dj_store/core/stores/gateway/tap/migrations/0002_auto_20220815_1610.py,sha256=gRsekTbqUH4h5yg5d1zWuai7Wiv6-rfsmjnXundgin8,674
|
@@ -90,23 +90,27 @@ ob_dj_store/core/stores/migrations/0058_attributechoice_is_default.py,sha256=nv_
|
|
90
90
|
ob_dj_store/core/stores/migrations/0059_auto_20230217_2006.py,sha256=ZaTZRC10L9uzMuya0rXHcsvJzsfF6H9-kcbzrrKVZMQ,1304
|
91
91
|
ob_dj_store/core/stores/migrations/0060_alter_orderitem_product_variant.py,sha256=wyGWekRoR3XAGFfNScNV1jvqMz_HgWACCeiodUa_fGA,607
|
92
92
|
ob_dj_store/core/stores/migrations/0061_auto_20230223_1435.py,sha256=Rqi0XMNw21mVlSzmWo132xaJfamUeyZ1l0_wdr6ipg0,796
|
93
|
+
ob_dj_store/core/stores/migrations/0062_auto_20230226_2005.py,sha256=ApzGG5teYcLd4horeCzxIWnVPTeRoMNlJProUhYHacY,1187
|
94
|
+
ob_dj_store/core/stores/migrations/0063_alter_store_payment_methods.py,sha256=QKIrNVtjttvYn4IO1GpGkA2gX4cyqjHNbFQ7q7cQqno,571
|
95
|
+
ob_dj_store/core/stores/migrations/0064_auto_20230228_1814.py,sha256=6fgusQrMykN_tlNBxiJqLNvrHBA0yI32JK0kQ4VfNpQ,644
|
96
|
+
ob_dj_store/core/stores/migrations/0065_auto_20230228_1932.py,sha256=r3-ThPhh_Lf4J3tYbCLiRbLSui5VSqwaVCtzvEZes_8,919
|
93
97
|
ob_dj_store/core/stores/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
94
98
|
ob_dj_store/core/stores/models/__init__.py,sha256=1lEOqmvQlQJZj9nnObTAQqgnPP1yVGvM8H9yjglZ0VI,1568
|
95
99
|
ob_dj_store/core/stores/models/_address.py,sha256=qS5TQ9Z12zx_4CrrHvG8PoYVkdiOq_MtbKR14WKh3Hw,1661
|
96
100
|
ob_dj_store/core/stores/models/_cart.py,sha256=qgjg5MXTMRIZRJJDx5BQ1pa9__ylfrnYMMRGbB2R53c,4555
|
97
|
-
ob_dj_store/core/stores/models/_favorite.py,sha256=
|
101
|
+
ob_dj_store/core/stores/models/_favorite.py,sha256=bpXlFBNK8jsQkZG1RiDAbNTNSoVP0NOUUxZI8c46QzI,2561
|
98
102
|
ob_dj_store/core/stores/models/_feedback.py,sha256=eCUVgprNK5hSRKOS4M_pdR7QH2-rqhoYevlpykhCOLg,1472
|
99
103
|
ob_dj_store/core/stores/models/_inventory.py,sha256=vAXSpCyUdYDIWgUEUUObQfhAcCcQO6j6zATrHf5dPuQ,3928
|
100
|
-
ob_dj_store/core/stores/models/_order.py,sha256=
|
101
|
-
ob_dj_store/core/stores/models/_payment.py,sha256=
|
102
|
-
ob_dj_store/core/stores/models/_product.py,sha256=
|
103
|
-
ob_dj_store/core/stores/models/_store.py,sha256=
|
104
|
-
ob_dj_store/core/stores/models/_wallet.py,sha256=
|
104
|
+
ob_dj_store/core/stores/models/_order.py,sha256=qtdUpG30dZeDGeh0Z8JhzyyqQIuxTdLfyzd0-xaoo3o,8018
|
105
|
+
ob_dj_store/core/stores/models/_payment.py,sha256=dCOXOYkgxOGJqp0nxEvzHmdZxR_srFUIZAhrB--SP1U,6143
|
106
|
+
ob_dj_store/core/stores/models/_product.py,sha256=yGVp3vl5rCReG4c8ogWy2NUcsTJeqCxP0tm6lQyYx7Y,10928
|
107
|
+
ob_dj_store/core/stores/models/_store.py,sha256=g7QXKbZI886Pdw6smuheVep7Vh1ke42PEhJhnxW4byA,7334
|
108
|
+
ob_dj_store/core/stores/models/_wallet.py,sha256=4LUyWPlgRedthWij-Nkn4diYvWHU755IOBLgpjZOyQ8,3679
|
105
109
|
ob_dj_store/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
106
|
-
ob_dj_store/utils/helpers.py,sha256=
|
110
|
+
ob_dj_store/utils/helpers.py,sha256=02igVH2DSDTZYa6kFSTmBnJeXfTdgjRCRSXQ7mvmCGo,1224
|
107
111
|
ob_dj_store/utils/model.py,sha256=DV7hOhTaZL3gh9sptts2jTUFlTArKG3i7oPioq9HLFE,303
|
108
|
-
ob_dj_store/utils/utils.py,sha256=
|
109
|
-
ob_dj_store-0.0.11.
|
110
|
-
ob_dj_store-0.0.11.
|
111
|
-
ob_dj_store-0.0.11.
|
112
|
-
ob_dj_store-0.0.11.
|
112
|
+
ob_dj_store/utils/utils.py,sha256=euWeNI39P48jGNwKoBCC5AmwQUmgDeb92t0fQtPm-5g,1282
|
113
|
+
ob_dj_store-0.0.11.10.dist-info/METADATA,sha256=pjF7LcR9ltkOqvsxXXp5ZGjaJRR47kGrO_SyxVtGrZ4,2828
|
114
|
+
ob_dj_store-0.0.11.10.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
115
|
+
ob_dj_store-0.0.11.10.dist-info/top_level.txt,sha256=CZG3G0ptTkzGnc0dFYN-ZD7YKdJBmm47bsmGwofD_lk,12
|
116
|
+
ob_dj_store-0.0.11.10.dist-info/RECORD,,
|
File without changes
|
File without changes
|