222 lines
6.2 KiB
Python
222 lines
6.2 KiB
Python
from rest_framework import serializers
|
||
|
||
from commerce.models import (
|
||
Cost,
|
||
Product,
|
||
ProductBinding,
|
||
Sale,
|
||
SaleLine,
|
||
SourceSystem,
|
||
StockSnapshot,
|
||
)
|
||
|
||
|
||
class SourceSystemSerializer(serializers.ModelSerializer):
|
||
class Meta:
|
||
model = SourceSystem
|
||
fields = [
|
||
"id",
|
||
"code",
|
||
"name",
|
||
"is_active",
|
||
"metadata",
|
||
"created_at",
|
||
"updated_at",
|
||
]
|
||
read_only_fields = ["id", "created_at", "updated_at"]
|
||
|
||
|
||
class ProductBindingSerializer(serializers.ModelSerializer):
|
||
source_code = serializers.CharField(source="source.code", read_only=True)
|
||
|
||
class Meta:
|
||
model = ProductBinding
|
||
fields = [
|
||
"id",
|
||
"product",
|
||
"source",
|
||
"source_code",
|
||
"external_id",
|
||
"external_sku",
|
||
"is_primary",
|
||
"created_at",
|
||
"updated_at",
|
||
]
|
||
read_only_fields = ["id", "created_at", "updated_at"]
|
||
|
||
|
||
class ProductSerializer(serializers.ModelSerializer):
|
||
bindings = ProductBindingSerializer(many=True, read_only=True)
|
||
variants_count = serializers.IntegerField(read_only=True)
|
||
|
||
class Meta:
|
||
model = Product
|
||
fields = [
|
||
"id",
|
||
"parent",
|
||
"kind",
|
||
"sku",
|
||
"name",
|
||
"barcode",
|
||
"description",
|
||
"is_active",
|
||
"variants_count",
|
||
"bindings",
|
||
"created_at",
|
||
"updated_at",
|
||
]
|
||
read_only_fields = ["id", "created_at", "updated_at"]
|
||
|
||
|
||
class SaleLineSerializer(serializers.ModelSerializer):
|
||
net_amount = serializers.DecimalField(
|
||
max_digits=18, decimal_places=2, read_only=True
|
||
)
|
||
|
||
class Meta:
|
||
model = SaleLine
|
||
fields = [
|
||
"id",
|
||
"sale",
|
||
"product",
|
||
"external_id",
|
||
"external_product_id",
|
||
"external_sku",
|
||
"name",
|
||
"quantity",
|
||
"gross_amount",
|
||
"discount_amount",
|
||
"net_amount",
|
||
"cost_amount",
|
||
"metadata",
|
||
]
|
||
|
||
def validate(self, attrs):
|
||
gross = attrs.get("gross_amount", getattr(self.instance, "gross_amount", 0))
|
||
discount = attrs.get(
|
||
"discount_amount", getattr(self.instance, "discount_amount", 0)
|
||
)
|
||
if discount > gross:
|
||
raise serializers.ValidationError(
|
||
{"discount_amount": "Скидка не может превышать сумму позиции."}
|
||
)
|
||
return attrs
|
||
|
||
|
||
class SaleSerializer(serializers.ModelSerializer):
|
||
source_code = serializers.CharField(source="source.code", read_only=True)
|
||
lines = SaleLineSerializer(many=True, read_only=True)
|
||
|
||
class Meta:
|
||
model = Sale
|
||
fields = [
|
||
"id",
|
||
"source",
|
||
"source_code",
|
||
"source_record",
|
||
"external_id",
|
||
"number",
|
||
"event_type",
|
||
"channel",
|
||
"status",
|
||
"counts_as_sale",
|
||
"currency",
|
||
"occurred_at",
|
||
"source_updated_at",
|
||
"lines",
|
||
"created_at",
|
||
"updated_at",
|
||
]
|
||
|
||
|
||
class CostSerializer(serializers.ModelSerializer):
|
||
source_code = serializers.CharField(source="source.code", read_only=True)
|
||
|
||
class Meta:
|
||
model = Cost
|
||
fields = [
|
||
"id",
|
||
"source",
|
||
"source_code",
|
||
"product",
|
||
"sale_line",
|
||
"external_id",
|
||
"channel",
|
||
"cost_type",
|
||
"amount",
|
||
"currency",
|
||
"occurred_at",
|
||
"metadata",
|
||
"created_at",
|
||
]
|
||
validators = []
|
||
|
||
def validate(self, attrs):
|
||
product = attrs.get("product", getattr(self.instance, "product", None))
|
||
sale_line = attrs.get("sale_line", getattr(self.instance, "sale_line", None))
|
||
if product is None and sale_line is None:
|
||
raise serializers.ValidationError(
|
||
"Нужно указать товар или позицию продажи."
|
||
)
|
||
external_id = attrs.get(
|
||
"external_id", getattr(self.instance, "external_id", "")
|
||
)
|
||
if external_id:
|
||
source = attrs.get("source", getattr(self.instance, "source", None))
|
||
cost_type = attrs.get(
|
||
"cost_type", getattr(self.instance, "cost_type", None)
|
||
)
|
||
duplicate = Cost.objects.filter(
|
||
source=source,
|
||
external_id=external_id,
|
||
cost_type=cost_type,
|
||
)
|
||
if self.instance:
|
||
duplicate = duplicate.exclude(pk=self.instance.pk)
|
||
if duplicate.exists():
|
||
raise serializers.ValidationError(
|
||
{"external_id": "Расход с таким внешним ID уже существует."}
|
||
)
|
||
return attrs
|
||
|
||
|
||
class StockSnapshotSerializer(serializers.ModelSerializer):
|
||
source_code = serializers.CharField(source="source.code", read_only=True)
|
||
available = serializers.DecimalField(
|
||
max_digits=18, decimal_places=4, read_only=True
|
||
)
|
||
|
||
class Meta:
|
||
model = StockSnapshot
|
||
fields = [
|
||
"id",
|
||
"product",
|
||
"source",
|
||
"source_code",
|
||
"warehouse_external_id",
|
||
"warehouse_name",
|
||
"quantity",
|
||
"reserved",
|
||
"available",
|
||
"in_transit",
|
||
"captured_at",
|
||
"metadata",
|
||
"created_at",
|
||
]
|
||
|
||
|
||
class ProductMetricsQuerySerializer(serializers.Serializer):
|
||
date_from = serializers.DateTimeField(required=False)
|
||
date_to = serializers.DateTimeField(required=False)
|
||
|
||
def validate(self, attrs):
|
||
if (
|
||
attrs.get("date_from")
|
||
and attrs.get("date_to")
|
||
and attrs["date_from"] > attrs["date_to"]
|
||
):
|
||
raise serializers.ValidationError(
|
||
{"date_to": "Дата окончания должна быть не раньше даты начала."}
|
||
)
|
||
return attrs
|