Rezerwacje (Reservation) Ostatnia aktualizacja dokumentacji: 2026-02-26 Stan synchronizacji z kodem: ✅ Zsynchronizowany
Serce systemu zajmij.to — pełny cykl życia rezerwacji od utworzenia, przez płatność, aż po zwrot i opinię.
1. Opis ogólny Domena Rezerwacji odpowiada za cały proces rezerwowania obiektów i zapisów na zajęcia. To jak elektroniczna recepcja , która pracuje 24 godziny na dobę, 7 dni w tygodniu — przyjmuje rezerwacje, pobiera płatności, wysyła potwierdzenia i obsługuje zwroty.
System obsługuje dwa typy rezerwacji:
Rezerwacje godzinowe — wynajem sal, boisk, sprzętu na określone godziny Zapisy na zajęcia — uczestnictwo w zajęciach grupowych (fitness, basen, warsztaty) 2. Architektura domeny 2.1 Modele danych Model Tabela Opis Reservation reservations Główny model rezerwacji — dane klienta, cena, statusy, polimorficzne powiązanie z obiektem (Item) lub zajęciami (ActivityItem) ReservationSlot reservation_slots Pojedynczy termin (slot) w ramach rezerwacji — data, godziny, cena, status płatności ReservationPayment reservation_payments Płatność za rezerwację — kwota, metoda, status transakcji, URL płatności P24 ReservationPaymentRefund reservation_payment_refunds Zwrot płatności — kwota, metoda zwrotu, status, potwierdzenie ReservationPaymentReceipt reservation_payment_receipts Paragon PDF — numer, data wystawienia, ścieżka PDF, data wysyłki ReservationPaymentLog reservation_payment_logs Log operacji płatniczych — kanał, poziom, typ zdarzenia, dane P24 ReservationPaidLog reservation_paid_logs Audyt zmian płatności — snapshot stanu before/after, akcja, kto zmienił ReservationPaymentReminderLog reservation_payment_reminder_logs Log wysłanych przypomnień o płatności — typ, data wysłania WaitingReservation waiting_reservations Tymczasowa rezerwacja oczekująca na potwierdzenie email (soft-lock) WaitingReservationSlot waiting_reservation_slots Slot tymczasowej rezerwacji — blokuje termin w harmonogramie
2.2 Diagram relacji erDiagram
Reservation ||--o{ ReservationSlot : "hasMany"
Reservation ||--o{ ReservationPayment : "hasMany"
Reservation ||--o{ ReservationPaidLog : "hasMany"
Reservation ||--o{ ReservationPaymentReminderLog : "hasMany"
Reservation }o--|| Organization : "belongsTo"
Reservation }o--o| Client : "belongsTo"
Reservation }o--o| Pricing : "belongsTo"
Reservation ||--o| Review : "hasOne"
Reservation ||--o{ Complaint : "hasMany"
Reservation ||--o{ Note : "morphMany"
Reservation ||--o{ Schedule : "morphMany"
Reservation ||--o{ StatusLog : "morphMany"
ReservationSlot }o--|| Reservation : "belongsTo"
ReservationSlot ||--o| Schedule : "morphOne"
ReservationSlot ||--o{ ReservationPaymentRefund : "hasMany"
ReservationSlot }o--o| User : "cancelledBy"
ReservationPayment }o--|| Reservation : "belongsTo"
ReservationPayment ||--o{ ReservationPaymentRefund : "hasMany"
ReservationPayment ||--o| ReservationPaymentReceipt : "hasOne"
ReservationPayment }o--o| User : "creator"
ReservationPaymentRefund }o--|| ReservationPayment : "belongsTo"
ReservationPaymentRefund }o--o| ReservationSlot : "belongsTo"
ReservationPaymentRefund }o--o| User : "processor"
ReservationPaymentRefund }o--o| User : "manualConfirmer"
ReservationPaymentReceipt }o--|| ReservationPayment : "belongsTo"
ReservationPaymentLog }o--o| Reservation : "belongsTo"
ReservationPaymentLog }o--o| ReservationPayment : "belongsTo"
ReservationPaymentLog }o--o| Organization : "belongsTo"
ReservationPaidLog }o--|| Reservation : "belongsTo"
ReservationPaidLog }o--o| ReservationPayment : "belongsTo"
ReservationPaidLog }o--o| ReservationPaymentRefund : "belongsTo"
ReservationPaidLog }o--o| User : "changer"
WaitingReservation }o--|| Organization : "belongsTo"
WaitingReservation ||--o{ WaitingReservationSlot : "hasMany"
WaitingReservationSlot }o--|| WaitingReservation : "belongsTo"
WaitingReservationSlot ||--o| Schedule : "morphOne" 2.3 Struktura tabel w bazie danych Tabela reservations Kolumna Typ Nullable Default Opis id uuid (PK) Nie — Unikalny identyfikator uuid uuid Nie — Publiczny identyfikator (do linków) reservationable_type string Nie — Typ obiektu: Item lub ActivityItem reservationable_id uuid Nie — ID obiektu/zajęć organization_id uuid (FK) Nie — Organizacja client_id uuid (FK) Tak null Powiązany klient access_code string Nie — Kod dostępu (ukryty w API) first_name string Nie — Imię rezerwującego last_name string Nie — Nazwisko rezerwującego email string Nie — Email rezerwującego mobile_phone string Nie — Telefon rezerwującego total_price float Nie — Cena łączna total_net decimal(12,2) Tak null Kwota netto total_vat decimal(12,2) Tak null Kwota VAT vat_rate string(10) Tak null Stawka VAT price_breakdown json Tak null Rozbicie cenowe per slot pricing_id uuid (FK) Tak null Użyty cennik status enum Nie — Status: pending, confirmed, canceled, rejected payment_status enum Nie not_required Status płatności is_company boolean Nie false Czy firma company_name text Tak null Nazwa firmy nip string Tak null NIP regon string Tak null REGON street, street_number, postal_code, city string Tak null Adres commune, district, voivodeship string Tak null Dane TERYT reservationable_snapshot json Nie — Snapshot obiektu/cennika w momencie rezerwacji ip_address string Tak null IP rezerwującego user_agent string Tak null User-Agent przeglądarki accepted_rodo boolean Nie false Zgoda RODO accepted_rodo_path string Tak null Ścieżka do treści RODO accepted_terms boolean Nie false Akceptacja regulaminu accepted_terms_path string Tak null Ścieżka do regulaminu accepted_reservationable_statute boolean Nie false Akceptacja regulaminu obiektu accepted_reservationable_statute_path string Tak null Ścieżka do regulaminu obiektu consents_accepted_at timestamp Tak null Data akceptacji zgód show_price boolean Nie true Czy pokazywać cenę price_confirmed boolean Nie false Potwierdzenie ceny przez admina price_confirmed_at timestamp Tak null Data potwierdzenia ceny price_confirmed_by uuid (FK) Tak null Kto potwierdził cenę send_notifications boolean Nie true Czy wysyłać powiadomienia review_reminder_sent_at timestamp Tak null Data wysłania przypomnienia o opinii created_at, updated_at timestamp Nie — Znaczniki czasu
Tabela reservation_slots Kolumna Typ Nullable Default Opis id uuid (PK) Nie — Identyfikator reservation_id uuid (FK) Nie — Rezerwacja nadrzędna date date Nie — Data rezerwacji time_from time Nie — Godzina rozpoczęcia time_to time Nie — Godzina zakończenia start_at datetime Nie — Pełna data+godzina start end_at datetime Nie — Pełna data+godzina koniec price float Tak null Cena slotu is_paid boolean Nie false Czy opłacony paid_at timestamp Tak null Data opłacenia paid_amount decimal(10,2) Nie 0 Opłacona kwota refunded_amount decimal(10,2) Nie 0 Zwrócona kwota status enum Nie active Status: active, cancelled cancelled_at timestamp Tak null Data anulowania cancelled_by uuid (FK) Tak null Kto anulował cancellation_reason string Tak null Powód anulowania
Tabela reservation_payments Kolumna Typ Nullable Default Opis id uuid (PK) Nie — Identyfikator reservation_id uuid (FK) Nie — Rezerwacja amount decimal(10,2) Nie — Kwota płatności currency string(3) Nie PLN Waluta status enum Nie pending Status transakcji payment_method enum Nie przelewy24 Metoda: przelewy24, manual, free external_transaction_id string Tak null ID transakcji P24 payment_url string Tak null URL do płatności P24 paid_at timestamp Tak null Data opłacenia expires_at timestamp Tak null Data wygaśnięcia created_by uuid (FK) Tak null Kto utworzył (admin) metadata json Tak null Dodatkowe dane
Tabela reservation_payment_refunds Kolumna Typ Nullable Default Opis id uuid (PK) Nie — Identyfikator reservation_payment_id uuid (FK) Nie — Płatność źródłowa reservation_slot_id uuid (FK) Tak null Opcjonalnie powiązany slot amount decimal(10,2) Nie — Kwota zwrotu status enum Nie pending Status: pending, pending_gateway, pending_manual, completed, failed refund_type enum Nie full Typ: full, partial, slot_cancellation, forced_cancellation, item_block, activity_cancellation reason text Tak null Powód zwrotu external_refund_id string Tak null ID zwrotu P24 admin_notes text Tak null Notatki admina refund_method enum Tak null Metoda: gateway, transfer, cash, auto, undefined confirmation_number string Tak null Numer potwierdzenia (unikalny) confirmation_generated_at timestamp Tak null Data wygenerowania potwierdzenia confirmation_sent_at timestamp Tak null Data wysłania potwierdzenia confirmation_sent_to string Tak null Email odbiorcy potwierdzenia manual_confirmed_at timestamp Tak null Data ręcznego potwierdzenia manual_confirmed_by uuid (FK) Tak null Kto ręcznie potwierdził processed_by uuid (FK) Tak null Kto przetworzył processed_at timestamp Tak null Data przetworzenia metadata json Tak null Dodatkowe dane
Tabela reservation_payment_receipts Kolumna Typ Nullable Default Opis id uuid (PK) Nie — Identyfikator reservation_payment_id uuid (FK) Nie — Płatność receipt_number string Nie — Numer paragonu (unikalny) issued_at timestamp Nie — Data wystawienia pdf_path string Tak null Ścieżka do PDF sent_to_email string Tak null Email odbiorcy sent_at timestamp Tak null Data wysłania
Tabela reservation_payment_logs Kolumna Typ Nullable Default Opis id uuid (PK) Nie — Identyfikator organization_id uuid Tak null Organizacja reservation_id uuid Tak null Rezerwacja reservation_payment_id uuid Tak null Płatność reservation_payment_refund_id uuid Tak null Zwrot channel string(50) Nie — Kanał: p24_gateway, security, consistency, payment level string(20) Nie — Poziom: info, warning, error, critical event_type string(100) Nie — Typ zdarzenia (np. signature_verified, callback_processed) message string(500) Nie — Wiadomość context json Tak null Kontekst (kwoty, ID, itp.) ip_address string(45) Tak null IP żądania user_agent text Tak null User-Agent request_id string(100) Tak null ID żądania (korelacja logów) p24_session_id string(100) Tak null ID sesji P24 p24_order_id string Tak null ID zamówienia P24 p24_request_id string Tak null ID żądania P24
Tabela reservation_paid_logs Kolumna Typ Nullable Default Opis id uuid (PK) Nie — Identyfikator reservation_id uuid (FK) Nie — Rezerwacja reservation_payment_id uuid (FK) Tak null Płatność reservation_payment_refund_id uuid (FK) Tak null Zwrot action enum Nie — Typ akcji (23 wartości — patrz sekcja Statusy) previous_total_price / new_total_price decimal(10,2) Tak null Cena przed/po previous_refund_amount / new_refund_amount decimal(10,2) Tak null Kwota zwrotu przed/po previous_is_paid / new_is_paid boolean Tak null Opłacona przed/po previous_is_refund / new_is_refund boolean Tak null Czy zwrot przed/po previous_paid_at / new_paid_at timestamp Tak null Data płatności przed/po previous_refund_at / new_refund_at timestamp Tak null Data zwrotu przed/po initiated_refund_amount decimal(10,2) Tak null Kwota zainicjowanego zwrotu changed_by uuid (FK) Tak null Kto zmienił reason text Tak null Powód zmiany
Tabela waiting_reservations Kolumna Typ Nullable Default Opis id uuid (PK) Nie — Identyfikator organization_id uuid (FK) Nie — Organizacja reservationable_type string Nie — Typ obiektu (polimorfizm) reservationable_id uuid Nie — ID obiektu first_name, last_name, email, mobile_phone string Nie — Dane kontaktowe is_company, company_name, nip, regon — Tak — Dane firmy street, street_number, postal_code, city, commune, district, voivodeship string Tak null Adres total_price decimal(10,2) Tak null Cena total_net, total_vat, vat_rate — Tak null Dane VAT pricing_id uuid Tak null Cennik price_breakdown json Tak null Rozbicie cenowe show_price boolean Nie true Widoczność ceny slots_data json Tak null Dane slotów (JSON) ip_address, user_agent string Tak null Dane przeglądarki confirmation_token string(64) Nie — Token potwierdzenia (unikalny, ukryty) accepted_rodo, accepted_terms, accepted_reservationable_statute boolean Nie false Zgody consents_accepted_at timestamp Tak null Data akceptacji zgód expires_at datetime Tak null Czas wygaśnięcia
Tabela waiting_reservation_slots Kolumna Typ Nullable Default Opis id uuid (PK) Nie — Identyfikator waiting_reservation_id uuid (FK) Nie — Rezerwacja oczekująca date date Nie — Data time_from, time_to string Nie — Godziny start_at, end_at datetime Nie — Pełne daty price decimal(10,2) Tak null Cena
3. Endpointy API 3.1 Rezerwacje GET /api/reservations Opis: Lista rezerwacji z filtrami (paginacja, sortowanie) Autoryzacja: Admin, Supervisor, Employee (middleware role) Query Parameters: Standardowe filtry Spatie QueryBuilder + relations[] GET /api/reservations/{reservationId} Opis: Szczegóły rezerwacji z relacjami (complaints, statusLogs) Autoryzacja: Admin, Supervisor, Employee (middleware role) POST /api/reservations (auth) Opis: Tworzenie rezerwacji przez administratora Autoryzacja: Policy update na Item/Activity Zachowanie: Tworzy rezerwację bezpośrednio (bez soft-lock) POST /api/no-auth/reservations (noAuth) Opis: Tworzenie rezerwacji przez mieszkańca (gość) Autoryzacja: Brak (throttle public-store) Zachowanie: Tworzy WaitingReservation z soft-lock, wysyła email potwierdzający PATCH /api/reservations/{reservationId} Opis: Aktualizacja rezerwacji (dane klienta, sloty, cena) Autoryzacja: Policy update na Reservation PATCH /api/reservations/{reservationId}/change-status Opis: Zmiana statusu rezerwacji Autoryzacja: Policy update na Reservation PATCH /api/reservations/{reservationId}/change-send-notifications Opis: Włączenie/wyłączenie powiadomień dla rezerwacji Autoryzacja: Policy update na Reservation PUT /api/reservations/{reservationId}/confirm-price Opis: Potwierdzenie ceny rezerwacji przez admina Autoryzacja: Policy update na Reservation GET /api/reservations/{reservationId}/cancellation-info (auth + noAuth) Opis: Informacje o polityce anulowania i kwotach zwrotu Autoryzacja: Auth: dowolny zalogowany | NoAuth: throttle public-find GET /api/no-auth/reservations/{reservationId}/find Opis: Wyszukanie rezerwacji przez UUID + access_code (dla gościa) Autoryzacja: Brak (throttle public-find) POST /api/no-auth/confirm-reservation-email Opis: Potwierdzenie emaila rezerwacji (konwersja WaitingReservation → Reservation) Autoryzacja: Brak (throttle public-store) 3.2 Płatności GET /api/reservation-payments (auth + noAuth) Opis: Lista płatności z filtrami Autoryzacja: Auth: Admin/Supervisor/Employee | NoAuth: throttle public-find POST /api/reservation-payments (auth + noAuth) Opis: Tworzenie nowej płatności (online P24, manual, free, dopłata) Autoryzacja: Auth: Policy update na Reservation | NoAuth: throttle public-store GET /api/reservation-payments/{paymentId} Opis: Szczegóły płatności Autoryzacja: Admin, Supervisor, Employee POST /api/reservation-payments/{paymentId}/mark-as-completed Opis: Ręczne oznaczenie płatności jako opłaconej (manual payments) Autoryzacja: Policy update na ReservationPayment POST /api/reservation-payments/{paymentId}/cancel Opis: Anulowanie oczekującej płatności Autoryzacja: Policy update na ReservationPayment POST /api/reservation-payments/{paymentId}/refund Opis: Inicjowanie zwrotu (pełny lub częściowy) Autoryzacja: Policy update na ReservationPayment GET /api/reservation-payments/{paymentId}/receipt (auth + noAuth) Opis: Pobranie paragonu PDF Autoryzacja: Auth: dowolny | NoAuth: throttle public-find POST /api/reservation-payments/{paymentId}/send-receipt Opis: Wysłanie paragonu emailem Autoryzacja: Policy update na ReservationPayment POST /api/reservation-payments/{paymentId}/verify-p24-status (auth + noAuth) Opis: Weryfikacja statusu transakcji P24 Autoryzacja: Auth: dowolny | NoAuth: throttle public-store POST /api/reservation-payment-callback (auth + noAuth) Opis: Webhook callback z Przelewy24 po płatności Autoryzacja: Throttle payment-callback, weryfikacja sygnatury SHA384 3.3 Zwroty GET /api/reservation-payment-refunds (auth + noAuth) Opis: Lista zwrotów z filtrami Autoryzacja: Auth: Admin/Supervisor/Employee | NoAuth: throttle public-find POST /api/reservation-payment-refunds/{refundId}/confirm Opis: Potwierdzenie ręcznego zwrotu (pending_manual → completed) Autoryzacja: Policy update na ReservationPaymentRefund GET /api/reservation-payment-refunds/{refundId}/download (auth + noAuth) Opis: Pobranie potwierdzenia zwrotu PDF Autoryzacja: Auth: dowolny | NoAuth: throttle public-find POST /api/reservation-payment-refunds/{refundId}/send Opis: Wysłanie potwierdzenia zwrotu emailem Autoryzacja: Policy update na ReservationPaymentRefund POST /api/reservation-payment-refund-callback (auth + noAuth) Opis: Webhook callback z P24 po zwrocie Autoryzacja: Throttle payment-callback, weryfikacja sygnatury 3.4 Sloty GET /api/reservation-slots (auth + noAuth) Opis: Lista slotów rezerwacji Autoryzacja: Auth: dowolny | NoAuth: throttle public-find GET /api/reservation-slots/{slotId} (auth + noAuth) Opis: Szczegóły slotu Autoryzacja: Auth: dowolny | NoAuth: throttle public-find POST /api/cancel-reservation-slots (auth + noAuth) Opis: Anulowanie wybranych slotów rezerwacji Autoryzacja: Auth: Policy update na Reservation | NoAuth: throttle public-store 3.5 Załączniki GET /api/reservation-attachments (auth + noAuth) Opis: Lista załączników rezerwacji Autoryzacja: Auth: dowolny | NoAuth: throttle public-find POST /api/reservation-attachments (auth + noAuth) Opis: Dodanie załącznika (zdjęcia, PDF, dokumenty) Autoryzacja: Auth: Policy update na Reservation | NoAuth: throttle public-store Akceptowane formaty: JPEG, PNG, GIF, WebP, MP4, MOV, AVI, PDF, DOC, DOCX DELETE /api/reservation-attachments/{attachmentId} (auth + noAuth) Opis: Usunięcie załącznika Autoryzacja: Auth: Policy update na Reservation | NoAuth: throttle public-store 3.6 Logi płatności GET /api/reservation-paid-logs Opis: Lista logów zmian płatności (audyt) Autoryzacja: Admin, Supervisor, Employee 4. Logika biznesowa 4.1 Główne procesy Proces tworzenia rezerwacji (mieszkaniec / noAuth) Walidacja danych (formularz, dostępność slotów, deadline, blokady) Obliczenie ceny na podstawie cennika (CalculatePriceForReservationable) Utworzenie WaitingReservation z WaitingReservationSlot (soft-lock) Każdy WaitingReservationSlot tworzy wpis w Schedule (blokuje termin) Wysłanie emaila z linkiem potwierdzającym (ReservationEmailConfirmationNotification) Po kliknięciu linku: Walidacja tokenu i ważności (confirmation_token, expires_at) Usunięcie WaitingReservation (i wpisów Schedule) Utworzenie Reservation z ReservationSlot (nowe wpisy Schedule) Wygenerowanie identyfikatorów (UUID, access_code) Przypisanie/utworzenie klienta (FindOrCreateClientForReservation) Zbudowanie snapshotu (BuildReservationSnapshots) Ustalenie statusu płatności (DetermineReservationPricingAndStatus) Wysłanie powiadomień (SendNewReservationNotifications) Proces tworzenia rezerwacji (admin / auth) Walidacja danych (formularz, dostępność slotów) Bezpośrednie utworzenie Reservation z ReservationSlot (bez soft-lock) Wygenerowanie identyfikatorów, snapshot, ustalenie ceny Powiadomienia do klienta i managera Proces płatności online (Przelewy24) Utworzenie ReservationPayment (status: pending) Rejestracja transakcji w P24 (P24PaymentCreator) Wygenerowanie URL płatności i podpisu SHA384 Klient przekierowany do P24 P24 wysyła callback (ProcessPrzelewy24Callback): Weryfikacja sygnatury (P24CallbackValidator) Weryfikacja statusu transakcji (VerifyP24TransactionStatus) Oznaczenie płatności jako completed (MarkPaymentAsCompleted) Dystrybucja kwoty do slotów (DistributePaymentToSlots) Aktualizacja payment_status rezerwacji Wygenerowanie paragonu (ReceiptService) Wysłanie powiadomień (SendPaymentConfirmedNotification) Proces zwrotu Walidacja (RefundValidator): status completed/partially_refunded, kwota ≤ available Ustalenie metody zwrotu (DetermineRefundMethod) Utworzenie ReservationPaymentRefund Jeśli gateway: wysłanie do P24 (InitiateGatewayRefund → CallP24RefundApi) Jeśli manual: status pending_manual, oczekuje na potwierdzenie admina Po zakończeniu (CompleteRefund): Aktualizacja refunded_amount na slotach (UpdateSlotsRefundedAmountsFromRefund) Aktualizacja payment_status płatności i rezerwacji Wygenerowanie potwierdzenia zwrotu (RefundConfirmationService) Wysłanie powiadomień (SendRefundProcessedNotification) 4.2 Reguły biznesowe Rezerwacja nie może kolidować z istniejącą rezerwacją — system sprawdza harmonogram Anulowanie jest możliwe tylko w statusach pending lub confirmed Edycja rezerwacji możliwa tylko w statusach pending lub confirmed Slot w przeszłości nie może być zarezerwowany (SlotNotInPastRule) Rezerwacja wymaga deadline'u — X godzin przed terminem (ReservationDeadlineRule) Minimalny zwrot to 0.01 PLN (MIN_REFUND_AMOUNT) Maksymalnie 50 oczekujących zwrotów na płatność (MAX_PENDING_REFUNDS_PER_PAYMENT) Duplikaty zwrotów wykrywane w oknie 60 sekund (DUPLICATE_WINDOW_SECONDS) Zwrot bramkowy: max 3 próby z opóźnieniem 2 sekund (MAX_RETRY_ATTEMPTS, RETRY_DELAY_SECONDS) Niezalogowany użytkownik przy anulowaniu slotów — zwrot zawsze pending_manual Gdy refunded_amount >= price slotu → automatyczne anulowanie slotu Gdy wszystkie sloty anulowane → automatyczne anulowanie rezerwacji Dopłata: jeśli amount > remaining, system automatycznie zwiększa total_price Blokada obiektu anuluje tylko kolidujące sloty , nie całe rezerwacje Odwołanie zajęć anuluje wszystkie rezerwacje powiązane z danym ActivityItem Cena nie może być zmniejszona poniżej opłaconej kwoty (wymaga zwrotu) Rezerwacja wymaga akceptacji regulaminu obiektu, jeśli obiekt go posiada (ReservationableStatuteRequiredRule) StoreReservationControllerRequest — tworzenie rezerwacji Pole Reguły reservationable_type required, string, in:Item,ActivityItem reservationable_id required, uuid, exists first_name required, string, max:255 last_name required, string, max:255 email required, email, max:255 mobile_phone required, string, max:32 is_company sometimes, boolean company_name required_if:is_company,true nip required_if:is_company,true slots required, array, min:1 slots.*.date required, date slots.*.time_from required, date_format:H:i slots.*.time_to required, date_format:H:i, after:slots.*.time_from accepted_rodo required, boolean, accepted accepted_terms required, boolean, accepted
Custom Rules: - SlotAvailabilityRule — sprawdza czy termin nie jest zajęty - SlotNotInPastRule — termin nie może być w przeszłości - ReservationDeadlineRule — deadline rezerwacji - ItemBlockConflictRule — brak kolizji z blokadami - ReservationableAllowedRule — obiekt pozwala na rezerwację - ReservationableStatuteRequiredRule — regulamin obiektu wymagany - FullDayReservationRule — rezerwacja pełnodniowa (jeśli dotyczy) - ActivityItemHasAvailableSlotsRule — wolne miejsca na zajęciach - VerifyReservationCorrectDataRule — spójność danych
RefundReservationPaymentControllerRequest — zwrot Pole Reguły amount required, numeric, min:0.01 reason required, string, max:500 refund_method required, in:gateway,transfer,cash,auto slot_id nullable, uuid, exists:reservation_slots,id
Custom Rules: - MaxRefundAmountPaymentRule — kwota ≤ dostępna na płatności - MaxRefundAmountReservationRule — kwota ≤ dostępna na rezerwacji
5. Autoryzacja i uprawnienia Polityki (Policies) Model Akcja Admin/Supervisor Employee Warunki Reservation view ✅ (ta sama organizacja) ❌ belongsToOrganization Reservation update ✅ (ta sama organizacja) ✅ (manager obiektu) Supervisor: organizacja, Employee: isItemManager ReservationPayment view ✅ (ta sama organizacja) ❌ Przez rezerwację ReservationPayment update ✅ (ta sama organizacja) ✅ (manager obiektu) Przez rezerwację ReservationPaymentRefund update ✅ (ta sama organizacja) ✅ (manager obiektu) Przez payment → rezerwacja ReservationSlot update ✅ (ta sama organizacja) ✅ (manager obiektu) Przez rezerwację ReservationPaidLog view ✅ (ta sama organizacja) ❌ Przez rezerwację ReservationPaidLog update ❌ ❌ Logi niemodyfikowalne ReservationPaymentReceipt update ✅ (ta sama organizacja) ✅ (manager obiektu) Przez payment → rezerwacja
Middleware Kontroler Metody chronione Rola ReservationController index, show, update, changeStatus, changeSendNotifications, confirmPrice Admin, Supervisor, Employee ReservationPaymentController show, markAsCompleted, sendReceipt, cancel, refund Admin, Supervisor, Employee ReservationPaymentRefundController confirm, send Admin, Supervisor, Employee ReservationPaidLogController index Admin, Supervisor, Employee ReservationSlotController — (brak middleware) Dostęp przez Policy ReservationAttachmentController — (brak middleware) Dostęp przez Policy
6. Eventy i efekty uboczne Observer: ReservationObserver Hook Co robi creating Wywołuje CreatingReservationObserver — generowanie UUID, access_code, przypisanie klienta updated Wywołuje UpdatedReservationObserver — obsługa zmian statusu, harmonogramu, powiadomień deleting Wywołuje DeletingReservationObserver — czyszczenie harmonogramów i powiązanych danych
Observer: StatusLogObserver Automatycznie loguje każdą zmianę statusu do tabeli status_logs (polimorficzna relacja).
Atrybuty wyliczane (Attr) Atrybut Model Opis is_paid Reservation payment_status ∈ [paid, partially_refunded, not_required] paid_at Reservation Data najnowszej potwierdzonej płatności is_refund Reservation payment_status ∈ [refunded, partially_refunded] refund_at Reservation Data najnowszego zwrotu total_paid Reservation payments_amount - total_refunded total_refunded Reservation Suma completed refundów available_for_refund Reservation total_paid - total_already_refunded can_add_review Reservation Status confirmed + termin zakończony + brak opinii can_cancel_reservation Reservation Status cancellable + deadline nie minął is_completed, is_pending, is_expired ReservationPayment Na podstawie statusu i expires_at total_refunded, available_for_refund ReservationPayment Z relacji refundów has_receipt ReservationPayment Czy istnieje paragon is_active, is_cancelled ReservationSlot Na podstawie statusu is_fully_paid, is_partially_paid ReservationSlot paid_amount vs price available_for_refund ReservationSlot paid_amount - refunded_amount is_completed, is_pending ReservationPaymentRefund Na podstawie statusu is_pending_gateway, is_pending_manual ReservationPaymentRefund Szczegółowe statusy pending has_confirmation, is_confirmation_sent ReservationPaymentRefund Czy jest/wysłano potwierdzenie can_confirm_manual ReservationPaymentRefund Czy można ręcznie potwierdzić
7. Powiadomienia System wysyła automatyczne powiadomienia na każdym etapie:
Powiadomienie Klasa Kiedy Odbiorca Potwierdzenie emaila ReservationEmailConfirmationNotification Po złożeniu rezerwacji (noAuth) Klient Rezerwacja utworzona ReservationCreatedNotification Po potwierdzeniu emaila / utworzeniu Klient Potwierdzenie płatności ReservationPaymentConfirmedNotification Po opłaceniu (callback P24 / manual) Klient Płatność oczekująca ReservationPaymentPendingNotification Po utworzeniu płatności P24 Klient Płatność nieudana ReservationPaymentFailedNotification Po nieudanej płatności P24 Klient Przypomnienie o płatności ReservationPaymentReminderNotification CRON — przed terminem płatności Klient Przypomnienie o rezerwacji ReservationReminderNotification CRON — dzień przed terminem Klient Paragon (e-receipt) ReservationReceiptNotification Po wygenerowaniu paragonu Klient Potwierdzenie ceny ReservationPriceConfirmedNotification Po potwierdzeniu ceny przez admina Klient Anulowanie rezerwacji ReservationCancelledNotification Po anulowaniu Klient Anulowanie (blokada obiektu) ReservationCancelledDueToItemBlockNotification Po blokadzie obiektu Klient Anulowanie (odwołanie zajęć) ReservationCancelledDueToActivityCancellationNotification Po odwołaniu zajęć Klient Zwrot przetworzony ReservationRefundProcessedNotification Po zakończeniu zwrotu Klient Potwierdzenie zwrotu (PDF) RefundConfirmationNotification Po wysłaniu potwierdzenia zwrotu Klient Prośba o opinię ReservationReviewReminderNotification CRON — po zakończeniu rezerwacji Klient Nowa rezerwacja (manager) NewReservationForItemManagerNotification Po utworzeniu Manager obiektu Anulowanie slotu (manager) SlotCancelledForManagerNotification Po anulowaniu slotu Manager obiektu Nowy uczestnik (trener) NewParticipantForTrainerNotification Po zapisie na zajęcia Trener
8. Komendy CRON Komenda Opis Harmonogram reservation:send-reminders Wysyłanie przypomnień o nadchodzących rezerwacjach Codziennie reservation:send-payment-reminders Przypomnienia o nieopłaconych rezerwacjach Codziennie reservation:send-review-reminders Przypomnienia o dodaniu opinii (po zakończeniu) Codziennie reservation:cleanup-expired-payments Oznaczanie wygasłych płatności P24 jako failed Co kilka minut reservation:cleanup-waiting Usuwanie wygasłych WaitingReservation (soft-lock cleanup) Co kilka minut reservation:cleanup-payment-logs Usuwanie starych logów płatności Codziennie/tygodniowo reservation:reconcile-pending-refunds Uzgadnianie statusów oczekujących zwrotów P24 Codziennie reservation:create-bulk Masowe tworzenie rezerwacji (narzędzie) Na żądanie
9. Powiązania z innymi domenami 10. Konfiguracja Konfiguracja Przelewy24 Plik: config/transfers24.php
Parametr Env Variable Opis merchant_id PRZELEWY24_MERCHANT_ID ID sprzedawcy pos_id PRZELEWY24_POS_ID ID punktu sprzedaży crc PRZELEWY24_CRC Klucz CRC do podpisów report_key PRZELEWY24_REPORT_KEY Klucz raportowy test_server PRZELEWY24_TEST_SERVER Tryb testowy (default: true) url_return — /payment/return (frontend) url_status — /api/no-auth/reservation-payment-callback (webhook) url_refund_status — /api/no-auth/reservation-payment-refund-callback time-limit — 15 minut na transakcję encoding — UTF-8
Polityka anulowania Każdy obiekt (Item) może mieć własną politykę:
Parametr Opis Przykład cancellation_deadline_hours Ile godzin przed terminem można anulować 24 cancellation_policy_description Tekst polityki wyświetlany klientowi "Anulowanie możliwe do 24h przed..."
Terminy rezerwacji Parametr Opis Przykład reservation_deadline_hours Ile godzin przed terminem można rezerwować 2 reservation_start_time Od której godziny możliwe rezerwacje 06:00 reservation_end_time Do której godziny możliwe rezerwacje 22:00
Stałe konfiguracyjne (ReservationEnumService) Stała Wartość Opis MIN_REFUND_AMOUNT 0.01 Minimalny zwrot (PLN) MAX_RETRY_ATTEMPTS 3 Max prób zwrotu P24 RETRY_DELAY_SECONDS 2 Opóźnienie między próbami DUPLICATE_WINDOW_SECONDS 60 Okno wykrywania duplikatów MAX_PENDING_REFUNDS_PER_PAYMENT 50 Max oczekujących zwrotów na płatność
11. Statusy i enumy Statusy rezerwacji stateDiagram-v2
[*] --> pending: Utworzenie
pending --> confirmed: Potwierdzenie email
pending --> canceled: Anulowanie
pending --> rejected: Odrzucenie
confirmed --> canceled: Anulowanie
confirmed --> [*]: Zakończenie
canceled --> [*]
rejected --> [*] Status Opis pending Rezerwacja oczekuje na potwierdzenie emaila confirmed Rezerwacja potwierdzona, oczekuje na płatność lub realizację canceled Rezerwacja anulowana (przez klienta, admina lub system) rejected Rezerwacja odrzucona przez administratora
Statusy płatności rezerwacji (payment_status) Status Opis not_required Płatność nie jest wymagana (rezerwacja bezpłatna) pending Oczekuje na płatność partially_paid Częściowo opłacona (przy płatnościach ratalnych / dopłatach) paid W pełni opłacona refunded Zwrot pełnej kwoty partially_refunded Częściowy zwrot
Statusy transakcji (ReservationPayment.status) Status Opis pending Oczekuje na płatność completed Opłacona failed Nieudana cancelled Anulowana refunded Pełny zwrot partially_refunded Częściowy zwrot reverted Cofnięta
Statusy zwrotów (ReservationPaymentRefund.status) Status Opis pending Oczekuje na przetworzenie pending_gateway Wysłano do P24, oczekuje na callback pending_manual Oczekuje na ręczne potwierdzenie admina completed Zwrot zakończony failed Zwrot nieudany
Metody płatności Metoda Opis przelewy24 Płatność online przez Przelewy24 (BLIK, karta, przelew) manual Płatność ręczna (gotówka, przelew poza systemem) free Bezpłatna rezerwacja
Metody zwrotu Metoda Opis gateway Automatyczny zwrot przez Przelewy24 transfer Ręczny przelew bankowy cash Zwrot gotówką auto Automatyczny zwrot systemowy undefined Metoda nieokreślona (oczekuje na wybór)
Typy zwrotu Typ Opis full Pełny zwrot (anulowanie przez klienta/admina) partial Częściowy zwrot slot_cancellation Zwrot za anulowanie pojedynczego slotu forced_cancellation Wymuszone anulowanie item_block Zwrot z powodu blokady obiektu activity_cancellation Zwrot z powodu odwołania zajęć manual Ręczny zwrot
Typy anulowania Typ Opis by_resident Anulowane przez mieszkańca by_admin Anulowane przez admina forced Wymuszone anulowanie due_to_item_block Z powodu blokady obiektu due_to_activity_cancellation Z powodu odwołania zajęć
Akcje w PaidLog 23 typy akcji logowanych w reservation_paid_logs:
Akcja Opis created Utworzenie rezerwacji paid Opłacenie refund Zwrot payment_created Utworzenie płatności payment_completed Zakończenie płatności payment_failed Nieudana płatność payment_cancelled Anulowanie płatności refund_initiated Inicjacja zwrotu refund_completed Zakończenie zwrotu price_confirmed Potwierdzenie ceny price_changed Zmiana ceny price_zeroed Wyzerowanie ceny price_increased_for_doplata Zwiększenie ceny (dopłata) price_reduced_after_cancellation Zmniejszenie ceny po anulowaniu płatności cancelled_by_resident Anulowanie przez mieszkańca cancelled_by_admin Anulowanie przez admina cancelled_forced Wymuszone anulowanie cancelled_due_to_item_block Anulowanie (blokada obiektu) cancelled_due_to_activity_cancellation Anulowanie (odwołanie zajęć) slots_cancelled Anulowanie slotów manual_payment_marked Ręczne oznaczenie płatności manual_payment_reverted Cofnięcie ręcznej płatności manual_refund_marked Ręczne oznaczenie zwrotu free_reservation_confirmed Potwierdzenie bezpłatnej rezerwacji
12. Dopłaty (Multiple Payments) System obsługuje scenariusz dopłat, gdy rezerwacja ma już częściowe lub pełne opłaty.
Jak to działa? sequenceDiagram
participant A as Admin
participant S as System
participant R as Rezerwacja
participant P as Płatność
participant SL as Sloty
Note over R: total_price=2952, total_paid=2952 (w pełni opłacona)
A->>S: Dodaj dopłatę (amount=1000, mark_completed=true)
S->>S: Auto-zwiększa total_price do 3952
S->>P: Tworzy płatność (completed, 1000 PLN)
S->>SL: Dystrybuuje 1000 PLN do slotów
S->>R: Aktualizuje payment_status
Note over R: total_price=3952, total_paid=3952 Parametry API dla dopłat {
"reservation_id" : "uuid" ,
"payment_method" : "manual" ,
"amount" : 1000 ,
"mark_completed" : true ,
"paid_at" : "2026-02-06" ,
"reason" : "Dopłata za dodatkowy sprzęt"
}
Zasady dopłat Warunek Zachowanie Brak completed payments amount = nowa cena całkowita (stare zachowanie) Są completed payments amount = kwota dopłaty amount > pozostałe do zapłaty Automatycznie zwiększa total_price amount nie podane Tworzy płatność na pełną pozostałą kwotę
13. Mechanizm soft-lock Mechanizm soft-lock (tymczasowej blokady)
Po złożeniu rezerwacji przez niezalogowanego użytkownika, system tworzy WaitingReservation wraz z WaitingReservationSlot dla każdego wybranego terminu. Każdy WaitingReservationSlot tworzy wpis w harmonogramie (Schedule), co blokuje termin dla innych użytkowników — formularz rezerwacji pokazuje go jako niedostępny.
Jeśli użytkownik nie potwierdzi rezerwacji w wyznaczonym czasie, komenda CRON reservation:cleanup-waiting automatycznie czyści wygasłe WaitingReservation wraz z ich slotami i wpisami w harmonogramie — termin wraca jako dostępny.
Zabezpieczenia anty-troll:
Konfigurowalny czas na potwierdzenie (domyślnie do 60 min) Rate limiting na endpoint składania rezerwacji (throttle:public-store) Honeypot fields w formularzu (website, company_website, fax_number) 14. Bezpieczeństwo płatności Weryfikacja callbacków P24 Każdy callback weryfikowany podpisem SHA384 (P24CallbackValidator) Porównanie amount, session_id, order_id z oryginalnymi danymi Logowanie prób fraud (PAYMENT_LOG_CHANNEL_SECURITY) Zdarzenia bezpieczeństwa: signature_mismatch, session_mismatch, order_mismatch, amount_mismatch Logi płatności Szczegółowe logi w reservation_payment_logs:
Kanał Opis p24_gateway Komunikacja z Przelewy24 security Zdarzenia bezpieczeństwa consistency Sprawdzanie spójności danych payment Ogólne zdarzenia płatności
Poziom Opis info Normalne operacje warning Potencjalne problemy error Błędy critical Krytyczne błędy bezpieczeństwa
15. Dane audytowe (Snapshot) Przy tworzeniu rezerwacji system zapisuje snapshot obiektu w polu reservationable_snapshot:
Snapshot dla Item {
"_pricing_snapshot" : {
"id" : "uuid" ,
"name" : "Cennik standardowy" ,
"prices" : [ ... ],
"vat_rate" : "23%"
},
"_client_snapshot" : {
"first_name" : "Jan" ,
"last_name" : "Kowalski" ,
"email" : "jan@example.com"
},
"_vat_rate_source" : "pricing" ,
"name" : "Sala gimnastyczna" ,
"address" : "ul. Szkolna 1"
}
Snapshot dla ActivityItem {
"_pricing_snapshot" : { ... },
"_client_snapshot" : { ... },
"_vat_rate_source" : "pricing" ,
"activity_name" : "Fitness" ,
"activity_item_date" : "2026-03-01" ,
"trainer_name" : "Anna Nowak"
}
16. Kluczowe klasy biznesowe Action/Other — główne klasy Klasa Opis CreateReservation Tworzenie rezerwacji (auth) CreateWaitingReservation Tworzenie tymczasowej rezerwacji (noAuth soft-lock) UpdateReservation Aktualizacja rezerwacji CancelReservation Anulowanie rezerwacji SlotCreator Tworzenie slotów z danymi SlotValidator Walidacja dostępności slotów SlotCancellation Logika anulowania slotów SlotScheduleManager Zarządzanie wpisami harmonogramu P24PaymentCreator Rejestracja transakcji w P24 P24CallbackHandler Obsługa callbacków P24 P24CallbackValidator Weryfikacja podpisów callbacków PaymentFactory Tworzenie płatności wg metody InitiateRefund Inicjowanie procesu zwrotu InitiateGatewayRefund Zwrot przez P24 CompleteRefund Finalizacja zwrotu RefundValidator Walidacja parametrów zwrotu RefundDistributor Dystrybucja zwrotu do slotów ReceiptService Generowanie/wysyłanie paragonów ReceiptGenerator Generator pliku PDF paragonu RefundConfirmationService Generowanie potwierdzeń zwrotów RefundConfirmationGenerator Generator PDF potwierdzenia zwrotu DistributePaymentToSlots Dystrybucja płatności do slotów CalculatePriceForReservationable Obliczanie ceny rezerwacji BuildReservationSnapshots Budowanie snapshotów danych FindOrCreateClientForReservation Automatyczne tworzenie/przypisanie klienta SendNewReservationNotifications Wysyłanie powiadomień o nowej rezerwacji HandleReservationStatusChange Obsługa zmian statusu rezerwacji
Scopes (Query Scopes) Scope Model Opis active() ReservationSlot Sloty ze statusem active cancelled() ReservationSlot Sloty anulowane paid() ReservationSlot Sloty opłacone unpaid() ReservationSlot Sloty nieopłacone withAvailableRefund() ReservationSlot Sloty z dostępnym zwrotem pending() ReservationPayment Płatności oczekujące completed() ReservationPayment Płatności zakończone notExpired() ReservationPayment Niewygasłe płatności pending() ReservationPaymentRefund Zwroty oczekujące completed() ReservationPaymentRefund Zwroty zakończone pendingManual() ReservationPaymentRefund Zwroty pending_manual pendingGateway() ReservationPaymentRefund Zwroty pending_gateway forSlot(slotId) ReservationPaymentRefund Zwroty dla konkretnego slotu withConfirmation() ReservationPaymentRefund Zwroty z potwierdzeniem sent() / notSent() ReservationPaymentReceipt Paragony wysłane/niewysłane withPdf() ReservationPaymentReceipt Paragony z PDF reservationsWithoutReview() Reservation Rezerwacje bez opinii canAddComplaint() Reservation Rezerwacje kwalifikujące się do reklamacji
Model Reservation rejestruje dwie kolekcje mediów (Spatie MediaLibrary):
Kolekcja Akceptowane typy Opis attachments JPEG, PNG, GIF, WebP, MP4, MOV, AVI, PDF, DOC, DOCX Załączniki do rezerwacji refund_confirmations PDF Potwierdzenia zwrotów (z custom property refund_id)
18. Znane ograniczenia i TODO Ważne ograniczenia
Rezerwacje nie mogą kolidować — system automatycznie blokuje możliwość zarezerwowania zajętego terminu W przypadku blokady obiektu (ItemBlock), system anuluje tylko kolidujące sloty z automatycznym zwrotem — pozostałe terminy pozostają aktywne W przypadku odwołania zajęć (ActivityItem is_canceled = true), system anuluje wszystkie rezerwacje powiązane z daną sesją Cena nie może być zmniejszona poniżej już opłaconej kwoty — wymaga zwrotu Niezalogowany użytkownik przy anulowaniu slotów — zwrot zawsze pending_manual