Dodawanie i edycja (Cenniki)
Przewodnik po dodawaniu i wycenianiu nowych rodzajów zajęć.
👤 Instrukcja dla pracownika (Administracja)
Aby utworzyć nowy rodzaj zajęć w systemie (np. "Tenis Dzieci VIP"):
Ścieżka dla pracownika: Dashboard ➔ Rodzaje zajęć ➔ "+ Dodaj nowy rodzaj zajęć" ➔ Sekcja Konfiguracja Cennika (na samym dole)
Poniżej przedstawiono procedurę konfiguracji wariantów cenowych.
:::tip Miasto W formularzu (dodawania i edycji) pole Miasto decyduje, w której lokalizacji zajęcia będą oferowane. Wartość "Wszystkie miasta" udostępnia je w każdej lokalizacji. Szczegóły: Rodzaje zajęć → Miasto. :::
Modele konfiguracji cennika
W sekcji Konfiguracja Cennika formularza kreacji dostępne są dwa modele rozliczeniowe:
Opcja A: Cennik Podstawowy (Zalecany dla regularnych zajęć grupowych)
Należy zastosować ten model w przypadku, gdy obowiązuje jedna stawka godzinowa, niezależnie od dnia tygodnia czy pory odbywania się zajęć. Kwota podana w polu Cena jest stawką za godzinę i jest mnożona przez czas trwania zajęć (np. stawka 50 zł przy zajęciach 90-minutowych daje 75 zł).
Opcja B: Cennik Zaawansowany (Zalecany przy wynajmie infrastruktury)
Model zaawansowany umożliwia różnicowanie opłat za usługę w oparciu o kryteria czasowe (np. stawki szczytowe i pozaszczytowe). Konfiguracja wymaga określenia następujących parametrów:
- Cena bazowa: Kwota domyślna, aplikowana w sytuacjach, gdy żadna z dodatkowych reguł (wyjątków) nie ma zastosowania do terminu rezerwacji.
- Reguły cenowe (Wyjątki): Mechanizm pozwalający na definiowanie przedziałów czasowych (po kliknięciu "Dodaj Regułę"). Przykłady zastosowania:
- "Stawka wakacyjna - poranna": Ustalenie ceny 40 zł w okresie od 1 lipca do 31 sierpnia, w przedziale godzinowym 08:00 - 12:00.
- "Stawka szczytowa": Ustalenie ceny 80 zł (obowiązującej całorocznie) w godzinach 16:00 - 22:00.
Reguły obowiązujące do północy
Jeżeli kort jest czynny do północy, w polu Godzina do należy wpisać 00:00 — reguła obejmie wtedy czas aż do końca doby (np. 07:00 - 00:00 to cały dzień pracy kortu od 7 rano do północy). W ten sam sposób zapisuje się reguły nocne przechodzące przez północ, np. 22:00 - 02:00. Jedyny niedozwolony przypadek to identyczna godzina początkowa i końcowa (np. 10:00 - 10:00), bo taki przedział nie wyznacza żadnego czasu.
Ceny z groszami
Każde pole ceny (Cena, Cena bazowa, reguła cenowa, cena niestandardowa w rezerwacji) przyjmuje kwoty z dokładnością do dwóch miejsc po przecinku, np. 75,21. Separatorem może być przecinek lub kropka — obie formy są równoważne. Próba wpisania trzeciego miejsca po przecinku nie zostanie przyjęta (znak nie pojawi się w polu). Puste pole oznacza brak ceny (0 zł dla cenników, brak nadpisania dla ceny niestandardowej).
Ważne! Hierarchia reguł cenowych Algorytm analizuje listę reguł sekwencyjnie (od góry do dołu). Weryfikowana jest zbieżność terminu zajęć z warunkami pierwszej reguły na liście. W przypadku spełnienia warunków, system aplikuje przypisaną cenę i kończy proces iteracji. Jeżeli warunki nie są spełnione, następuje weryfikacja kolejnej reguły. W przypadku braku dopasowania w pełnym cyklu, system aplikuje ustaloną "Cenę bazową".
Modyfikacja modelu cenowego w istniejących zajęciach
Administrator posiada możliwość modyfikacji "Rodzaju zajęć" po jego zapisaniu. Należy jednak mieć na uwadze następujące zasady:
- Przekształcenie modelu z "Podstawowego" na "Zaawansowany" jest w pełni bezinwazyjne.
- Odwrócenie tego procesu (powrót do "Podstawowego") skutkuje bezpowrotnym usunięciem skonfigurowanej tabeli reguł wyjątków. System każdorazowo wymaga potwierdzenia tej akcji w oknie dialogowym.
- Zmiany w konfiguracji cennika (włączając w to usunięcie reguł) mają wpływ wyłącznie na nowo generowane pozycje w harmonogramie. Istniejące rezerwacje, na podstawie których system wygenerował już pozycje płatności u klientów, zachowują swoje pierwotne kwoty, zapewniając pełną spójność danych finansowych.
🛠️ Dokumentacja techniczna
Szczegóły dla deweloperów o formatach i regułach.
Model dla zaawansowanego cennika korzysta z obiektów JSON serializowanych do pola w bazie (pricing_rules).
Kluczowe założenia silnika pricing_rules (calculatePrice)
- System bierze datę startu i końca konkretnej instancji gry (
game). - Sprawdza przedziały
overlappod kątem timezone (przelicza je naEurope/Warsaw). - Reguły aplikowane są sekwencyjnie. Funkcja Array.find() szuka pierwszego warunku
trueiterując od indexu 0. - Walidacja frontowa (
isValidPricingRuleRangezlib/utils/pricing.ts) liczona jest z zapisanych póldateFrom/dateToprzeliczonych naEurope/Warsaw, a nie z pomocniczych póltimeFrom/timeToformularza. Odrzuca wyłącznie dwa przypadki: datę końcową wcześniejszą niż początkowa (porównanie po samych dniach) oraz identyczną godzinę początkową i końcową. KomunikatformValidation.invalidDateTimeRangepokazywany jest na czerwono pod listą reguł. - Przedział z godziną końcową mniejszą lub równą początkowej (
07:00 - 00:00,22:00 - 02:00) traktowany jest jako przechodzący przez północ i przedłużany o dobę — zarówno wcalculateActivityPrice, jak i wisTimeInRange(używanym przezgetApplicablePricingRuleigetPricingRuleIddo zapisaniaapplied_pricing_rule_id). Godzina00:00jako koniec oznacza więc koniec doby, a nie jej początek.
Pola cenowe (PriceInput)
Wszystkie pola kwotowe korzystają ze wspólnego komponentu components/price-input.tsx.
- Komponent trzyma wpisywany tekst w lokalnym stanie i przekazuje w górę wartość liczbową (
onValueChange). Dzięki temu stany pośrednie (75,) nie są kasowane przez ponowne formatowanie wartości liczbowej — wcześniej pola były kontrolowane bezpośrednio przezparseFloat, co uniemożliwiało wpisanie groszy. - Wpisany tekst jest synchronizowany z wartością z formularza wyłącznie wtedy, gdy pole nie jest aktywne (
focus), więcform.reset()działa, ale nie przerywa pisania. Po opuszczeniu pola tekst jest normalizowany do postaci wynikającej z wartości liczbowej. emptyValueokreśla wartość zgłaszaną przy pustym polu i wartość renderowaną jako puste pole:0dla cenników,nulldla ceny niestandardowej rezerwacji.- Dozwolony format wejścia:
/^\d*[,.]?\d{0,2}$/. Znaki niepasujące do wzorca są odrzucane bez zmiany stanu.