+ PriceSnapshot
* Category commission inside a commission_rub field
This commit is contained in:
parent
ce59792419
commit
8c0f5ac6fd
|
|
@ -0,0 +1,29 @@
|
|||
# Generated by Django 4.2.2 on 2023-10-04 02:53
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('store', '0042_oldchecklist_checklist_split_payment_proof_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PriceSnapshot',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('yuan_rate', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='Курс CNY/RUB')),
|
||||
('delivery_price_CN', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='Цена доставки по Китаю')),
|
||||
('delivery_price_CN_RU', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='Цена доставки Китай-РФ')),
|
||||
('commission_rub', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='Комиссия, руб')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='checklist',
|
||||
name='price_snapshot',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='checklist', to='store.pricesnapshot', verbose_name='Сохраненные цены'),
|
||||
),
|
||||
]
|
||||
116
store/models.py
116
store/models.py
|
|
@ -228,17 +228,23 @@ def generate_checklist_id():
|
|||
|
||||
class ChecklistQuerySet(models.QuerySet):
|
||||
def with_base_related(self):
|
||||
return self.select_related('manager', 'category', 'payment_method', 'promocode')\
|
||||
return self.select_related('manager', 'category', 'payment_method', 'promocode', 'price_snapshot')\
|
||||
.prefetch_related(Prefetch('images', to_attr='_images'))
|
||||
|
||||
def default_ordering(self):
|
||||
return self.order_by(F('status_updated_at').desc(nulls_last=True))
|
||||
|
||||
def annotate_price_rub(self):
|
||||
# FIXME: implement price_rub in DB query
|
||||
return self
|
||||
|
||||
yuan_rate = GlobalSettings.load().yuan_rate
|
||||
return self.annotate(_price_rub=F('price_yuan') * yuan_rate)
|
||||
|
||||
def annotate_commission_rub(self):
|
||||
# FIXME: implement category commission in DB query
|
||||
return self
|
||||
|
||||
commission = GlobalSettings.load().commission_rub
|
||||
return self.annotate(_commission_rub=Case(
|
||||
When(GreaterThan(F("_price_rub"), 150_000), then=F("_price_rub") * settings.COMMISSION_OVER_150K),
|
||||
|
|
@ -247,6 +253,13 @@ class ChecklistQuerySet(models.QuerySet):
|
|||
))
|
||||
|
||||
|
||||
class PriceSnapshot(models.Model):
|
||||
yuan_rate = models.DecimalField('Курс CNY/RUB', max_digits=10, decimal_places=2, default=0)
|
||||
delivery_price_CN = models.DecimalField('Цена доставки по Китаю', max_digits=10, decimal_places=2, default=0)
|
||||
delivery_price_CN_RU = models.DecimalField('Цена доставки Китай-РФ', max_digits=10, decimal_places=2, default=0)
|
||||
commission_rub = models.DecimalField('Комиссия, руб', max_digits=10, decimal_places=2, default=0)
|
||||
|
||||
|
||||
@cleanup.select
|
||||
class Checklist(models.Model):
|
||||
# Statuses
|
||||
|
|
@ -350,6 +363,10 @@ class Checklist(models.Model):
|
|||
cdek_tracking = models.CharField('Трек-номер СДЭК', max_length=100, null=True, blank=True)
|
||||
cdek_barcode_pdf = models.FileField('Штрих-код СДЭК в PDF', upload_to='docs', null=True, blank=True)
|
||||
|
||||
price_snapshot = models.ForeignKey('PriceSnapshot', verbose_name='Сохраненные цены',
|
||||
related_name='checklist',
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
|
||||
objects = ChecklistQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
|
|
@ -368,11 +385,18 @@ class Checklist(models.Model):
|
|||
|
||||
@property
|
||||
def price_rub(self) -> int:
|
||||
# Prefer annotated field
|
||||
if hasattr(self, '_price_rub'):
|
||||
return self._price_rub
|
||||
# FIXME: implement price_rub in DB query
|
||||
# # Prefer annotated field for calculation
|
||||
# if hasattr(self, '_price_rub'):
|
||||
# return self._price_rub
|
||||
|
||||
return math.ceil(GlobalSettings.load().yuan_rate * self.price_yuan)
|
||||
# Get saved prices
|
||||
if self.price_snapshot_id:
|
||||
yuan_rate = self.price_snapshot.yuan_rate
|
||||
else:
|
||||
yuan_rate = GlobalSettings.load().yuan_rate
|
||||
|
||||
return math.ceil(yuan_rate * self.price_yuan)
|
||||
|
||||
@property
|
||||
def full_price(self) -> int:
|
||||
|
|
@ -392,32 +416,58 @@ class Checklist(models.Model):
|
|||
no_comission = promocode.no_comission
|
||||
|
||||
if not free_delivery:
|
||||
price += GlobalSettings.load().delivery_price_CN + self.delivery_price_CN_RU
|
||||
price += self.delivery_price_CN + self.delivery_price_CN_RU
|
||||
|
||||
if not no_comission:
|
||||
price += self.commission_rub
|
||||
|
||||
# Add commission of bottom-most category
|
||||
if self.category:
|
||||
category = self.category.get_ancestors(ascending=True, include_self=True).first()
|
||||
category_commission = getattr(category, 'commission', 0)
|
||||
price += category_commission * self.price_rub / 100
|
||||
|
||||
return max(0, math.ceil(price))
|
||||
|
||||
@property
|
||||
def yuan_rate(self) -> Decimal:
|
||||
# Get saved value if exists
|
||||
if self.price_snapshot_id:
|
||||
return self.price_snapshot.yuan_rate
|
||||
else:
|
||||
return GlobalSettings.load().yuan_rate
|
||||
|
||||
@property
|
||||
def delivery_price_CN(self) -> Decimal:
|
||||
# Get saved value if exists
|
||||
if self.price_snapshot_id:
|
||||
return self.price_snapshot.delivery_price_CN
|
||||
else:
|
||||
return GlobalSettings.load().delivery_price_CN
|
||||
|
||||
@property
|
||||
def delivery_price_CN_RU(self) -> Decimal:
|
||||
return getattr(self.category, 'delivery_price_CN_RU', Decimal(0))
|
||||
# Get saved value if exists
|
||||
if self.price_snapshot_id:
|
||||
return self.price_snapshot.delivery_price_CN_RU
|
||||
else:
|
||||
return getattr(self.category, 'delivery_price_CN_RU', Decimal(0))
|
||||
|
||||
@property
|
||||
def commission_rub(self) -> Decimal:
|
||||
# Prefer annotated field
|
||||
if hasattr(self, '_commission_rub'):
|
||||
return self._commission_rub
|
||||
# FIXME: implement category commission in DB query
|
||||
# # Prefer annotated field
|
||||
# if hasattr(self, '_commission_rub'):
|
||||
# return self._commission_rub
|
||||
|
||||
return (self.price_rub * Decimal(settings.COMMISSION_OVER_150K)
|
||||
if self.price_rub > 150_000
|
||||
else GlobalSettings.load().commission_rub)
|
||||
# Prefer saved value
|
||||
if self.price_snapshot_id:
|
||||
return self.price_snapshot.commission_rub
|
||||
|
||||
commission = (self.price_rub * Decimal(settings.COMMISSION_OVER_150K)
|
||||
if self.price_rub > 150_000
|
||||
else GlobalSettings.load().commission_rub)
|
||||
|
||||
# Add commission of bottom-most category
|
||||
if self.category_id:
|
||||
category_commission = getattr(self.category, 'commission', 0)
|
||||
commission += category_commission * self.price_rub / 100
|
||||
|
||||
return commission
|
||||
|
||||
@property
|
||||
def preview_image(self):
|
||||
|
|
@ -467,9 +517,27 @@ class Checklist(models.Model):
|
|||
|
||||
self.images.add(image_obj)
|
||||
|
||||
def save_prices(self):
|
||||
# Temporarily remove snapshot from object
|
||||
self.price_snapshot = None
|
||||
|
||||
snapshot, _ = PriceSnapshot.objects.get_or_create(
|
||||
checklist__id=self.price_snapshot_id,
|
||||
defaults={
|
||||
'yuan_rate': self.yuan_rate,
|
||||
'delivery_price_CN': self.delivery_price_CN,
|
||||
'delivery_price_CN_RU': self.delivery_price_CN_RU,
|
||||
'commission_rub': self.commission_rub,
|
||||
}
|
||||
)
|
||||
|
||||
# Restore snapshot
|
||||
self.price_snapshot = snapshot
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.id:
|
||||
old_obj = Checklist.objects.filter(id=self.id).first()
|
||||
|
||||
# If status was updated, update status_updated_at field
|
||||
if old_obj and self.status != old_obj.status:
|
||||
self.status_updated_at = timezone.now()
|
||||
|
|
@ -485,5 +553,15 @@ class Checklist(models.Model):
|
|||
if not self.preview_image:
|
||||
self.generate_preview()
|
||||
|
||||
# Save price details to snapshot
|
||||
if self.price_snapshot_id:
|
||||
# Status updated from other statuses back to DRAFT
|
||||
if self.status == Checklist.Status.DRAFT:
|
||||
self.price_snapshot.delete()
|
||||
self.price_snapshot = None
|
||||
|
||||
elif self.status != Checklist.Status.DRAFT:
|
||||
self.save_prices()
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
|
|
|||
|
|
@ -75,16 +75,16 @@ class ChecklistSerializer(serializers.ModelSerializer):
|
|||
promo = serializers.SlugRelatedField(source='promocode', slug_field='name',
|
||||
queryset=Promocode.objects.active(), required=False, allow_null=True)
|
||||
|
||||
currency = serializers.SerializerMethodField('get_yuan_rate')
|
||||
currency = serializers.DecimalField(source='yuan_rate', read_only=True, max_digits=10, decimal_places=2)
|
||||
curencycurency2 = serializers.DecimalField(source='price_yuan', required=False, max_digits=10, decimal_places=2)
|
||||
currency3 = serializers.IntegerField(source='price_rub', read_only=True)
|
||||
chinadelivery = serializers.SerializerMethodField('get_delivery_price_CN', read_only=True)
|
||||
chinadelivery2 = serializers.DecimalField(source='delivery_price_CN_RU', read_only=True, max_digits=10,
|
||||
decimal_places=2)
|
||||
chinadelivery = serializers.DecimalField(source='delivery_price_CN', read_only=True, max_digits=10, decimal_places=2)
|
||||
chinadelivery2 = serializers.DecimalField(source='delivery_price_CN_RU', read_only=True,
|
||||
max_digits=10, decimal_places=2)
|
||||
fullprice = serializers.IntegerField(source='full_price', read_only=True)
|
||||
realprice = serializers.DecimalField(source='real_price', required=False, allow_null=True, max_digits=10,
|
||||
decimal_places=2)
|
||||
commission = serializers.SerializerMethodField('get_commission', read_only=True)
|
||||
commission = serializers.DecimalField(source='commission_rub', read_only=True, max_digits=10, decimal_places=2)
|
||||
|
||||
buyername = serializers.CharField(source='buyer_name', required=False, allow_null=True)
|
||||
buyerphone = serializers.CharField(source='buyer_phone', required=False, allow_null=True)
|
||||
|
|
@ -151,22 +151,10 @@ class ChecklistSerializer(serializers.ModelSerializer):
|
|||
|
||||
return instance
|
||||
|
||||
@staticmethod
|
||||
def get_yuan_rate(obj: Checklist):
|
||||
return GlobalSettings.load().yuan_rate
|
||||
|
||||
@staticmethod
|
||||
def get_image(obj: Checklist):
|
||||
return obj.images.all()
|
||||
|
||||
@staticmethod
|
||||
def get_delivery_price_CN(obj: Checklist):
|
||||
return GlobalSettings.load().delivery_price_CN
|
||||
|
||||
@staticmethod
|
||||
def get_commission(obj: Checklist):
|
||||
return GlobalSettings.load().commission_rub
|
||||
|
||||
class Meta:
|
||||
model = Checklist
|
||||
fields = ('id', 'status', 'managerid', 'link',
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user