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.
Files changed (82) hide show
  1. ob_dj_store/apis/stores/filters.py +42 -19
  2. ob_dj_store/apis/stores/rest/serializers/serializers.py +256 -63
  3. ob_dj_store/apis/stores/urls.py +6 -0
  4. ob_dj_store/apis/stores/views.py +140 -227
  5. ob_dj_store/apis/stripe/__init__.py +0 -0
  6. ob_dj_store/apis/stripe/serializers.py +185 -0
  7. ob_dj_store/apis/stripe/urls.py +25 -0
  8. ob_dj_store/apis/stripe/views.py +191 -0
  9. ob_dj_store/apis/tap/views.py +2 -6
  10. ob_dj_store/core/stores/admin.py +41 -38
  11. ob_dj_store/core/stores/admin_inlines.py +8 -13
  12. ob_dj_store/core/stores/gateway/stripe/__init__.py +2 -0
  13. ob_dj_store/core/stores/gateway/stripe/admin.py +77 -0
  14. ob_dj_store/core/stores/gateway/stripe/apps.py +9 -0
  15. ob_dj_store/core/stores/gateway/stripe/managers.py +35 -0
  16. ob_dj_store/core/stores/gateway/stripe/migrations/0001_initial.py +168 -0
  17. ob_dj_store/core/stores/gateway/stripe/migrations/__init__.py +1 -0
  18. ob_dj_store/core/stores/gateway/stripe/models.py +174 -0
  19. ob_dj_store/core/stores/gateway/stripe/utils.py +170 -0
  20. ob_dj_store/core/stores/gateway/tap/admin.py +1 -3
  21. ob_dj_store/core/stores/gateway/tap/managers.py +1 -6
  22. ob_dj_store/core/stores/gateway/tap/migrations/0001_initial.py +1 -3
  23. ob_dj_store/core/stores/gateway/tap/migrations/0008_alter_tappayment_user.py +25 -0
  24. ob_dj_store/core/stores/gateway/tap/models.py +4 -13
  25. ob_dj_store/core/stores/gateway/tap/utils.py +2 -7
  26. ob_dj_store/core/stores/managers.py +12 -4
  27. ob_dj_store/core/stores/migrations/0001_initial.py +1 -4
  28. ob_dj_store/core/stores/migrations/0005_auto_20220425_2119.py +2 -5
  29. ob_dj_store/core/stores/migrations/0005_auto_20220427_1729.py +1 -2
  30. ob_dj_store/core/stores/migrations/0006_auto_20220428_0100.py +2 -8
  31. ob_dj_store/core/stores/migrations/0007_cart_cartitem_order_orderitem.py +2 -8
  32. ob_dj_store/core/stores/migrations/0010_auto_20220509_1633.py +1 -4
  33. ob_dj_store/core/stores/migrations/0012_auto_20220514_0633.py +1 -4
  34. ob_dj_store/core/stores/migrations/0013_auto_20220518_1539.py +1 -4
  35. ob_dj_store/core/stores/migrations/0014_auto_20220519_0018.py +3 -12
  36. ob_dj_store/core/stores/migrations/0017_auto_20220524_0912.py +3 -10
  37. ob_dj_store/core/stores/migrations/0018_auto_20220524_1613.py +1 -3
  38. ob_dj_store/core/stores/migrations/0021_auto_20220531_1849.py +1 -4
  39. ob_dj_store/core/stores/migrations/0026_auto_20220630_1913.py +8 -32
  40. ob_dj_store/core/stores/migrations/0031_auto_20220811_1733.py +1 -4
  41. ob_dj_store/core/stores/migrations/0033_auto_20220815_0133.py +2 -8
  42. ob_dj_store/core/stores/migrations/0039_auto_20220831_1521.py +1 -4
  43. ob_dj_store/core/stores/migrations/0044_remove_productvariant_has_inventory.py +1 -4
  44. ob_dj_store/core/stores/migrations/0049_auto_20221029_1524.py +2 -8
  45. ob_dj_store/core/stores/migrations/0050_favoriteextra.py +1 -3
  46. ob_dj_store/core/stores/migrations/0052_auto_20221129_1732.py +2 -8
  47. ob_dj_store/core/stores/migrations/0059_auto_20230217_2006.py +2 -8
  48. ob_dj_store/core/stores/migrations/0062_auto_20230226_2005.py +2 -6
  49. ob_dj_store/core/stores/migrations/0064_auto_20230228_1814.py +1 -2
  50. ob_dj_store/core/stores/migrations/0066_auto_20230304_1532.py +2 -8
  51. ob_dj_store/core/stores/migrations/0070_auto_20230323_1628.py +1 -4
  52. ob_dj_store/core/stores/migrations/0071_auto_20230328_1825.py +2 -5
  53. ob_dj_store/core/stores/migrations/0082_auto_20230613_1424.py +1 -4
  54. ob_dj_store/core/stores/migrations/0084_payment_result.py +1 -3
  55. ob_dj_store/core/stores/migrations/0087_auto_20230828_2138.py +1 -4
  56. ob_dj_store/core/stores/migrations/0097_auto_20231108_1939.py +1 -4
  57. ob_dj_store/core/stores/migrations/0100_remove_shippingmethod_type_arabic.py +1 -4
  58. ob_dj_store/core/stores/migrations/0106_alter_paymentmethod_payment_provider.py +35 -0
  59. ob_dj_store/core/stores/migrations/0107_auto_20250425_2059.py +29 -0
  60. ob_dj_store/core/stores/migrations/0108_alter_paymentmethod_payment_provider.py +35 -0
  61. ob_dj_store/core/stores/migrations/0109_wallettransaction_cashback_type.py +27 -0
  62. ob_dj_store/core/stores/migrations/0110_auto_20250923_1714.py +26 -0
  63. ob_dj_store/core/stores/migrations/0111_auto_20251023_1700.py +35 -0
  64. ob_dj_store/core/stores/migrations/0112_auto_20251027_1739.py +98 -0
  65. ob_dj_store/core/stores/migrations/0113_order_tax_value.py +20 -0
  66. ob_dj_store/core/stores/migrations/0114_store_mask_customer_info.py +18 -0
  67. ob_dj_store/core/stores/models/__init__.py +9 -1
  68. ob_dj_store/core/stores/models/_address.py +1 -3
  69. ob_dj_store/core/stores/models/_cart.py +11 -5
  70. ob_dj_store/core/stores/models/_feedback.py +1 -3
  71. ob_dj_store/core/stores/models/_inventory.py +3 -2
  72. ob_dj_store/core/stores/models/_order.py +69 -20
  73. ob_dj_store/core/stores/models/_payment.py +28 -24
  74. ob_dj_store/core/stores/models/_product.py +31 -17
  75. ob_dj_store/core/stores/models/_store.py +9 -13
  76. ob_dj_store/core/stores/models/_wallet.py +34 -26
  77. ob_dj_store/core/stores/receivers.py +43 -27
  78. ob_dj_store/core/stores/utils.py +1 -2
  79. {ob_dj_store-0.0.19.dist-info → ob_dj_store-0.0.23.2.dist-info}/METADATA +3 -2
  80. {ob_dj_store-0.0.19.dist-info → ob_dj_store-0.0.23.2.dist-info}/RECORD +82 -60
  81. {ob_dj_store-0.0.19.dist-info → ob_dj_store-0.0.23.2.dist-info}/WHEEL +1 -1
  82. {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
- is_open_after_midnight = models.BooleanField(default=False)
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.is_open_after_midnight:
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
- tap_payment = payment.tap_payment
135
- return (tap_payment.payment_url, tap_payment.charge_id)
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
- if not created:
25
- return
26
- cart = Cart(customer=instance)
27
- cart.save()
28
- wallet_media = WalletMedia.objects.filter(is_default=True)
29
- for currency in store_settings.WALLET_CURRENCIES:
30
- instance.wallets.create(currency=currency, media_image=wallet_media.first())
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
  )
@@ -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
1
+ Metadata-Version: 2.4
2
2
  Name: ob-dj-store
3
- Version: 0.0.19
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