ob-dj-store 0.0.19__py3-none-any.whl → 0.0.23.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.
- ob_dj_store/apis/stores/filters.py +42 -19
- ob_dj_store/apis/stores/rest/serializers/serializers.py +256 -63
- ob_dj_store/apis/stores/urls.py +6 -0
- ob_dj_store/apis/stores/views.py +140 -227
- ob_dj_store/apis/stripe/__init__.py +0 -0
- ob_dj_store/apis/stripe/serializers.py +185 -0
- ob_dj_store/apis/stripe/urls.py +25 -0
- ob_dj_store/apis/stripe/views.py +191 -0
- ob_dj_store/apis/tap/views.py +2 -6
- ob_dj_store/core/stores/admin.py +41 -38
- ob_dj_store/core/stores/admin_inlines.py +8 -13
- ob_dj_store/core/stores/gateway/stripe/__init__.py +2 -0
- ob_dj_store/core/stores/gateway/stripe/admin.py +77 -0
- ob_dj_store/core/stores/gateway/stripe/apps.py +9 -0
- ob_dj_store/core/stores/gateway/stripe/managers.py +35 -0
- ob_dj_store/core/stores/gateway/stripe/migrations/0001_initial.py +168 -0
- ob_dj_store/core/stores/gateway/stripe/migrations/__init__.py +1 -0
- ob_dj_store/core/stores/gateway/stripe/models.py +174 -0
- ob_dj_store/core/stores/gateway/stripe/utils.py +170 -0
- ob_dj_store/core/stores/gateway/tap/admin.py +1 -3
- ob_dj_store/core/stores/gateway/tap/managers.py +1 -6
- ob_dj_store/core/stores/gateway/tap/migrations/0001_initial.py +1 -3
- ob_dj_store/core/stores/gateway/tap/migrations/0008_alter_tappayment_user.py +25 -0
- ob_dj_store/core/stores/gateway/tap/models.py +4 -13
- ob_dj_store/core/stores/gateway/tap/utils.py +2 -7
- ob_dj_store/core/stores/managers.py +12 -4
- ob_dj_store/core/stores/migrations/0001_initial.py +1 -4
- ob_dj_store/core/stores/migrations/0005_auto_20220425_2119.py +2 -5
- ob_dj_store/core/stores/migrations/0005_auto_20220427_1729.py +1 -2
- ob_dj_store/core/stores/migrations/0006_auto_20220428_0100.py +2 -8
- ob_dj_store/core/stores/migrations/0007_cart_cartitem_order_orderitem.py +2 -8
- ob_dj_store/core/stores/migrations/0010_auto_20220509_1633.py +1 -4
- ob_dj_store/core/stores/migrations/0012_auto_20220514_0633.py +1 -4
- ob_dj_store/core/stores/migrations/0013_auto_20220518_1539.py +1 -4
- ob_dj_store/core/stores/migrations/0014_auto_20220519_0018.py +3 -12
- ob_dj_store/core/stores/migrations/0017_auto_20220524_0912.py +3 -10
- ob_dj_store/core/stores/migrations/0018_auto_20220524_1613.py +1 -3
- ob_dj_store/core/stores/migrations/0021_auto_20220531_1849.py +1 -4
- ob_dj_store/core/stores/migrations/0026_auto_20220630_1913.py +8 -32
- ob_dj_store/core/stores/migrations/0031_auto_20220811_1733.py +1 -4
- ob_dj_store/core/stores/migrations/0033_auto_20220815_0133.py +2 -8
- ob_dj_store/core/stores/migrations/0039_auto_20220831_1521.py +1 -4
- ob_dj_store/core/stores/migrations/0044_remove_productvariant_has_inventory.py +1 -4
- ob_dj_store/core/stores/migrations/0049_auto_20221029_1524.py +2 -8
- ob_dj_store/core/stores/migrations/0050_favoriteextra.py +1 -3
- ob_dj_store/core/stores/migrations/0052_auto_20221129_1732.py +2 -8
- ob_dj_store/core/stores/migrations/0059_auto_20230217_2006.py +2 -8
- ob_dj_store/core/stores/migrations/0062_auto_20230226_2005.py +2 -6
- ob_dj_store/core/stores/migrations/0064_auto_20230228_1814.py +1 -2
- ob_dj_store/core/stores/migrations/0066_auto_20230304_1532.py +2 -8
- ob_dj_store/core/stores/migrations/0070_auto_20230323_1628.py +1 -4
- ob_dj_store/core/stores/migrations/0071_auto_20230328_1825.py +2 -5
- ob_dj_store/core/stores/migrations/0082_auto_20230613_1424.py +1 -4
- ob_dj_store/core/stores/migrations/0084_payment_result.py +1 -3
- ob_dj_store/core/stores/migrations/0087_auto_20230828_2138.py +1 -4
- ob_dj_store/core/stores/migrations/0097_auto_20231108_1939.py +1 -4
- ob_dj_store/core/stores/migrations/0100_remove_shippingmethod_type_arabic.py +1 -4
- ob_dj_store/core/stores/migrations/0106_alter_paymentmethod_payment_provider.py +35 -0
- ob_dj_store/core/stores/migrations/0107_auto_20250425_2059.py +29 -0
- ob_dj_store/core/stores/migrations/0108_alter_paymentmethod_payment_provider.py +35 -0
- ob_dj_store/core/stores/migrations/0109_wallettransaction_cashback_type.py +27 -0
- ob_dj_store/core/stores/migrations/0110_auto_20250923_1714.py +26 -0
- ob_dj_store/core/stores/migrations/0111_auto_20251023_1700.py +35 -0
- ob_dj_store/core/stores/migrations/0112_auto_20251027_1739.py +98 -0
- ob_dj_store/core/stores/migrations/0113_order_tax_value.py +20 -0
- ob_dj_store/core/stores/migrations/0114_store_mask_customer_info.py +18 -0
- ob_dj_store/core/stores/models/__init__.py +9 -1
- ob_dj_store/core/stores/models/_address.py +1 -3
- ob_dj_store/core/stores/models/_cart.py +11 -5
- ob_dj_store/core/stores/models/_feedback.py +1 -3
- ob_dj_store/core/stores/models/_inventory.py +3 -2
- ob_dj_store/core/stores/models/_order.py +69 -20
- ob_dj_store/core/stores/models/_payment.py +28 -24
- ob_dj_store/core/stores/models/_product.py +31 -17
- ob_dj_store/core/stores/models/_store.py +9 -13
- ob_dj_store/core/stores/models/_wallet.py +34 -26
- ob_dj_store/core/stores/receivers.py +43 -27
- ob_dj_store/core/stores/utils.py +1 -2
- {ob_dj_store-0.0.19.dist-info → ob_dj_store-0.0.23.2.dist-info}/METADATA +3 -2
- {ob_dj_store-0.0.19.dist-info → ob_dj_store-0.0.23.2.dist-info}/RECORD +82 -60
- {ob_dj_store-0.0.19.dist-info → ob_dj_store-0.0.23.2.dist-info}/WHEEL +1 -1
- {ob_dj_store-0.0.19.dist-info → ob_dj_store-0.0.23.2.dist-info}/top_level.txt +0 -0
|
@@ -141,7 +141,7 @@ class AvailabilityHours(DjangoModelCleanMixin, models.Model):
|
|
|
141
141
|
def clean(self) -> None:
|
|
142
142
|
super().clean()
|
|
143
143
|
try:
|
|
144
|
-
if self.store.is_open_after_midnight:
|
|
144
|
+
if self.store.current_opening_hours.is_open_after_midnight:
|
|
145
145
|
return
|
|
146
146
|
except Exception as e:
|
|
147
147
|
logger.info(f"OpeningHours has no store: {e}")
|
|
@@ -204,10 +204,7 @@ class Product(DjangoModelCleanMixin, models.Model):
|
|
|
204
204
|
|
|
205
205
|
name = models.CharField(max_length=200, help_text=_("Name"), unique=True)
|
|
206
206
|
name_arabic = models.CharField(
|
|
207
|
-
max_length=200,
|
|
208
|
-
null=True,
|
|
209
|
-
blank=True,
|
|
210
|
-
help_text=_("Name in arabic"),
|
|
207
|
+
max_length=200, null=True, blank=True, help_text=_("Name in arabic"),
|
|
211
208
|
)
|
|
212
209
|
slug = models.SlugField(max_length=255, unique=True)
|
|
213
210
|
label = models.CharField(
|
|
@@ -219,18 +216,11 @@ class Product(DjangoModelCleanMixin, models.Model):
|
|
|
219
216
|
description = models.TextField(null=True, blank=True)
|
|
220
217
|
description_arabic = models.TextField(null=True, blank=True)
|
|
221
218
|
# TODO: A product can be assigned to multiple categories
|
|
222
|
-
category = models.ManyToManyField(
|
|
223
|
-
Category,
|
|
224
|
-
related_name="products",
|
|
225
|
-
blank=True,
|
|
226
|
-
)
|
|
219
|
+
category = models.ManyToManyField(Category, related_name="products", blank=True,)
|
|
227
220
|
is_active = models.BooleanField(default=False)
|
|
228
221
|
is_featured = models.BooleanField(default=False)
|
|
229
222
|
tags = models.ManyToManyField(ProductTag, related_name="products", blank=True)
|
|
230
|
-
type = models.CharField(
|
|
231
|
-
max_length=32,
|
|
232
|
-
choices=ProductTypes.choices,
|
|
233
|
-
)
|
|
223
|
+
type = models.CharField(max_length=32, choices=ProductTypes.choices,)
|
|
234
224
|
plu = models.CharField(max_length=40, unique=True, null=True, blank=True)
|
|
235
225
|
external_id = models.CharField(max_length=40, unique=True, null=True, blank=True)
|
|
236
226
|
order_value = models.PositiveSmallIntegerField(
|
|
@@ -258,6 +248,28 @@ class Product(DjangoModelCleanMixin, models.Model):
|
|
|
258
248
|
def __str__(self):
|
|
259
249
|
return f"Product {self.name} (PK={self.pk})"
|
|
260
250
|
|
|
251
|
+
def get_inventory(self, store_id):
|
|
252
|
+
try:
|
|
253
|
+
# Prefer the primary variant if available
|
|
254
|
+
product_variant = (
|
|
255
|
+
self.product_variants.filter(inventories__is_primary=True).first()
|
|
256
|
+
or self.product_variants.first()
|
|
257
|
+
)
|
|
258
|
+
if not product_variant:
|
|
259
|
+
return None
|
|
260
|
+
return product_variant.inventories.get(store_id=store_id)
|
|
261
|
+
except ObjectDoesNotExist:
|
|
262
|
+
return None
|
|
263
|
+
|
|
264
|
+
def is_snoozed(self, store_id):
|
|
265
|
+
try:
|
|
266
|
+
inventory = self.product_variants.first().inventories.get(store=store_id)
|
|
267
|
+
except ObjectDoesNotExist:
|
|
268
|
+
return False
|
|
269
|
+
if not self.is_active:
|
|
270
|
+
return True
|
|
271
|
+
return inventory.is_snoozed
|
|
272
|
+
|
|
261
273
|
|
|
262
274
|
# TODO: must remove, redundunt
|
|
263
275
|
class Attribute(DjangoModelCleanMixin, models.Model):
|
|
@@ -377,9 +389,7 @@ class ProductAttribute(DjangoModelCleanMixin, models.Model):
|
|
|
377
389
|
AttributeChoice, related_name="product_attributes", blank=True
|
|
378
390
|
)
|
|
379
391
|
type = models.CharField(
|
|
380
|
-
max_length=32,
|
|
381
|
-
default=Type.ONE_CHOICE,
|
|
382
|
-
choices=Type.choices,
|
|
392
|
+
max_length=32, default=Type.ONE_CHOICE, choices=Type.choices,
|
|
383
393
|
)
|
|
384
394
|
order_value = models.PositiveSmallIntegerField(
|
|
385
395
|
verbose_name=_("ordering"), default=1
|
|
@@ -439,6 +449,9 @@ class ProductVariant(DjangoModelCleanMixin, models.Model):
|
|
|
439
449
|
image_thumbnail_medium = models.ImageField(
|
|
440
450
|
upload_to="product_variant_media/", null=True, blank=True
|
|
441
451
|
)
|
|
452
|
+
order_value = models.PositiveSmallIntegerField(
|
|
453
|
+
verbose_name=_("ordering"), default=1
|
|
454
|
+
)
|
|
442
455
|
# Audit fields
|
|
443
456
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
444
457
|
updated_at = models.DateTimeField(auto_now=True)
|
|
@@ -448,6 +461,7 @@ class ProductVariant(DjangoModelCleanMixin, models.Model):
|
|
|
448
461
|
class Meta:
|
|
449
462
|
verbose_name = _("Product Variation")
|
|
450
463
|
verbose_name_plural = _("Product Variations")
|
|
464
|
+
ordering = ("order_value",)
|
|
451
465
|
|
|
452
466
|
def __str__(self):
|
|
453
467
|
return f"Variation {self.product.name} {self.name} (PK={self.pk})"
|
|
@@ -8,6 +8,7 @@ from django.utils.timezone import now
|
|
|
8
8
|
from django.utils.translation import gettext_lazy as _
|
|
9
9
|
from django_countries.fields import CountryField
|
|
10
10
|
from phonenumber_field.modelfields import PhoneNumberField
|
|
11
|
+
from timezone_field import TimeZoneField
|
|
11
12
|
|
|
12
13
|
from ob_dj_store.core.stores.managers import (
|
|
13
14
|
CountryPaymentMethodManager,
|
|
@@ -85,9 +86,7 @@ class PaymentMethod(models.Model):
|
|
|
85
86
|
"""
|
|
86
87
|
|
|
87
88
|
payment_provider = models.CharField(
|
|
88
|
-
max_length=20,
|
|
89
|
-
choices=settings.PAYMENT_PROVIDER_CHOICES,
|
|
90
|
-
default="cod",
|
|
89
|
+
max_length=20, choices=settings.PAYMENT_PROVIDER_CHOICES, default="cod",
|
|
91
90
|
)
|
|
92
91
|
is_active = models.BooleanField(default=True)
|
|
93
92
|
name = models.CharField(max_length=200, help_text=_("Name"))
|
|
@@ -149,9 +148,7 @@ class Store(DjangoModelCleanMixin, models.Model):
|
|
|
149
148
|
help_text=_("Shipping methods within the store"),
|
|
150
149
|
)
|
|
151
150
|
pickup_addresses = models.ManyToManyField(
|
|
152
|
-
"stores.address",
|
|
153
|
-
related_name="pickup_stores",
|
|
154
|
-
blank=True,
|
|
151
|
+
"stores.address", related_name="pickup_stores", blank=True,
|
|
155
152
|
)
|
|
156
153
|
payment_methods = models.ManyToManyField(
|
|
157
154
|
PaymentMethod,
|
|
@@ -179,15 +176,13 @@ class Store(DjangoModelCleanMixin, models.Model):
|
|
|
179
176
|
)
|
|
180
177
|
image = models.ImageField(upload_to=store_media_upload_to, null=True, blank=True)
|
|
181
178
|
currency = models.CharField(
|
|
182
|
-
max_length=3,
|
|
183
|
-
default="KWD",
|
|
184
|
-
validators=[
|
|
185
|
-
validate_currency,
|
|
186
|
-
],
|
|
179
|
+
max_length=3, default="KWD", validators=[validate_currency,],
|
|
187
180
|
)
|
|
188
181
|
busy_mode = models.BooleanField(default=False)
|
|
189
182
|
is_digital = models.BooleanField(default=False)
|
|
190
|
-
|
|
183
|
+
timezone = TimeZoneField(default="Asia/Kuwait")
|
|
184
|
+
has_daylight_saving_time = models.BooleanField(default=False)
|
|
185
|
+
mask_customer_info = models.BooleanField(default=False)
|
|
191
186
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
192
187
|
updated_at = models.DateTimeField(auto_now=True)
|
|
193
188
|
|
|
@@ -246,6 +241,7 @@ class OpeningHours(DjangoModelCleanMixin, models.Model):
|
|
|
246
241
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
247
242
|
updated_at = models.DateTimeField(auto_now=True)
|
|
248
243
|
always_open = models.BooleanField(default=False)
|
|
244
|
+
is_open_after_midnight = models.BooleanField(default=False)
|
|
249
245
|
|
|
250
246
|
class Meta:
|
|
251
247
|
ordering = ("weekday", "from_hour")
|
|
@@ -260,7 +256,7 @@ class OpeningHours(DjangoModelCleanMixin, models.Model):
|
|
|
260
256
|
def clean(self) -> None:
|
|
261
257
|
super().clean()
|
|
262
258
|
try:
|
|
263
|
-
if self.store
|
|
259
|
+
if self.store:
|
|
264
260
|
return
|
|
265
261
|
except Exception as e:
|
|
266
262
|
logger.info(f"OpeningHours has no store: {e}")
|
|
@@ -47,9 +47,7 @@ class WalletMedia(DjangoModelCleanMixin, models.Model):
|
|
|
47
47
|
|
|
48
48
|
class Wallet(models.Model):
|
|
49
49
|
user = models.ForeignKey(
|
|
50
|
-
settings.AUTH_USER_MODEL,
|
|
51
|
-
on_delete=models.CASCADE,
|
|
52
|
-
related_name="wallets",
|
|
50
|
+
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="wallets",
|
|
53
51
|
)
|
|
54
52
|
name = models.CharField(max_length=200, null=True, blank=True)
|
|
55
53
|
name_arabic = models.CharField(max_length=200, null=True, blank=True)
|
|
@@ -61,11 +59,7 @@ class Wallet(models.Model):
|
|
|
61
59
|
related_name="wallets",
|
|
62
60
|
)
|
|
63
61
|
currency = models.CharField(
|
|
64
|
-
max_length=3,
|
|
65
|
-
default="KWD",
|
|
66
|
-
validators=[
|
|
67
|
-
validate_currency,
|
|
68
|
-
],
|
|
62
|
+
max_length=3, default="KWD", validators=[validate_currency,],
|
|
69
63
|
)
|
|
70
64
|
is_active = models.BooleanField(default=True)
|
|
71
65
|
|
|
@@ -82,8 +76,7 @@ class Wallet(models.Model):
|
|
|
82
76
|
query = self.transactions.aggregate(
|
|
83
77
|
balance=Coalesce(
|
|
84
78
|
models.Sum(
|
|
85
|
-
"amount",
|
|
86
|
-
filter=models.Q(type=WalletTransaction.TYPE.CREDIT),
|
|
79
|
+
"amount", filter=models.Q(type=WalletTransaction.TYPE.CREDIT),
|
|
87
80
|
),
|
|
88
81
|
models.Value(Decimal(0)),
|
|
89
82
|
output_field=models.DecimalField(),
|
|
@@ -118,21 +111,34 @@ class Wallet(models.Model):
|
|
|
118
111
|
)
|
|
119
112
|
user = self.user
|
|
120
113
|
order = Order.objects.create(
|
|
121
|
-
customer=user,
|
|
122
|
-
payment_method=payment_method,
|
|
123
|
-
extra_infos=extra_infos,
|
|
114
|
+
customer=user, payment_method=payment_method, extra_infos=extra_infos,
|
|
124
115
|
)
|
|
125
116
|
payment = Payment.objects.create(
|
|
126
|
-
orders=[
|
|
127
|
-
order,
|
|
128
|
-
],
|
|
117
|
+
orders=[order,],
|
|
129
118
|
user=user,
|
|
130
119
|
currency=self.currency,
|
|
131
120
|
method=payment_method,
|
|
132
121
|
amount=amount,
|
|
133
122
|
)
|
|
134
|
-
|
|
135
|
-
|
|
123
|
+
|
|
124
|
+
provider = payment_method.payment_provider
|
|
125
|
+
logger.info(f"Payment ID: {payment.id}")
|
|
126
|
+
logger.info(f"Payment provider: {provider}")
|
|
127
|
+
try:
|
|
128
|
+
if provider == settings.STRIPE:
|
|
129
|
+
logger.info(
|
|
130
|
+
f"Stripe payment info: {payment.stripe_payment.payment_intent_id}"
|
|
131
|
+
)
|
|
132
|
+
return (
|
|
133
|
+
payment.stripe_payment.payment_url,
|
|
134
|
+
payment.stripe_payment.payment_intent_id,
|
|
135
|
+
)
|
|
136
|
+
else:
|
|
137
|
+
logger.info(f"TAP payment info: {payment.tap_payment.charge_id}")
|
|
138
|
+
return (payment.tap_payment.payment_url, payment.tap_payment.charge_id)
|
|
139
|
+
except Exception as e:
|
|
140
|
+
logger.warning(f"Error returning payment details")
|
|
141
|
+
return (None, None)
|
|
136
142
|
|
|
137
143
|
|
|
138
144
|
class WalletTransaction(models.Model):
|
|
@@ -147,15 +153,15 @@ class WalletTransaction(models.Model):
|
|
|
147
153
|
CREDIT = "CREDIT", _("credit")
|
|
148
154
|
DEBIT = "DEBIT", _("debit")
|
|
149
155
|
|
|
156
|
+
class CashBackType(models.TextChoices):
|
|
157
|
+
BY_ORDER = "BY_ORDER", _("By Order")
|
|
158
|
+
BY_OFFER = "BY_OFFER", _("By Offer")
|
|
159
|
+
BY_STREAK = "BY_STREAK", _("By Streak")
|
|
160
|
+
|
|
150
161
|
wallet = models.ForeignKey(
|
|
151
|
-
"stores.Wallet",
|
|
152
|
-
on_delete=models.CASCADE,
|
|
153
|
-
related_name="transactions",
|
|
154
|
-
)
|
|
155
|
-
type = models.CharField(
|
|
156
|
-
max_length=100,
|
|
157
|
-
choices=TYPE.choices,
|
|
162
|
+
"stores.Wallet", on_delete=models.CASCADE, related_name="transactions",
|
|
158
163
|
)
|
|
164
|
+
type = models.CharField(max_length=100, choices=TYPE.choices,)
|
|
159
165
|
|
|
160
166
|
amount = models.DecimalField(
|
|
161
167
|
max_digits=settings.DEFAULT_MAX_DIGITS,
|
|
@@ -166,7 +172,9 @@ class WalletTransaction(models.Model):
|
|
|
166
172
|
is_cashback = models.BooleanField(default=False)
|
|
167
173
|
is_refund = models.BooleanField(default=False)
|
|
168
174
|
is_redeemed = models.BooleanField(default=False)
|
|
169
|
-
|
|
175
|
+
cashback_type = models.CharField(
|
|
176
|
+
max_length=100, choices=CashBackType.choices, blank=True, null=True
|
|
177
|
+
)
|
|
170
178
|
objects = WalletTransactionManager()
|
|
171
179
|
|
|
172
180
|
# Audit
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
1
3
|
from django.conf import settings
|
|
2
4
|
from django.db.models.signals import post_save, pre_save
|
|
3
5
|
from django.dispatch import receiver
|
|
@@ -12,8 +14,11 @@ from ob_dj_store.core.stores.models import (
|
|
|
12
14
|
ProductVariant,
|
|
13
15
|
WalletMedia,
|
|
14
16
|
)
|
|
17
|
+
from ob_dj_store.core.stores.utils import get_currency_by_country
|
|
15
18
|
from ob_dj_store.utils.utils import resize_image
|
|
16
19
|
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
17
22
|
|
|
18
23
|
@receiver(
|
|
19
24
|
post_save,
|
|
@@ -21,37 +26,56 @@ from ob_dj_store.utils.utils import resize_image
|
|
|
21
26
|
dispatch_uid="create_customer_cart_and_wallet_handler",
|
|
22
27
|
)
|
|
23
28
|
def create_customer_cart_and_wallet_handler(sender, instance, created, **kwargs):
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
try:
|
|
30
|
+
logger.info(f"Creating cart and wallet for user {instance.id}")
|
|
31
|
+
if not hasattr(instance, "cart"):
|
|
32
|
+
cart = Cart(customer=instance)
|
|
33
|
+
cart.save()
|
|
34
|
+
|
|
35
|
+
wallet_media = WalletMedia.objects.filter(is_default=True)
|
|
36
|
+
wallet_currencies = settings.WALLET_CURRENCIES
|
|
37
|
+
logger.info(f"Wallet currencies: {wallet_currencies}")
|
|
38
|
+
# getattr(instance, "country", "") : only for bypassing ob_dj_store users
|
|
39
|
+
if getattr(instance, "country", "") and instance.country:
|
|
40
|
+
currency = get_currency_by_country(instance.country.code)
|
|
41
|
+
if currency not in wallet_currencies:
|
|
42
|
+
wallet_currencies = settings.US_WALLET_CURRENCIES
|
|
43
|
+
logger.info(f"Wallet currencies: {wallet_currencies}")
|
|
44
|
+
|
|
45
|
+
# check if wallet exists since we now run the signal on every user update
|
|
46
|
+
for currency in wallet_currencies:
|
|
47
|
+
instance.wallets.get_or_create(
|
|
48
|
+
currency=currency, media_image=wallet_media.first()
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# delete gcc wallets if exists for US based users
|
|
52
|
+
if getattr(instance, "country", "") and instance.country:
|
|
53
|
+
currency = get_currency_by_country(instance.country.code)
|
|
54
|
+
if currency in settings.US_WALLET_CURRENCIES:
|
|
55
|
+
instance.wallets.filter(
|
|
56
|
+
currency__in=settings.WALLET_CURRENCIES
|
|
57
|
+
).delete()
|
|
58
|
+
except Exception:
|
|
59
|
+
logger.error(f"Error creating cart for user {instance.id}")
|
|
31
60
|
|
|
32
61
|
|
|
33
62
|
# add receiver to ProductVariant to create inventory
|
|
34
63
|
|
|
35
64
|
|
|
36
65
|
@receiver(
|
|
37
|
-
post_save,
|
|
38
|
-
sender=Order,
|
|
39
|
-
dispatch_uid="create_order_history_handler",
|
|
66
|
+
post_save, sender=Order, dispatch_uid="create_order_history_handler",
|
|
40
67
|
)
|
|
41
68
|
def create_order_history_handler(sender, instance, created, **kwargs):
|
|
42
69
|
try:
|
|
43
70
|
OrderHistory.objects.create(
|
|
44
|
-
order=instance,
|
|
45
|
-
status=instance.status,
|
|
71
|
+
order=instance, status=instance.status,
|
|
46
72
|
)
|
|
47
73
|
except Exception:
|
|
48
74
|
pass
|
|
49
75
|
|
|
50
76
|
|
|
51
77
|
@receiver(
|
|
52
|
-
pre_save,
|
|
53
|
-
sender=Category,
|
|
54
|
-
dispatch_uid="create_category_thumbnails",
|
|
78
|
+
pre_save, sender=Category, dispatch_uid="create_category_thumbnails",
|
|
55
79
|
)
|
|
56
80
|
def create_category_thumbnails(sender, instance, **kwargs):
|
|
57
81
|
medium_dim = getattr(store_settings, "THUMBNAIL_MEDIUM_DIMENSIONS", None)
|
|
@@ -74,9 +98,7 @@ def create_category_thumbnails(sender, instance, **kwargs):
|
|
|
74
98
|
|
|
75
99
|
|
|
76
100
|
@receiver(
|
|
77
|
-
pre_save,
|
|
78
|
-
sender=ProductMedia,
|
|
79
|
-
dispatch_uid="create_product_media_thumbnails",
|
|
101
|
+
pre_save, sender=ProductMedia, dispatch_uid="create_product_media_thumbnails",
|
|
80
102
|
)
|
|
81
103
|
def create_product_media_thumbnails(sender, instance, **kwargs):
|
|
82
104
|
medium_dim = getattr(store_settings, "THUMBNAIL_MEDIUM_DIMENSIONS", None)
|
|
@@ -99,17 +121,13 @@ def create_product_media_thumbnails(sender, instance, **kwargs):
|
|
|
99
121
|
|
|
100
122
|
|
|
101
123
|
@receiver(
|
|
102
|
-
pre_save,
|
|
103
|
-
sender=WalletMedia,
|
|
104
|
-
dispatch_uid="create_wallet_thumbnails",
|
|
124
|
+
pre_save, sender=WalletMedia, dispatch_uid="create_wallet_thumbnails",
|
|
105
125
|
)
|
|
106
126
|
def create_wallet_thumbnails(sender, instance, **kwargs):
|
|
107
127
|
medium_dim = getattr(store_settings, "THUMBNAIL_MEDIUM_DIMENSIONS", None)
|
|
108
128
|
if instance.image and medium_dim:
|
|
109
129
|
instance.image_thumbnail_medium = resize_image(
|
|
110
|
-
instance.image,
|
|
111
|
-
dim=medium_dim,
|
|
112
|
-
size_name="medium",
|
|
130
|
+
instance.image, dim=medium_dim, size_name="medium",
|
|
113
131
|
)
|
|
114
132
|
|
|
115
133
|
|
|
@@ -122,7 +140,5 @@ def create_product_vraiant_image_thumbnails(sender, instance, **kwargs):
|
|
|
122
140
|
medium_dim = getattr(store_settings, "THUMBNAIL_MEDIUM_DIMENSIONS", None)
|
|
123
141
|
if instance.image and medium_dim:
|
|
124
142
|
instance.image_thumbnail_medium = resize_image(
|
|
125
|
-
instance.image,
|
|
126
|
-
dim=medium_dim,
|
|
127
|
-
size_name="medium",
|
|
143
|
+
instance.image, dim=medium_dim, size_name="medium",
|
|
128
144
|
)
|
ob_dj_store/core/stores/utils.py
CHANGED
|
@@ -76,8 +76,7 @@ def get_country_by_currency(currency):
|
|
|
76
76
|
def validate_currency(value):
|
|
77
77
|
if not pycountry.currencies.get(alpha_3=value):
|
|
78
78
|
raise ValidationError(
|
|
79
|
-
_("%(value)s is not a currency"),
|
|
80
|
-
params={"value": value},
|
|
79
|
+
_("%(value)s is not a currency"), params={"value": value},
|
|
81
80
|
)
|
|
82
81
|
|
|
83
82
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: ob-dj-store
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.23.2
|
|
4
4
|
Summary: OBytes django application for managing ecommerce stores.
|
|
5
5
|
Home-page: https://www.obytes.com/
|
|
6
6
|
Author: OBytes
|
|
@@ -25,6 +25,7 @@ Requires-Dist: djangorestframework-gis
|
|
|
25
25
|
Requires-Dist: django-filter
|
|
26
26
|
Requires-Dist: django-leaflet
|
|
27
27
|
Requires-Dist: django-countries
|
|
28
|
+
Dynamic: requires-dist
|
|
28
29
|
|
|
29
30
|
## OBytes Django Store App
|
|
30
31
|
|