Timeline — ER dijagram

Ponuda ima više grupa, grupa ima jedan timeline, timeline ima više stavki. Postojeće tablice prikazane su sa stvarnim stupcima iz baze.

točno jedan nula ili jedan nula ili više nullable FK (labava veza) nova tablica nova kolona u postojećoj tablici

Napomene

Zašto offer_groups, a ne groups

GROUPS je rezervirana riječ u MySQL-u 8, a ime prati postojeće offer_days / offer_day_items.

"Sve grupe" i shared_key

Svaka grupa ima svoje fizičke retke. Kopije iste stavke u različitim grupama dijele shared_key; izmjena u "Sve grupe" ažurira sve retke s tim ključem u grupama čiji timeline ima is_edited_separately = 0.

Aktivnosti: activities

Aktivnosti (doručak, ukrcaj u bus, prijava u hotel…) su nova tablica koja se uređuje u CMS-u (vlastiti CRUD), a timeline ih nudi za povlačenje. name je translatable (json, kao ostala prevodiva polja), pa stavka timelinea s type = activity pamti samo activity_id, a naziv na PDF-u ide na jeziku klijenta. Dodavanje s timelinea ("+ Aktivnost") sprema novi zapis u tu tablicu (samo hrvatski naziv, ostali jezici u CMS-u). Brisanje je soft delete, pa stavke koje već koriste aktivnost ostaju.

Labava veza na itinerar

offer_day_item_id je nullable s ON DELETE SET NULL. Brisanje usluge iz itinerara ostavlja stavku timelinea; type = service bez offer_day_item_id znači "obrisana usluga".

Po grupi: pax, vodiči, vozač, status

Vozači postoje samo na grupi (offer_group_drivers, jedan bus može imati više vozača), ne na stavkama timelinea. Ime i telefon nisu obavezni i nisu preduvjet za najavu ni voucher. pax, status i vodiči (pivot timeline_item_tour_guide) ne sinkroniziraju se kroz "Sve grupe". Raster uz ponudu prikazuje sve jedinstvene vodiče svih stavki (usluge i aktivnosti), a uz svaku uslugu jedinstvene vodiče stavki vezanih uz tu uslugu; ako nijedan nije dodijeljen, prikazuje "Potreban vodič" — to je zadano stanje usluge bez vodiča, ne posebno polje.

Status po grupi

status = null znači da stavka prati status usluge iz Rastera usluga (raster_services.status). Kad grupa postavi drugačiji status, Raster uz uslugu ispisuje "Grupa X – drugačiji status". Odabir istog statusa kao u Rasteru vraća null.

IN / OUT cijene

IN / OUT cijene nisu na stavkama timelinea nego u raster_services: jedna cijena po usluzi za cijelu ponudu (ne po grupi). To nisu cijene stavke ponude nego analitičke cijene: unose se ručno (prazne dok se ne unesu) i uspoređuju s nabavnom / prodajnom cijenom iz ponude (offer_day_items) radi ispravka kalkulacije. Ne mijenjaju ponudu.

Raster usluga: raster_services

Jedan red po usluzi ponude, zajednički za sve grupe: status, IN / OUT i najava partneru. Ne kopira se itinerar: red nastaje tek kad se na rasteru nešto postavi (status, cijena, najava, račun), a naziv, datum i cijene ponude čitaju se iz offer_day_items. Bez reda raster prikazuje zadano (Neobrađeno, prazno). Brisanje usluge: deleting hook na OfferDayItem — ako ponuda ima timeline, red se kreira ako ne postoji, u item_snapshot se kopira stavka, a offer_day_item_id postaje null; raster je i dalje prikazuje kao "Obrisana usluga" radi poziva i storna. Ako ponuda nema timeline, red se briše zajedno sa stavkom. offer_id zato stoji na tablici. Računi usluge su datoteke preko MediaStorage (media kolekcija na ovom modelu), ne stupci; ostali računi su po ponudi, na Offer.

Financije: PDF-ovi ponude

Tab "Financije" je popis PDF-ova po ponudi (jedan PDF = jedan red). Nema nove tablice: datoteke idu preko MediaStorage (Spatie tablica media), a naziv i vrijeme učitavanja dolaze iz nje. PDF-ovi se učitavaju samo s Rastera: "Račun usluga" (po usluzi) ide u kolekciju service_invoices na RasterService (red se kreira ako ne postoji), a "Ostali računi" (jedan gumb po ponudi, uz Vodiče) u kolekciju other_invoices na Offer. Financije prikazuju oboje po ponudi, s vrstom računa i nazivom usluge. Svaki PDF ima status Novo → Završeno (gumb), spremljen u custom_properties media zapisa (completed_at, null = Novo). Učitava se kroz modal (više PDF-ova odjednom), a svaki PDF dobiva svoju napomenu, također u custom_properties (note), koja se prikazuje u Financijama.

Napomene za najavu

timelines.notes je rich text po grupi (rooming lista, prehrana, smještaj vodiča, ostali izleti…). Ne sinkronizira se kroz "Sve grupe" i ide u najavu vodiču, ne na timeline PDF.

Najave

Najava vodiču (po grupi, timelines.announced_at): timeline PDF + timelines.notes + vaučeri svih usluga grupe u privitku. Najava partneru (raster_services.partner_announced_at): tekstualni sažetak usluge iz timelinea uz molbu za pisanu potvrdu, bez vaučera. Šalje se s Rastera usluga, jednom po usluzi za sve grupe. Slanjem se status usluge automatski postavlja na "Najavljeno"; inače se status mijenja ručno. Sadržaj po grupi: dan i vrijeme, broj gostiju (+ vodič + vozač), vodič, vozač; uz to slobodni tekst. Slobodni tekst se sprema u raster_services.partner_announcement_text.