161 lines
7.3 KiB
Python
161 lines
7.3 KiB
Python
import random
|
|
import os
|
|
from django.core.management.base import BaseCommand
|
|
from django.contrib.auth import get_user_model
|
|
from django.utils import timezone
|
|
from django.core.files import File
|
|
from django.db import transaction
|
|
from operations.models import RadniNalog, RadniNalogSlika, PutniNalog, BrojacSekvence
|
|
from fleet.models import Vozilo, Stroj
|
|
from kupci.models import Kupac
|
|
from kalendar.services import kreiraj_kalendarski_unos
|
|
|
|
User = get_user_model()
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Popunjava bazu s Putnim nalozima, Radnim nalozima i slikama sinkronizirano sa sekvencama'
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument('total_putovanja', type=int, nargs='?', default=3, help='Broj putnih naloga')
|
|
parser.add_argument('--img', type=str, default='test_assets/kvar.jpg')
|
|
|
|
def handle(self, *args, **kwargs):
|
|
total_putovanja = kwargs['total_putovanja']
|
|
test_img_path = kwargs['img']
|
|
|
|
kupci = Kupac.objects.prefetch_related('strojevi').all()
|
|
vozila = list(Vozilo.objects.all())
|
|
serviseri = list(User.objects.filter(is_staff=True))
|
|
|
|
if not kupci.exists() or not vozila or not serviseri:
|
|
self.stdout.write(self.style.ERROR("Baza mora imati kupce, vozila i servisere (is_staff=True)."))
|
|
return
|
|
|
|
# Provjera slike
|
|
if not os.path.exists(test_img_path):
|
|
self.stdout.write(self.style.WARNING(f"Testna slika {test_img_path} nije pronađena. Generiram bez slika."))
|
|
test_img_path = None
|
|
|
|
opisi_kvarova = [
|
|
"Godišnji periodični servis dizalice.",
|
|
"Zamjena hidrauličnog crijeva i dopuna ulja.",
|
|
"Kalibracija senzora opterećenja.",
|
|
"Popravak daljinskog upravljača.",
|
|
"Hitna intervencija: Stroj u kvaru."
|
|
]
|
|
|
|
self.stdout.write(f'🚀 Generiranje {total_putovanja} putovanja sinkronizirano sa sekvencama...')
|
|
success_count_rn = 0
|
|
trenutna_godina = timezone.now().year
|
|
|
|
# Definiramo ključ i prefikse za putne naloge
|
|
prefix_pn = f"PN-{trenutna_godina}-"
|
|
kljuc_sekvence_rn = f"radni_nalog_{trenutna_godina}"
|
|
|
|
for i in range(total_putovanja):
|
|
serviser = random.choice(serviseri)
|
|
vozilo = random.choice(vozila)
|
|
|
|
# 1. GENERIRANJE NEUNIŠTIVOG BROJA PUTNOG NALOGA
|
|
# Da skripta ne bi udarila u unique=True, tražimo stvarni zadnji PN u bazi
|
|
with transaction.atomic():
|
|
zadnji_pn = PutniNalog.objects.select_for_update().filter(
|
|
broj_naloga__startswith=prefix_pn
|
|
).order_by('-broj_naloga').first()
|
|
|
|
if zadnji_pn:
|
|
try:
|
|
zadnji_broj_pn = int(zadnji_pn.broj_naloga.split('-')[-1])
|
|
novi_broj_pn = zadnji_broj_pn + 1
|
|
except (ValueError, IndexError):
|
|
novi_broj_pn = PutniNalog.objects.count() + 1
|
|
else:
|
|
novi_broj_pn = 1
|
|
|
|
broj_pn = f"{prefix_pn}{novi_broj_pn:04d}"
|
|
|
|
# Kreiraj PUTNI NALOG
|
|
putni_nalog = PutniNalog.objects.create(
|
|
broj_naloga=broj_pn,
|
|
vozilo=vozilo,
|
|
korisnik=serviser,
|
|
relacija="Zagreb - Teren - Zagreb",
|
|
mjesto_odredista="Teren",
|
|
vrijeme_polaska=timezone.now()
|
|
)
|
|
|
|
self.stdout.write(self.style.MIGRATE_LABEL(f"Otvoren {broj_pn} (Vozilo: {vozilo.registracija})"))
|
|
|
|
# 2. Kreiraj 1 do 3 RADNA NALOGA za ovaj putni nalog
|
|
za_odraditi = random.randint(1, 3)
|
|
kreirani_radni_nalozi = []
|
|
|
|
for j in range(za_odraditi):
|
|
klijenti_sa_strojima = [k for k in kupci if k.strojevi.exists()]
|
|
if not klijenti_sa_strojima:
|
|
continue
|
|
klijent = random.choice(klijenti_sa_strojima)
|
|
stroj = random.choice(list(klijent.strojevi.all()))
|
|
|
|
try:
|
|
# Inicijaliziramo objekt bez broja_naloga kako bi se aktivirala
|
|
# naša neuništiva sekvencijska logika unutar save() metode modela!
|
|
nalog = RadniNalog(
|
|
klijent=klijent,
|
|
stroj=stroj,
|
|
putni_nalog=putni_nalog,
|
|
opis_kvara=random.choice(opisi_kvarova),
|
|
izvrsitelj=serviser,
|
|
status=RadniNalog.StatusRadaChoices.PLANIRANO
|
|
)
|
|
|
|
# Prvo moramo izvršiti osnovni save da model kroz BrojacSekvence dodijeli čisti broj
|
|
nalog.save()
|
|
|
|
# Ako slika postoji, dodajemo je NAKON što je broj kreiran (da putanja_slike_naloga ima ispravan folder)
|
|
if test_img_path:
|
|
with open(test_img_path, 'rb') as f:
|
|
nalog.slika_kvara.save(f'rn_{nalog.broj_naloga}.jpg', File(f), save=True)
|
|
|
|
kreirani_radni_nalozi.append(nalog)
|
|
|
|
# Dodatne slike u galeriju
|
|
if test_img_path:
|
|
for k in range(random.randint(1, 2)):
|
|
with open(test_img_path, 'rb') as f:
|
|
RadniNalogSlika.objects.create(
|
|
radni_nalog=nalog,
|
|
slika=File(f, name=f'gal_{nalog.broj_naloga}_{k}.jpg'),
|
|
opis=f"Detalj kvara {k+1}"
|
|
)
|
|
|
|
# 5. Upis u kalendar
|
|
try:
|
|
kreiraj_kalendarski_unos(nalog)
|
|
except Exception as cal_err:
|
|
self.stdout.write(self.style.WARNING(f" ⚠️ Kalendar unos preskočen: {cal_err}"))
|
|
|
|
success_count_rn += 1
|
|
self.stdout.write(f" ✅ {nalog.broj_naloga} uspješno povezan u {broj_pn}")
|
|
|
|
except Exception as e:
|
|
self.stderr.write(f" ❌ Greška kod kreiranja RN: {e}")
|
|
|
|
# 3. NASUMIČNO ZATVARANJE (Simulacija završenog posla)
|
|
if random.random() > 0.5 and kreirani_radni_nalozi:
|
|
try:
|
|
# Prvo moramo zatvoriti sve radne naloge da bi PN prošao validaciju
|
|
for rn in kreirani_radni_nalozi:
|
|
rn.status = RadniNalog.StatusRadaChoices.ZAVRSENO
|
|
rn.save()
|
|
|
|
# Dodajemo završne kilometre (uvijek više od početnih)
|
|
putni_nalog.zavrsna_km = putni_nalog.pocetna_km + random.randint(50, 500)
|
|
putni_nalog.status = PutniNalog.StatusChoices.ZAVRSEN
|
|
putni_nalog.save()
|
|
|
|
self.stdout.write(self.style.SUCCESS(f" 🏁 {broj_pn} automatski ZATVOREN. Kilometri vozila ažurirani."))
|
|
except Exception as e:
|
|
self.stdout.write(self.style.WARNING(f" ⚠️ PN-{broj_pn} nije zatvoren: {e}"))
|
|
|
|
self.stdout.write(self.style.SUCCESS(f'\nGotovo! Generirano {total_putovanja} PN i {success_count_rn} RN.')) |