Przejdź do treści

Cenniki (Pricing)

Ostatnia aktualizacja dokumentacji: 26 lutego 2026 Stan synchronizacji z kodem: Zsynchronizowany

Elastyczne ceny z pelna obsluga VAT — od stawek domyslnych po indywidualne cenniki dla stalych klientow.


1. Opis ogolny

Domena Cennikow zarzadza polityka cenowa obiektow i zajec. To jak ksiega cen w recepcji — ale z automatycznym obliczaniem VAT, mozliwoscia ustalania indywidualnych stawek dla klientow i historia zmian cen.

System obsluguje dwa typy cennikow:

  • Cennik godzinowy — dla obiektow wynajmowanych na godziny (sale, boiska)
  • Cennik za zajecia — dla aktywnosci grupowych (fitness, warsztaty)

2. Architektura domeny

2.1 Modele danych

Model Klasa Opis
Pricing Domain\Pricing\Model\Pricing Cennik przypisany polimorficznie do obiektu (Item) lub aktywnosci (Activity), opcjonalnie do klienta

2.2 Diagram relacji

erDiagram
    Pricing ||--o| Client : "cennik indywidualny"
    Pricing }o--|| Item : "priceable (morph)"
    Pricing }o--|| Activity : "priceable (morph)"
    Reservation ||--o| Pricing : "pricing_id (FK)"

    Pricing {
        uuid id PK
        string priceable_type
        uuid priceable_id
        decimal value
        uuid client_id FK
        string vat_rate_override
        boolean is_active
        datetime created_at
        datetime updated_at
    }

2.3 Struktura tabeli w bazie danych

Tabela: pricings

Migracja: 0001_01_01_000018_create_pricings.php

Kolumna Typ Nullable Default Opis
id uuid (PK) Nie auto Identyfikator cennika
priceable_type string Nie Typ modelu (FQCN): Domain\Item\Model\Item lub Domain\Activity\Model\Activity
priceable_id uuid Nie ID modelu (Item lub Activity)
value decimal(12,2) Nie Cena netto w PLN
client_id uuid (FK) Tak NULL ID klienta (cennik indywidualny); NULL = cennik domyslny
vat_rate_override string Nie '23' Nadpisanie stawki VAT
is_active boolean Nie true Czy cennik jest aktywny
created_at timestamp Tak Data utworzenia
updated_at timestamp Tak Data ostatniej modyfikacji

Indeksy:

Nazwa Kolumny Typ
pricings_effective_lookup priceable_type, priceable_id, client_id, is_active, created_at Kompozytowy

Klucze obce:

Kolumna Referencja On Delete
client_id clients.id CASCADE

Referencja z rezerwacji

Tabela reservations zawiera kolumne pricing_id (UUID, nullable) z kluczem obcym do pricings.id i regula onDelete('set null'). Dzieki snapshotowi cennika w reservationable_snapshot dane cenowe sa zachowane nawet po usunieciu cennika.

2.4 Atrybuty wyliczane (Accessors)

Atrybut Typ Opis Logika
effective_vat_rate string Efektywna stawka VAT vat_rate_override > klient vat_rate > '23' (domyslna)
effective_vat_rate_numeric float\|null Stawka VAT jako liczba 23.00, 8.00, 5.00, 0.00, null (dla ZW/NP)
effective_vat_rate_label string Etykieta stawki VAT "23%", "8%", "Zwolniony", "Nie podlega"
is_default_pricing bool Czy cennik domyslny true gdy client_id === null
price_unit string Jednostka cenowa 'hour' dla Item, 'activity' dla Activity
price_unit_label string Etykieta jednostki 'za godzine' lub 'za zajecia'
value_gross float Cena brutto value * (1 + stawka/100) lub value dla ZW/NP

2.5 Scopes (zakresy zapytan)

Scope Metoda Opis
default() whereNull('client_id') Cenniki domyslne (ogolne)
forClient($clientId) where('client_id', $clientId) Cenniki dla konkretnego klienta
active() where('is_active', true) Tylko aktywne cenniki
assignedClient() whereNotNull('client_id') Cenniki przypisane do klienta

2.6 Relacje modelu

Relacja Typ Model docelowy Opis
priceable() MorphTo Item lub Activity Obiekt/aktywnosc, do ktorej przypisany jest cennik
client() BelongsTo Client Klient (dla cennika indywidualnego)

2.7 Traity modelu

Trait Opis
HasUuids Automatyczne generowanie UUID jako klucz glowny
TraitPricing Metody domenowe (deaktywacja, obliczenia, observery)

3. Endpointy API

Prefix: /api/pricings Middleware: auth:api, role:admin|supervisor|employee Plik routow: routes/api/auth/pricing.php

3.1 Lista cennikow

GET /api/pricings

  • Opis: Pobiera liste cennikow z filtrami i paginacja
  • Autoryzacja: Role: admin, supervisor, employee
  • Controller: PricingController@index -> IndexPricingController

Query Parameters (filtry):

Parametr Typ Wymagane Reguly walidacji Opis
filter[priceable_type] string Nie sometimes\|string Typ modelu (FQCN klasy Item lub Activity)
filter[priceable_id] uuid Nie sometimes\|uuid ID obiektu/aktywnosci
filter[client_id] uuid\|null Nie sometimes\|nullable\|uuid ID klienta
filter[is_active] boolean Nie sometimes\|boolean Status aktywnosci
filter[assigned_client] Nie Scope: tylko cenniki przypisane do klienta
page integer Nie Standardowe reguły paginacji Numer strony
per_page integer Nie Standardowe reguły paginacji Elementy na strone

Dozwolone filtry (Spatie QueryBuilder):

Filtr Typ Opis
id exact Filtrowanie po ID cennika
priceable_type exact Filtrowanie po typie modelu
priceable_id exact Filtrowanie po ID modelu
client_id exact Filtrowanie po ID klienta
is_active exact Filtrowanie po statusie
assigned_client scope Cenniki z przypisanym klientem

Relacje ladowane w odpowiedzi:

  • priceable — obiekt (Item) lub aktywnosc (Activity)
  • client — klient (jesli cennik indywidualny)

Response (sukces, 200):

{
  "data": [
    {
      "id": "uuid-cennika",
      "priceable_type": "Domain\\Item\\Model\\Item",
      "priceable_id": "uuid-obiektu",
      "value": 100.00,
      "value_gross": 123.00,
      "client_id": null,
      "vat_rate_override": "23",
      "effective_vat_rate": "23",
      "effective_vat_rate_label": "23%",
      "is_active": true,
      "is_default": true,
      "price_unit": "hour",
      "price_unit_label": "za godzine",
      "created_at": "2026-02-26 10:00:00",
      "updated_at": "2026-02-26 10:00:00",
      "can": {
        "view": true,
        "create": true,
        "update": true
      },
      "priceable": { "..." : "dane obiektu/aktywnosci" },
      "client": null
    }
  ],
  "links": { "..." : "linki paginacji" },
  "meta": { "..." : "metadane paginacji" }
}

3.2 Tworzenie cennika

POST /api/pricings

  • Opis: Tworzy nowy cennik dla obiektu lub aktywnosci
  • Autoryzacja: Role: admin, supervisor, employee + Policy create (sprawdza przynaleznosc do organizacji)
  • Controller: PricingController@store -> StorePricingController

Body (Request):

Pole Typ Wymagane Reguly walidacji Opis
priceable_type string Warunkowo sometimes\|nullable\|required_with:priceable_id\|string\|in:Domain\Item\Model\Item,Domain\Activity\Model\Activity Typ modelu
priceable_id uuid Warunkowo sometimes\|nullable\|required_with:priceable_type\|uuid\|CheckExistPriceableIdRule ID modelu
value numeric Tak required\|numeric\|min:0 Cena netto (PLN)
client_id uuid Nie sometimes\|nullable\|uuid\|exists:clients,id ID klienta (cennik indywidualny)
vat_rate_override string Tak required\|in:23,8,5,0,zw,np Stawka VAT
is_active boolean Nie sometimes\|boolean Czy aktywny (domyslnie true)

Custom Validation Rule — CheckExistPriceableIdRule:

Sprawdza czy:

  1. priceable_type jest podklasa Eloquent\Model
  2. Istnieje rekord o podanym priceable_id w tabeli danego modelu

Przyklad request:

{
  "priceable_type": "Domain\\Item\\Model\\Item",
  "priceable_id": "550e8400-e29b-41d4-a716-446655440000",
  "value": 100.00,
  "vat_rate_override": "23",
  "client_id": null,
  "is_active": true
}

Response (sukces, 200):

{
  "message": "The Pricing has been successfully added",
  "status": 200,
  "success": false
}

Logika biznesowa przy tworzeniu:

  1. Walidacja danych wejsciowych
  2. Sprawdzenie policy create (przynaleznosc do organizacji)
  3. Wywolanie Pricing::create($validated)
  4. Observer creating automatycznie:
  5. Ustawia is_active = true jesli nie podano
  6. Dezaktywuje istniejace aktywne cenniki dla tej samej kombinacji (priceable + client)

Custom messages walidacji:

Pole Regula Klucz tlumaczenia
priceable_type required_with validation.custom.store_pricing.priceable_type_required_with
priceable_type in validation.custom.store_pricing.priceable_type_invalid
priceable_id required_with validation.custom.store_pricing.priceable_id_required_with
value required validation.custom.store_pricing.value_required
value min validation.custom.store_pricing.value_min
client_id exists validation.custom.store_pricing.client_id_exists
vat_rate_override required validation.custom.store_pricing.vat_rate_override_required
vat_rate_override in validation.custom.store_pricing.vat_rate_override_invalid

3.3 Zmiana stanu cennika

PATCH /api/pricings/{pricingId}/change-state

  • Opis: Przelacza stan is_active cennika (aktywacja/dezaktywacja)
  • Autoryzacja: Role: admin, supervisor, employee + Policy update
  • Controller: PricingController@changeState

Parametry URL:

Parametr Typ Opis
pricingId uuid ID cennika do zmiany stanu

Response (sukces, 200):

{
  "message": "Stan zostal zmieniony",
  "status": 200
}

Logika biznesowa:

  1. Sprawdzenie policy update (przynaleznosc do organizacji)
  2. Przelaczenie pola is_active na przeciwna wartosc
  3. Observer updating — jesli cennik jest aktywowany (is_active zmienia sie na true):
  4. Dezaktywuje inne aktywne cenniki dla tej samej kombinacji (priceable + client), wykluczajac biezacy

4. Logika biznesowa

4.1 Glowne procesy

Scenariusz 1: Ustawienie cennika dla sali

flowchart LR
    A[Wybiera obiekt] --> B[Dodaje cennik]
    B --> C[Podaje cene netto]
    C --> D[Wybiera stawke VAT]
    D --> E[Zapisuje]
    E --> F[System oblicza brutto]
  1. Administrator otwiera obiekt "Sala konferencyjna"
  2. Klika "Dodaj cennik"
  3. Wpisuje cene netto: 100 zl/godz.
  4. Wybiera stawke VAT: 23%
  5. Zapisuje — system automatycznie oblicza brutto: 123 zl/godz.
  6. Cennik jest aktywny od razu

Scenariusz 2: Indywidualna stawka dla stalego klienta

  1. Firma "ABC Sp. z o.o." jest stalym klientem
  2. Administrator tworzy cennik dla tej firmy
  3. Cena netto: 80 zl/godz. (rabat 20%)
  4. VAT: 23%
  5. Od teraz przy rezerwacjach tej firmy — automatycznie stawka 80 zl

Scenariusz 3: Zmiana ceny obiektu

  1. Administrator tworzy nowy cennik: 120 zl/godz.
  2. System automatycznie dezaktywuje poprzedni cennik (100 zl/godz.)
  3. Nowe rezerwacje — po nowej cenie
  4. Istniejace rezerwacje — zachowuja stara cene (snapshot)
  5. Historia cen jest zachowana

Scenariusz 4: Obiekt staje sie bezplatny (is_paid = false)

  1. Gdy is_paid na obiekcie/aktywnosci zmienia sie na false
  2. Klasa SetZeroForIsPaidDirtyField automatycznie tworzy cennik:
  3. value = 0
  4. is_active = true
  5. client_id = null
  6. vat_rate_override = '23'
  7. Observer creating dezaktywuje poprzednie cenniki

4.2 Reguly biznesowe

  1. Tylko jeden aktywny cennik — dla kazdej kombinacji (obiekt/aktywnosc + klient) moze istniec tylko jeden aktywny cennik
  2. Automatyczna dezaktywacja — tworzenie nowego cennika lub aktywacja istniejacego automatycznie dezaktywuje pozostale dla tej samej kombinacji
  3. Hierarchia cennikow — cennik kliencki ma priorytet nad domyslnym
  4. Cena minimalna — wartosc cennika nie moze byc ujemna (min:0)
  5. Snapshot w rezerwacji — przy tworzeniu rezerwacji cena jest "zamrazana" w reservationable_snapshot
  6. Dozwolone typy — cenniki moga byc tworzone tylko dla modeli Item i Activity
  7. Kasowanie kaskadowe — usuniecie klienta kasuje jego cenniki (onDelete: cascade)
  8. Zachowanie referencji — usuniecie cennika ustawia pricing_id w rezerwacji na NULL (onDelete: set null)

4.3 Klasy akcji (Action)

Controllery

Klasa Opis
IndexPricingController Pobiera liste cennikow z filtrami (Spatie QueryBuilder)
StorePricingController Tworzy nowy cennik (Pricing::create)

Atrybuty

Klasa Opis
GetValueGrossAttr Oblicza cene brutto: value * (1 + vatRate/100) lub value dla ZW/NP

Logika biznesowa (Other)

Klasa Opis
CreatingPricingObserver Hook creating: ustawia is_active = true domyslnie, dezaktywuje inne cenniki
UpdatingPricingObserver Hook updating: jesli is_active zmienia sie na true, dezaktywuje inne cenniki (wykluczajac biezacy)
DeactivateActivePricings Dezaktywuje aktywne cenniki dla tej samej kombinacji (priceable_type + priceable_id + client_id)
GetEffectivePricing Pobiera efektywny cennik: cennik kliencki > cennik domyslny > null
SetZeroForIsPaidDirtyField Tworzy cennik z wartoscia 0 gdy obiekt/aktywnosc staje sie bezplatny
TheLowestModelPricing Oblicza najnizsza cene domyslna z ostatnich 30 dni (dyrektywa Omnibus)

4.4 Observer modelu

Klasa: Domain\Pricing\Observer\PricingObserver

Rejestracja: Atrybut #[ObservedBy(PricingObserver::class)] na modelu Pricing

Hook Delegacja Logika
creating CreatingPricingObserver 1. Ustawia is_active = true jesli null. 2. Dezaktywuje inne aktywne cenniki (bez wykluczenia biezacego)
updating UpdatingPricingObserver Jesli is_active zmienia sie na true — dezaktywuje inne cenniki (wykluczajac biezacy)

Szczegoly dezaktywacji (DeactivateActivePricings):

Zapytanie:
  WHERE priceable_type = ? AND priceable_id = ?
  AND is_active = true
  AND (client_id = ? | client_id IS NULL)  -- w zaleznosci od cennika
  [AND id != ? -- jesli excludeCurrent = true]
SET is_active = false

5. Autoryzacja i uprawnienia

5.1 Middleware (routy)

Wszystkie endpointy cennikow wymagaja:

  • auth:api — uwierzytelnianie JWT
  • role:admin|supervisor|employee — dostep tylko dla personelu

5.2 Policy — PricingPolicy

Klasa bazowa: Support\Policy\BasePolicy

Metoda before(): Administratorzy (admin) maja pelny dostep do wszystkich operacji — policy nie jest dalej sprawdzane.

Metoda Supervisor Employee Warunek
view Tak Tak Uzytkownik nalezy do organizacji obiektu/aktywnosci
create Tak Warunkowo Supervisor: nalezy do organizacji. Employee: jest zarzadca obiektu (ItemManager)
update Tak Warunkowo Supervisor: nalezy do organizacji. Employee: jest zarzadca obiektu

Szczegoly metody create:

  1. Sprawdza czy obiekt (priceable) istnieje
  2. Pobiera organization_id z obiektu/aktywnosci
  3. Supervisor — sprawdza przynaleznosc do organizacji
  4. Employee — sprawdza czy jest ItemManager dla danego obiektu

Szczegoly metody update:

  1. Rozwiazuje organization_id przez relacje polimorficzna (priceable)
  2. Uzywa ->withoutGlobalScopes() aby ominac ewentualne filtry globalne
  3. Supervisor — sprawdza przynaleznosc do organizacji
  4. Employee — sprawdza isItemManager przez relacje polimorficzna

6. Stawki VAT

System obsluguje wszystkie polskie stawki VAT:

Stawka Kod Wartosc numeryczna Etykieta Przyklad uzycia
23% 23 23.00 "23%" Wynajem sal, sprzetu
8% 8 8.00 "8%" Uslugi sportowe
5% 5 5.00 "5%" Ksiazki, czasopisma
0% 0 0.00 "0%" Eksport uslug
ZW zw null "Zwolniony" Uslugi edukacyjne
NP np null "Nie podlega" Dotacje, darowizny

Enum: Domain\Pricing\Service\VatEnumService (backed string enum)

Metody statyczne:

Metoda Opis Zwraca
getNumericRate(?string) Zwraca wartosc liczbowa stawki float\|null
getLabel(string) Zwraca etykiete stawki string
getAllRates() Zwraca liste wszystkich kodow stawek string[]
isVatApplicable(string) Czy VAT jest naliczany (nie ZW/NP) bool

Obliczanie ceny brutto

Dla stawek numerycznych: brutto = netto x (1 + stawka/100)

Dla ZW i NP: brutto = netto (VAT nie jest naliczany)


7. Hierarchia cennikow

System stosuje nastepujaca hierarchie przy pobieraniu ceny:

flowchart TD
    A[Klient sklada rezerwacje] --> B{Ma cennik indywidualny?}
    B -->|Tak| C[Uzyj cennika klienta]
    B -->|Nie| D{Jest cennik domyslny?}
    D -->|Tak| E[Uzyj cennika domyslnego]
    D -->|Nie| F[Obiekt bezplatny]

Klasa: GetEffectivePricing

  1. Cennik kliencki — jesli klient ma przypisany aktywny cennik indywidualny, uzyj go
  2. Cennik domyslny — jesli nie ma cennika klienckiego, uzyj domyslnego (aktywnego, bez client_id)
  3. Brak cennika — zwraca null (obiekt bezplatny)

8. Jednostki cenowe

Typ price_unit price_unit_label Opis
Obiekt (Item) hour za godzine Stawka godzinowa
Aktywnosc (Activity) activity za zajecia Stawka za cale zajecia

Przyklady

  • Sala konferencyjna: 100 zl/godz. -> rezerwacja 2h = 200 zl netto
  • Zajecia jogi: 30 zl/zajecia -> rezerwacja = 30 zl netto

9. Dyrektywa Omnibus

System automatycznie sledzi najnizsza cene z ostatnich 30 dni:

Klasa: TheLowestModelPricing

Enum: PricingEnumService::OMNIBUS_DAYS = '30'

Logika:

SELECT MIN(value) FROM pricings
WHERE priceable_type = ? AND priceable_id = ?
AND client_id IS NULL
AND created_at >= NOW() - 30 DAYS
timeline
    title Historia cen obiektu
    1 lutego : 100 zl
    10 lutego : 90 zl (promocja)
    20 lutego : 110 zl
    Dzis : Najnizsza cena 30 dni = 90 zl

Tylko cenniki domyslne

Obliczanie najnizszej ceny dotyczy wylacznie cennikow domyslnych (client_id IS NULL). Cenniki indywidualne nie sa brane pod uwage.


10. Snapshot cennika w rezerwacji

Przy tworzeniu rezerwacji system zapisuje pelny snapshot cennika w polu reservationable_snapshot['_pricing_snapshot']. Dzieki temu:

  • Usuniecie cennika nie powoduje utraty danych rezerwacji
  • Zmiana ceny nie wplywa na istniejace rezerwacje
  • Audyt — zawsze wiadomo jaka byla cena jednostkowa w momencie rezerwacji

Zapisywane dane (w _pricing_snapshot)

Pole Opis
id UUID cennika
value Cena netto jednostkowa
value_gross Cena brutto jednostkowa
vat_rate Efektywna stawka VAT
vat_rate_override Nadpisanie stawki VAT (jesli bylo)
is_client_pricing true = cennik indywidualny
client_id UUID klienta (dla cennika indywidualnego)
price_unit hour lub activity
price_unit_label "za godzine" lub "za zajecia"

Zgodnosc FK

Kolumna pricing_id w rezerwacji ma onDelete('set null'), wiec po usunieciu cennika wartosc staje sie NULL. Dzieki _pricing_snapshot w reservationable_snapshot dane sa nadal dostepne.


11. API Resource — struktura odpowiedzi

Klasa: Domain\Pricing\Resource\PricingResource

Relacje ladowane: priceable, client

Pole JSON Typ Zrodlo
id string $this->id
priceable_type string $this->priceable_type
priceable_id string $this->priceable_id
value float $this->value (cena netto)
value_gross float $this->value_gross (accessor — cena brutto)
client_id string\|null $this->client_id
vat_rate_override string\|null $this->vat_rate_override
effective_vat_rate string $this->effective_vat_rate (accessor)
effective_vat_rate_label string $this->effective_vat_rate_label (accessor)
is_active bool $this->is_active
is_default bool $this->is_default_pricing (accessor)
price_unit string $this->price_unit (accessor)
price_unit_label string $this->price_unit_label (accessor)
created_at string\|null Format: Y-m-d H:i:s
updated_at string\|null Format: Y-m-d H:i:s
can object Uprawnienia uzytkownika (view, create, update)
priceable object\|null Relacja — dane obiektu/aktywnosci
client object\|null Relacja — dane klienta

Pole can niedostepne publicznie

Dla uzytkownikow nieuwierzytelnionych pole can jest usuwane z odpowiedzi (UNALLOWED_NO_AUTH_KEYS).


12. Enumy

PricingEnumService

Klasa: Domain\Pricing\Service\PricingEnumService (backed string enum)

Case Wartosc Opis
OMNIBUS_DAYS '30' Liczba dni dla obliczania najnizszej ceny (Omnibus)
ALLOWED_PRICEABLE_TYPE_ITEM Domain\Item\Model\Item (FQCN) Dozwolony typ: Obiekt
ALLOWED_PRICEABLE_TYPE_ACTIVITY Domain\Activity\Model\Activity (FQCN) Dozwolony typ: Aktywnosc

Metoda statyczna: getAllowedPriceableTypes() — zwraca tablice dozwolonych FQCN.

VatEnumService

Opisany w sekcji 6. Stawki VAT.


13. Powiazania z innymi domenami

Diagram powizan

graph LR
    Pricing -->|morphTo| Item["Zasoby (Item)"]
    Pricing -->|morphTo| Activity["Aktywnosci (Activity)"]
    Pricing -->|belongsTo| Client["Klienci (Client)"]
    Reservation["Rezerwacje"] -->|pricing_id FK| Pricing
    Item -->|morphMany| Pricing
    Activity -->|morphMany| Pricing
    Client -->|hasMany| Pricing

Tabela powizan

Domena Typ powiazania Opis
Zasoby (Item) Item.pricings()MorphMany Cenniki godzinowe dla obiektow. Item ma atrybuty current_pricing i lowest_pricing
Aktywnosci (Activity) Activity.pricings()MorphMany Cenniki za zajecia. Activity ma atrybuty current_pricing i lowest_pricing
Klienci (Client) Client.pricings()HasMany Cenniki indywidualne dla klientow. Kasowanie klienta kasuje jego cenniki
Rezerwacje (Reservation) Reservation.pricing_id — FK Cena rezerwacji obliczana z cennika; snapshot cennika zapisywany w reservationable_snapshot

Wykorzystanie przez inne domeny

Klasa Domena Uzywa Opis
GetCurrentPricingAttr Item, Activity Pricing model Pobiera aktywny cennik domyslny
GetLowestPricingAttr Item, Activity Pricing model Pobiera najnizsza cene z 30 dni
GetReservationPricing Reservation GetEffectivePricing Pobiera cennik dla rezerwacji (kliencki lub domyslny)
GenerateReservationItemTotalPrice Reservation Pricing model Oblicza calkowita cene rezerwacji
BuildReservationSnapshots Reservation Pricing model Tworzy snapshot cennika w rezerwacji
SlotCreator Reservation GetReservationPricing Oblicza cene slotow rezerwacji
CreateItem Item pricings()->create() Tworzy cennik przy tworzeniu obiektu
CreateActivity Activity pricings()->create() Tworzy cennik przy tworzeniu aktywnosci

14. Konfiguracja

Tworzenie cennika

Pole Opis Wymagane
Obiekt/Aktywnosc Do czego przypisany cennik Tak
Cena netto Kwota w zlotych Tak
Stawka VAT Jedna z 6 dostepnych Tak
Klient Dla cennika indywidualnego Nie
Aktywny Czy cennik jest uzywany Nie (domyslnie true)

Zasady aktywacji

Tylko jeden aktywny cennik

Dla kazdej kombinacji (obiekt/aktywnosc + klient) moze byc tylko jeden aktywny cennik.

Gdy aktywujesz nowy cennik, poprzedni zostaje automatycznie dezaktywowany.

Publiczny cennik

Obiekty i aktywnosci maja pole is_public_price_list (boolean). Gdy wlaczone, cennik jest widoczny dla niezalogowanych uzytkownikow.


15. Znane ograniczenia i TODO

Ograniczenie Opis
Brak endpointu DELETE Nie ma mozliwosci calkowitego usuniecia cennika przez API — mozna go tylko dezaktywowac
Brak endpointu UPDATE Nie ma mozliwosci edycji istniejacego cennika — trzeba utworzyc nowy
Brak walidacji duplikatow System pozwala na tworzenie wielu cennikow o tej samej wartosci dla tej samej kombinacji
Brak audytu Model Pricing nie korzysta ze Spatie Activity Log

Wartosc biznesowa

Argumenty dla decydentow

  1. Zgodnosc z przepisami VAT — automatyczne obliczenia, rozne stawki
  2. Elastycznosc cenowa — rabaty dla stalych klientow bez recznych korekt
  3. Przejrzystosc — jedna aktywna cena, brak pomylek
  4. Zgodnosc z dyrektywa Omnibus — najnizsza cena z 30 dni

Przykladowe metryki

Metryka Wartosc
Obslugiwane stawki VAT 6
Cennikow na obiekt Bez limitu
Okres Omnibus 30 dni