178 lines
7.3 KiB
Python
178 lines
7.3 KiB
Python
from rest_framework import serializers
|
|
from django.utils import timezone
|
|
|
|
from trznice.utils import RoundedDateTimeField
|
|
from account.serializers import CustomUserSerializer
|
|
from booking.serializers import ReservationSerializer
|
|
from account.models import CustomUser
|
|
from booking.models import Event, MarketSlot, Reservation
|
|
from .models import Order
|
|
|
|
from decimal import Decimal
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
#počítaní ceny!!! (taky validní)
|
|
class SlotPriceInputSerializer(serializers.Serializer):
|
|
slot_id = serializers.PrimaryKeyRelatedField(queryset=MarketSlot.objects.all())
|
|
used_extension = serializers.FloatField(min_value=0)
|
|
|
|
#počítaní ceny!!! (počítá správně!!)
|
|
class PriceCalculationSerializer(serializers.Serializer):
|
|
slot = serializers.PrimaryKeyRelatedField(queryset=MarketSlot.objects.all())
|
|
reserved_from = RoundedDateTimeField()
|
|
reserved_to = RoundedDateTimeField()
|
|
used_extension = serializers.FloatField(min_value=0, required=False)
|
|
|
|
final_price = serializers.DecimalField(max_digits=8, decimal_places=2, read_only=True)
|
|
|
|
def validate(self, data):
|
|
from django.utils.timezone import make_aware, is_naive
|
|
|
|
reserved_from = data["reserved_from"]
|
|
reserved_to = data["reserved_to"]
|
|
|
|
if is_naive(reserved_from):
|
|
reserved_from = make_aware(reserved_from)
|
|
if is_naive(reserved_to):
|
|
reserved_to = make_aware(reserved_to)
|
|
|
|
duration = reserved_to - reserved_from
|
|
days = duration.days + 1 # zahrnujeme první den
|
|
|
|
data["reserved_from"] = reserved_from
|
|
data["reserved_to"] = reserved_to
|
|
data["duration"] = days
|
|
|
|
market_slot = data["slot"]
|
|
event = market_slot.event if hasattr(market_slot, "event") else None
|
|
|
|
if not event or not event.square:
|
|
raise serializers.ValidationError("Slot musí být přiřazen k akci, která má náměstí.")
|
|
|
|
# Get width and height from market_slot
|
|
area = market_slot.width * market_slot.height
|
|
|
|
price_per_m2 = market_slot.price_per_m2 if market_slot.price_per_m2 and market_slot.price_per_m2 > 0 else event.price_per_m2
|
|
|
|
if not price_per_m2 or price_per_m2 < 0:
|
|
raise serializers.ValidationError("Cena za m² není dostupná nebo je záporná.")
|
|
|
|
# Calculate final price using slot area and reserved days
|
|
final_price = Decimal(area) * Decimal(price_per_m2) * Decimal(days)
|
|
final_price = final_price.quantize(Decimal("0.01"))
|
|
|
|
data["final_price"] = final_price
|
|
return data
|
|
|
|
|
|
|
|
class OrderSerializer(serializers.ModelSerializer):
|
|
created_at = RoundedDateTimeField(read_only=True, required=False)
|
|
payed_at = RoundedDateTimeField(read_only=True, required=False)
|
|
|
|
user = CustomUserSerializer(read_only=True)
|
|
reservation = ReservationSerializer(read_only=True)
|
|
|
|
user_id = serializers.PrimaryKeyRelatedField(
|
|
queryset=CustomUser.objects.all(), source="user", write_only=True, required=False, allow_null=True
|
|
)
|
|
reservation_id = serializers.PrimaryKeyRelatedField(
|
|
queryset=Reservation.objects.all(), source="reservation", write_only=True
|
|
)
|
|
|
|
price_to_pay = serializers.DecimalField(
|
|
max_digits=10, decimal_places=2, required=False, allow_null=True
|
|
)
|
|
|
|
class Meta:
|
|
model = Order
|
|
fields = [
|
|
"id",
|
|
"user", # nested read-only
|
|
"user_id", # required in POST/PUT
|
|
"reservation", # nested read-only
|
|
"reservation_id", # required in POST/PUT
|
|
"created_at",
|
|
"status",
|
|
"note",
|
|
"price_to_pay",
|
|
"payed_at",
|
|
]
|
|
read_only_fields = ["id", "created_at", "price_to_pay", "payed_at"]
|
|
|
|
extra_kwargs = {
|
|
"user_id": {"help_text": "ID uživatele, který objednávku vytvořil", "required": False},
|
|
"reservation_id": {"help_text": "ID rezervace, ke které se objednávka vztahuje", "required": True},
|
|
"status": {"help_text": "Stav objednávky (např. new / paid / cancelled)", "required": False},
|
|
"note": {"help_text": "Poznámka k objednávce (volitelné)", "required": False},
|
|
"price_to_pay": {
|
|
"help_text": "Celková cena, kterou má uživatel zaplatit. Pokud není zadána, převezme se z rezervace.",
|
|
"required": False,
|
|
"allow_null": True,
|
|
},
|
|
"payed_at": {"help_text": "Datum a čas, kdy byla objednávka zaplacena", "required": False},
|
|
}
|
|
|
|
def validate(self, data):
|
|
if "status" in data and data["status"] not in dict(Order.STATUS_CHOICES):
|
|
raise serializers.ValidationError({"status": "Neplatný stav objednávky."})
|
|
|
|
# status = data.get("status", getattr(self.instance, "status", "pending"))
|
|
# payed_at = data.get("payed_at", getattr(self.instance, "payed_at", None))
|
|
reservation = data.get("reservation", getattr(self.instance, "reservation", None))
|
|
price = data.get("price_to_pay", getattr(self.instance, "price_to_pay", 0))
|
|
|
|
errors = {}
|
|
|
|
# if status == "payed" and not payed_at:
|
|
# errors["payed_at"] = "Musíte zadat datum a čas zaplacení, pokud je objednávka zaplacena."
|
|
|
|
# if status != "payed" and payed_at:
|
|
# errors["payed_at"] = "Datum zaplacení může být uvedeno pouze u zaplacených objednávek."
|
|
|
|
if price is not None and price < 0:
|
|
errors["price_to_pay"] = "Cena musí být větší nebo rovna 0."
|
|
|
|
if reservation:
|
|
if self.instance is None and hasattr(reservation, "order"):
|
|
errors["reservation"] = "Tato rezervace již má přiřazenou objednávku."
|
|
|
|
|
|
user = data.get("user")
|
|
request_user = self.context["request"].user if "request" in self.context else None
|
|
|
|
# If user is not specified, use the logged-in user
|
|
if user is None and request_user is not None:
|
|
user = request_user
|
|
data["user"] = user
|
|
|
|
# If user is specified and differs from logged-in user, check permissions
|
|
if user is not None and request_user is not None and user != request_user:
|
|
if request_user.role not in ["admin", "cityClerk", "squareManager"]:
|
|
errors["user"] = "Pouze administrátor, úředník nebo správce tržiště může vytvářet rezervace pro jiné uživatele."
|
|
|
|
if errors:
|
|
raise serializers.ValidationError(errors)
|
|
|
|
return data
|
|
|
|
def create(self, validated_data):
|
|
if validated_data.get("reservation"):
|
|
validated_data["price_to_pay"] = validated_data["reservation"].final_price
|
|
|
|
validated_data["user"] = validated_data.pop("user_id", validated_data.get("user"))
|
|
validated_data["reservation"] = validated_data.pop("reservation_id", validated_data.get("reservation"))
|
|
|
|
return super().create(validated_data)
|
|
|
|
def update(self, instance, validated_data):
|
|
old_status = instance.status
|
|
new_status = validated_data.get("status", old_status)
|
|
|
|
logger.debug(f"\n\nUpdating order {instance.id} from status {old_status} to {new_status}\n\n")
|
|
|
|
if old_status != "payed" and new_status == "payed":
|
|
validated_data["payed_at"] = timezone.now()
|
|
return super().update(instance, validated_data) |