ob-dj-store 0.0.21__py3-none-any.whl → 0.0.21.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.
@@ -87,6 +87,7 @@ class ProductFilter(filters.FilterSet):
87
87
  """Product filters"""
88
88
 
89
89
  category = filters.CharFilter(method="by_category")
90
+ q = filters.CharFilter(method="filter_search")
90
91
 
91
92
  class Meta:
92
93
  model = Product
@@ -99,6 +100,17 @@ class ProductFilter(filters.FilterSet):
99
100
  def by_category(self, queryset, name, value):
100
101
  return queryset.filter(category__name__iexact=value)
101
102
 
103
+ def filter_search(self, queryset, name, value):
104
+ language = self.request.META.get("HTTP_LANGUAGE", "").strip().upper()
105
+ if language == "AR":
106
+ query = Q(name_arabic__icontains=value) | Q(
107
+ description_arabic__icontains=value
108
+ )
109
+ else:
110
+ query = Q(name__icontains=value) | Q(description__icontains=value)
111
+ qs = queryset.filter(query).distinct()[:5]
112
+ return qs
113
+
102
114
 
103
115
  class VariantFilter(filters.FilterSet):
104
116
  """Variant filters"""
@@ -947,6 +947,44 @@ class ProductSerializer(ArabicFieldsMixin, FavoriteMixin, serializers.ModelSeria
947
947
  return data
948
948
 
949
949
 
950
+ class ProductSearchSerializer(
951
+ ArabicFieldsMixin, FavoriteMixin, serializers.ModelSerializer
952
+ ):
953
+ is_snoozed = serializers.SerializerMethodField()
954
+ is_available = serializers.SerializerMethodField()
955
+
956
+ class Meta:
957
+ model = Product
958
+ fields = (
959
+ "id",
960
+ "name",
961
+ "name_arabic",
962
+ "slug",
963
+ "description",
964
+ "description_arabic",
965
+ "is_snoozed",
966
+ "is_available",
967
+ )
968
+
969
+ def get_store_id(self):
970
+ return self.context["request"].query_params.get("store")
971
+
972
+ def get_inventory_for_store(self, store_id):
973
+ if hasattr(self, "get_inventory"):
974
+ return self.get_inventory(store_id)
975
+ return None
976
+
977
+ def get_is_snoozed(self, obj):
978
+ store_id = self.get_store_id()
979
+ inventory = self.get_inventory_for_store(store_id)
980
+ return obj.is_snoozed(store_id=store_id) if inventory else False
981
+
982
+ def get_is_available(self, obj):
983
+ store_id = self.get_store_id()
984
+ inventory = self.get_inventory_for_store(store_id)
985
+ return bool(inventory and inventory.quantity)
986
+
987
+
950
988
  class ProductListSerializer(ArabicFieldsMixin, serializers.ModelSerializer):
951
989
  product_images = ProductMediaSerializer(many=True, source="images")
952
990
 
@@ -20,6 +20,7 @@ from ob_dj_store.apis.stores.views import (
20
20
  TaxViewSet,
21
21
  TransactionsViewSet,
22
22
  VariantView,
23
+ WalletV2ViewSet,
23
24
  WalletViewSet,
24
25
  )
25
26
 
@@ -43,6 +44,7 @@ router.register(r"cart", CartView, basename="cart")
43
44
  router.register(r"cart-item", CartItemView, basename="cart-item")
44
45
  router.register(r"favorite", FavoriteViewSet, basename="favorite")
45
46
  router.register(r"wallet", WalletViewSet, basename="wallet")
47
+ router.register(r"wallet_v2", WalletV2ViewSet, basename="wallet_v2")
46
48
  router.register(r"payment-method", PaymentMethodViewSet, basename="payment-method")
47
49
  router.register(r"order", ReorderViewSet, basename="re-order")
48
50
  router.register(r"partner/auth", PartnerAuthInfoViewSet, basename="auth")
@@ -51,6 +51,7 @@ from ob_dj_store.apis.stores.rest.serializers.serializers import (
51
51
  PaymentMethodSerializer,
52
52
  PaymentSerializer,
53
53
  ProductListSerializer,
54
+ ProductSearchSerializer,
54
55
  ProductSerializer,
55
56
  ProductVariantSerializer,
56
57
  ReorderSerializer,
@@ -61,6 +62,7 @@ from ob_dj_store.apis.stores.rest.serializers.serializers import (
61
62
  WalletSerializer,
62
63
  WalletTopUpSerializer,
63
64
  WalletTransactionListSerializer,
65
+ WalletTransactionSerializer,
64
66
  )
65
67
  from ob_dj_store.core.stores.gateway.tap.utils import TapException
66
68
  from ob_dj_store.core.stores.models import (
@@ -575,6 +577,11 @@ class ProductView(
575
577
  filterset_class = ProductFilter
576
578
  queryset = Product.objects.active()
577
579
 
580
+ def get_serializer_class(self):
581
+ if self.request.query_params.get("q"):
582
+ return ProductSearchSerializer
583
+ return ProductSerializer
584
+
578
585
  def apply_prefetch(self, queryset):
579
586
 
580
587
  qs = queryset.prefetch_related(
@@ -1103,13 +1110,19 @@ class WalletViewSet(
1103
1110
  methods=["GET"],
1104
1111
  detail=True,
1105
1112
  url_path="transactions",
1106
- serializer_class=WalletTransactionListSerializer,
1113
+ serializer_class=WalletTransactionSerializer,
1107
1114
  )
1108
- def transactions(self, request, *args, **kwargs):
1109
- wallet = self.get_object()
1110
- queryset = wallet.transactions.all().order_by("-created_at")
1111
- serializer = WalletTransactionListSerializer(queryset, many=True)
1112
- return Response({"results": serializer.data})
1115
+ def transactions(
1116
+ self, request: Request, *args: typing.Any, **kwargs: typing.Any
1117
+ ) -> Response:
1118
+ queryset = self.get_object().transactions.all().order_by("-created_at")
1119
+ page = self.paginate_queryset(queryset)
1120
+ if page is not None:
1121
+ serializer = self.get_serializer(page, many=True)
1122
+ return self.get_paginated_response(serializer.data)
1123
+
1124
+ serializer = self.get_serializer(queryset, many=True)
1125
+ return Response(serializer.data)
1113
1126
 
1114
1127
  @swagger_auto_schema(
1115
1128
  operation_summary="List Wallet selection images",
@@ -1137,6 +1150,34 @@ class WalletViewSet(
1137
1150
  return Response(serializer.data)
1138
1151
 
1139
1152
 
1153
+ class WalletV2ViewSet(
1154
+ mixins.ListModelMixin, viewsets.GenericViewSet,
1155
+ ):
1156
+ def get_queryset(self):
1157
+ return Wallet.objects.filter(
1158
+ user=self.request.user, is_active=True
1159
+ ).select_related("media_image")
1160
+
1161
+ @swagger_auto_schema(
1162
+ operation_summary="List Wallet's transactions",
1163
+ operation_description="""
1164
+ list user's wallet transactions(debit,credit)
1165
+ """,
1166
+ tags=["Wallet",],
1167
+ )
1168
+ @action(
1169
+ methods=["GET"],
1170
+ detail=True,
1171
+ url_path="transactions",
1172
+ serializer_class=WalletTransactionListSerializer,
1173
+ )
1174
+ def transactions(self, request, *args, **kwargs):
1175
+ wallet = self.get_object()
1176
+ queryset = wallet.transactions.all().order_by("-created_at")
1177
+ serializer = WalletTransactionListSerializer(queryset, many=True)
1178
+ return Response({"results": serializer.data})
1179
+
1180
+
1140
1181
  class PartnerAuthInfoViewSet(
1141
1182
  mixins.CreateModelMixin,
1142
1183
  mixins.RetrieveModelMixin,
@@ -0,0 +1,27 @@
1
+ # Generated by Django 3.2.8 on 2025-07-31 16:12
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("stores", "0108_alter_paymentmethod_payment_provider"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name="wallettransaction",
15
+ name="cashback_type",
16
+ field=models.CharField(
17
+ blank=True,
18
+ choices=[
19
+ ("BY_ORDER", "By Order"),
20
+ ("BY_OFFER", "By Offer"),
21
+ ("BY_STREAK", "By Streak"),
22
+ ],
23
+ max_length=100,
24
+ null=True,
25
+ ),
26
+ ),
27
+ ]
@@ -248,6 +248,19 @@ class Product(DjangoModelCleanMixin, models.Model):
248
248
  def __str__(self):
249
249
  return f"Product {self.name} (PK={self.pk})"
250
250
 
251
+ def get_inventory(self, store_id):
252
+ try:
253
+ inventory = self.product_variants.inventories.get(store=store_id)
254
+ except ObjectDoesNotExist:
255
+ return None
256
+
257
+ def is_snoozed(self, store_id):
258
+ try:
259
+ inventory = self.product_variants.inventories.get(store=store_id)
260
+ except ObjectDoesNotExist:
261
+ return False
262
+ return inventory.is_snoozed
263
+
251
264
 
252
265
  # TODO: must remove, redundunt
253
266
  class Attribute(DjangoModelCleanMixin, models.Model):
@@ -136,6 +136,11 @@ class WalletTransaction(models.Model):
136
136
  CREDIT = "CREDIT", _("credit")
137
137
  DEBIT = "DEBIT", _("debit")
138
138
 
139
+ class CashBackType(models.TextChoices):
140
+ BY_ORDER = "BY_ORDER", _("By Order")
141
+ BY_OFFER = "BY_OFFER", _("By Offer")
142
+ BY_STREAK = "BY_STREAK", _("By Streak")
143
+
139
144
  wallet = models.ForeignKey(
140
145
  "stores.Wallet", on_delete=models.CASCADE, related_name="transactions",
141
146
  )
@@ -150,7 +155,9 @@ class WalletTransaction(models.Model):
150
155
  is_cashback = models.BooleanField(default=False)
151
156
  is_refund = models.BooleanField(default=False)
152
157
  is_redeemed = models.BooleanField(default=False)
153
-
158
+ cashback_type = models.CharField(
159
+ max_length=100, choices=CashBackType.choices, blank=True, null=True
160
+ )
154
161
  objects = WalletTransactionManager()
155
162
 
156
163
  # Audit
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ob-dj-store
3
- Version: 0.0.21
3
+ Version: 0.0.21.2
4
4
  Summary: OBytes django application for managing ecommerce stores.
5
5
  Home-page: https://www.obytes.com/
6
6
  Author: OBytes
@@ -1,9 +1,9 @@
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=lDb-wS7dEsSS0XL2qN4XqoRKYSEDgxhVZLBPGL0pPM4,9764
4
- ob_dj_store/apis/stores/urls.py,sha256=7vwogfIGcKS0hHYK3iBXKQwi1kCA_vuHY1eZt8rAspg,2021
5
- ob_dj_store/apis/stores/views.py,sha256=YCYZ3XlJLFOwhpqMU-Lvx_emJwW-0fdyEF2SXROEmNU,41405
6
- ob_dj_store/apis/stores/rest/serializers/serializers.py,sha256=mhUS1LmnZpFY5OAnGbiMBwD6zywC7tZ8vKK1bVniJTE,67087
3
+ ob_dj_store/apis/stores/filters.py,sha256=cJ7OnNLFT1N5lp3IXFUpGMgqm-jhS24g-Y8pZmEMe58,10260
4
+ ob_dj_store/apis/stores/urls.py,sha256=W9sNJ7ST9pGnfVCf7GmduDO-_zK9MGTI6ybV8n-lzSc,2111
5
+ ob_dj_store/apis/stores/views.py,sha256=cwDFNY2rtTfjl_F9PpR5zOJy2DPmGidOjIlJ9fsgSYI,42744
6
+ ob_dj_store/apis/stores/rest/serializers/serializers.py,sha256=GUsUTN4MTXq92Uriv6Ql9MzjZJsSbmFDC3lZhSmB7vE,68219
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
@@ -142,6 +142,7 @@ ob_dj_store/core/stores/migrations/0105_store_is_open_after_midnight.py,sha256=8
142
142
  ob_dj_store/core/stores/migrations/0106_alter_paymentmethod_payment_provider.py,sha256=BDDfVs0fMifUnSlZ4zIct78F6PvfP5gyrVFyifrCvE4,1092
143
143
  ob_dj_store/core/stores/migrations/0107_auto_20250425_2059.py,sha256=XCj2Inlw8e-_6W9wvYeVVV-bGk6lX8_n2FNI5W80XVw,848
144
144
  ob_dj_store/core/stores/migrations/0108_alter_paymentmethod_payment_provider.py,sha256=abuqKAhuha8tEdxJy-Tj1RNFOMV63_z5v_qK5LLSNVI,1078
145
+ ob_dj_store/core/stores/migrations/0109_wallettransaction_cashback_type.py,sha256=XA_RtxLjnpsz-i0uKlCyYK-UWL4RR10Q_XeqVd3KX6A,691
145
146
  ob_dj_store/core/stores/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
147
  ob_dj_store/core/stores/models/__init__.py,sha256=VeWrDiIbw94ZDSFD-62rz9iTTW87iPdwDW5jcjxm7bs,2045
147
148
  ob_dj_store/core/stores/models/_address.py,sha256=uf9W4dnlXkEFhhsK75ZsDwWq5R2JEngf7VhBiLEnIVs,2193
@@ -152,14 +153,14 @@ ob_dj_store/core/stores/models/_inventory.py,sha256=_rGlVL5HjOlHQVB8CI0776CPcE5r
152
153
  ob_dj_store/core/stores/models/_order.py,sha256=_08lqX5p4brCdUilqfbT--6Ao2TMsqnzXaWoV_7IYL8,9758
153
154
  ob_dj_store/core/stores/models/_partner.py,sha256=OuYvevUWn1sYHs9PcFf51EUUC1uqytQss8Bx91aMOH8,4732
154
155
  ob_dj_store/core/stores/models/_payment.py,sha256=FTV-NmvQjxwwR5C5X7qYWV-ZUIZfqMMEjkBNaS-drLs,6421
155
- ob_dj_store/core/stores/models/_product.py,sha256=E_P0BfJ5A7-aSb_8graCLOL_7PmL1JiBgqwx-mQpiM0,17825
156
+ ob_dj_store/core/stores/models/_product.py,sha256=iBSXZcZdtCXFINiOFqbnaZot9rWPkFdzySXwKJO5h6I,18239
156
157
  ob_dj_store/core/stores/models/_store.py,sha256=0K-CNJWuXNqeyULL1J0M9hiNcVla0UNNjdCdN_nzNEE,9833
157
- ob_dj_store/core/stores/models/_wallet.py,sha256=_qVNn2T0p-IIp4duiRSXLZ1hs9MeOnFrFabSghMWNgw,5341
158
+ ob_dj_store/core/stores/models/_wallet.py,sha256=YvT-rvED-jrYjePLJpvdLXXoBudR6TGPu5cNE0m2fWo,5643
158
159
  ob_dj_store/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
159
160
  ob_dj_store/utils/helpers.py,sha256=o7wgypM7mI2vZqZKkhxnTcnHJC8GMQDOuYMnRwXr6tY,2058
160
161
  ob_dj_store/utils/model.py,sha256=DV7hOhTaZL3gh9sptts2jTUFlTArKG3i7oPioq9HLFE,303
161
162
  ob_dj_store/utils/utils.py,sha256=8UVAFB56qUSjJJ5f9vnermtw638gdFy4CFRCuMbns_M,1342
162
- ob_dj_store-0.0.21.dist-info/METADATA,sha256=nNHhaaoDX74DIVkXI3-7yGfjgene_TVIED1B8dx0bxo,2848
163
- ob_dj_store-0.0.21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
164
- ob_dj_store-0.0.21.dist-info/top_level.txt,sha256=CZG3G0ptTkzGnc0dFYN-ZD7YKdJBmm47bsmGwofD_lk,12
165
- ob_dj_store-0.0.21.dist-info/RECORD,,
163
+ ob_dj_store-0.0.21.2.dist-info/METADATA,sha256=3N8bQGyJNEAIPzgZDu-MpfFdHHNPmEo3Uv4pTjgtK84,2850
164
+ ob_dj_store-0.0.21.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
165
+ ob_dj_store-0.0.21.2.dist-info/top_level.txt,sha256=CZG3G0ptTkzGnc0dFYN-ZD7YKdJBmm47bsmGwofD_lk,12
166
+ ob_dj_store-0.0.21.2.dist-info/RECORD,,