from django.utils import timezone # Potrebno za kreiranje vremena polaska from django.db import transaction # Potrebno za zaključavanje baze i sprječavanje dupliranja brojeva from rest_framework import serializers from .models import RadniNalog, RadniNalogSlika, PutniNalog from kupci.serializers import KupacListaSerializer from fleet.serializers import VoziloListaSerializer, StrojSerializer # --- POMOĆNI SERIALIZER ZA SLIKE --- class RadniNalogSlikaSerializer(serializers.ModelSerializer): class Meta: model = RadniNalogSlika fields = ['id', 'slika', 'opis'] # --- POMOĆNI SERIALIZER ZA PRIKAZ VEZANOG PUTNOG NALOGA --- class PutniNalogMinimalSerializer(serializers.ModelSerializer): class Meta: model = PutniNalog fields = ['id', 'broj_naloga', 'status', 'pocetna_km'] # --- NOVI STANDARDNI PUTNI NALOG SERIALIZER (Za rješavanje ImportError-a) --- class PutniNalogSerializer(serializers.ModelSerializer): vozilo_detalji = VoziloListaSerializer(source='vozilo', read_only=True) korisnik_ime = serializers.CharField(source='korisnik.get_full_name', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) class Meta: model = PutniNalog fields = [ 'id', 'broj_naloga', 'vozilo', 'vozilo_detalji', 'korisnik', 'korisnik_ime', 'relacija', 'mjesto_odredista', 'pocetna_km', 'zavrsna_km', 'status', 'status_display', 'vrijeme_polaska', 'vrijeme_povratka' ] read_only_fields = ['id', 'broj_naloga', 'vrijeme_polaska'] # --- 1. LISTA SERIALIZER --- class RadniNalogListaSerializer(serializers.ModelSerializer): klijent_naziv = serializers.CharField(source='klijent.naziv', read_only=True) stroj_naziv = serializers.CharField(source='stroj.naziv', read_only=True) izvrsitelj_ime = serializers.CharField(source='izvrsitelj.get_full_name', read_only=True) class Meta: model = RadniNalog fields = [ 'id', 'broj_naloga', 'klijent_naziv', 'stroj_naziv', 'status', 'izvrsitelj_ime', 'datum_kreiranja' ] # --- 2. DETALJI SERIALIZER --- class RadniNalogDetaljiSerializer(serializers.ModelSerializer): klijent = KupacListaSerializer(read_only=True) stroj = StrojSerializer(read_only=True) slike = RadniNalogSlikaSerializer(many=True, read_only=True) putni_nalog = PutniNalogMinimalSerializer(read_only=True) # VOZILO dohvaćamo preko putnog naloga vozilo = serializers.SerializerMethodField() status_display = serializers.CharField(source='get_status_display', read_only=True) izvrsitelj_ime = serializers.CharField(source='izvrsitelj.get_full_name', read_only=True) class Meta: model = RadniNalog fields = [ 'id', 'broj_naloga', 'klijent', 'stroj', 'putni_nalog', 'vozilo', 'opis_kvara', 'izvrsitelj', 'izvrsitelj_ime', 'status', 'status_display', 'datum_kreiranja', 'datum_azuriranja', 'slika_kvara', 'potpis_klijenta', 'slike' ] read_only_fields = ['datum_kreiranja', 'datum_azuriranja'] def get_vozilo(self, obj): if obj.putni_nalog and obj.putni_nalog.vozilo: return { "id": obj.putni_nalog.vozilo.id, "naziv": obj.putni_nalog.vozilo.naziv, "registracija": obj.putni_nalog.vozilo.registracija, "trenutni_kilometri": obj.putni_nalog.vozilo.trenutni_kilometri, "status_prikaz": obj.putni_nalog.vozilo.status } return None # --- 3. DEFAULT SERIALIZER --- class RadniNalogSerializer(serializers.ModelSerializer): broj_naloga = serializers.CharField(required=False, read_only=True) class Meta: model = RadniNalog exclude = [] def validate_broj_naloga(self, value): if RadniNalog.objects.filter(broj_naloga=value).exists(): raise serializers.ValidationError("Radni nalog s ovim brojem već postoji.") return value def validate(self, data): stroj = data.get('stroj') klijent = data.get('klijent') if stroj and klijent and stroj.vlasnik != klijent: raise serializers.ValidationError( {"stroj": "Odabrani stroj ne pripada odabranom klijentu."} ) return data # --- 4. KREIRANJE PUTNOG NALOGA SERIALIZER (AUTOMATSKO PROŠIRENJE SEKVENCI) --- class KreirajPutniNalogSerializer(serializers.ModelSerializer): radni_nalog_id = serializers.IntegerField(write_only=True) class Meta: model = PutniNalog fields = ['id', 'radni_nalog_id', 'broj_naloga', 'vozilo', 'korisnik', 'relacija', 'mjesto_odredista', 'pocetna_km', 'status'] read_only_fields = ['id', 'broj_naloga', 'korisnik', 'relacija', 'mjesto_odredista', 'pocetna_km', 'status'] def validate_radni_nalog_id(self, value): try: nalog = RadniNalog.objects.get(id=value) except RadniNalog.DoesNotExist: raise serializers.ValidationError("Radni nalog s ovim ID-jem ne postoji.") if nalog.putni_nalog is not None: raise serializers.ValidationError("Za ovaj radni nalog već je izrađen putni nalog.") if not nalog.izvrsitelj: raise serializers.ValidationError("Radni nalog mora imati dodijeljenog izvršitelja da bi se kreirao putni nalog.") return value def create(self, validated_data): radni_nalog = RadniNalog.objects.get(id=validated_data['radni_nalog_id']) vozilo = validated_data.get('vozilo') godina = timezone.now().year prefix = f"PN-{godina}-" # Koristimo atomsku transakciju i select_for_update da spriječimo trke podataka with transaction.atomic(): # Pronalazimo zadnji kreirani putni nalog za tekuću godinu zadnji_pn = PutniNalog.objects.select_for_update().filter( broj_naloga__startswith=prefix ).order_by('-broj_naloga').first() if zadnji_pn: try: # PN-2026-0002 -> uzimamo zadnji segment "0002" i uvećavamo ga zadnji_broj_str = zadnji_pn.broj_naloga.split('-')[-1] novi_broj = int(zadnji_broj_str) + 1 except (ValueError, IndexError): novi_broj = 1 else: novi_broj = 1 # Sklapanje jedinstvenog broja putnog naloga u formatu PN-2026-XXXX broj_pn = f"{prefix}{novi_broj:04d}" # Siguran upis u bazu podataka putni_nalog = PutniNalog.objects.create( broj_naloga=broj_pn, vozilo=vozilo, korisnik=radni_nalog.izvrsitelj, relacija=f"Zagreb - {radni_nalog.klijent.grad} - Zagreb", mjesto_odredista=radni_nalog.klijent.grad, vrijeme_polaska=timezone.now() ) # Povezujemo radni nalog na novokreirani putni nalog radni_nalog.putni_nalog = putni_nalog radni_nalog.save() return putni_nalog