- Transakcyjność D2D: 3MD - # RC+ czyli CrossSellopodobne dodatki do rezerwacji (zwane roboczo dalej CrossSellPlus) ## Co to ma być? R+ - dodatek (w stylu upselli) do rezerwacji D2D (tylko do takiej rezerwacji. Krzysiu popraw mnie jeśli się mylę). ## TODOs RC+ - modele i relacje - ReservableExtra + STI - ^ - obsługa obrazków - ReservationReservableExtra - menu do ReservationReservableExtras - tagi do menu / Menuable :-) - Rule - serwisy - Wyliczanie możliwości dodania RC+'a' z Ruli (RC+ Rule Resolver czy coś) - Rekalkulacja kwoty rezerwacji z uwzględnieniem RC+ - końcówki (klient) - Q: getReservationPossibilities(reservationID!, date!, approxStartHour!, numPeople!, definitiveStartHour, reservationExtras: [{id: 1, quantity: 5}]) ReservationAttempt { reservationPossible: bool (definitiveStartHour?) hours : [{ hour: "HH:MM", available: bool }] availableReservationExtras: [ - id - pic_url - title - desc: text - price: decimal ] - Q: reservableExtras(+filtry) (użyte do litingu doświadczeń) - Q: reservableExtra (szczegóły RC+ z menu) - M: createReservation oraz updateReservation(z RC+ami) - końcówki (admin) - CRUD R+ (typ, menus+tagi, opis,temat,zdjęcia,...) na poziomie restauracji - CRUD Ruli do R+ - dodanie RRE do typu rezerwacji ## Dostępność dodatków Jego dostępność może być ograniczona kalendarzem (jeśli nie ma żadnych ruli to jest dostępny we wszystkich stolikach, jeśli ma swoje rule to są ważniejsze), posiada minimalna długość slotu która "rozpycha" rezerwację D2D - o ile jest miejsce w kalendarzu D2D. 1) ograniczona rulesami 2) lub jeśli nie ma ruli - nieograniczona (poprawcie jeśli się mylę)) 3) plany śledzenia stanu magazynowego zarzucono (poprawcie jeśli się mylę) > :cherries: Minimalna długość slotu nie jest cechą RC+ rula, ale samego RC+. Oznacza spodziewaną prędkość przeżuwania :-) Nazwijmy to tymczasowo `eating_duration` (w minutach, żeby pasowało do slotów). :cherries: no chyba, że ustalimy, że eating_duration jest cechą dania i ~~jest wyliczane z dań jakie znajdą się w RC+ie~~, ale to by pewnie komplikowało rezerwacje i "wydłużanie slotu", bo trzeba by to gdzieś keszować, bo zestaw dań w określonym RC+ie może zmieniać się w czasie. > **nic nie wyliczamy, duration jest jeden na poziomie RC+ i tyle** > [name=Janek][color=green] ### rozpychanie czasu rezerwacji RC+ :cherries::cherries::cherries::cherries: załóżmy że ktoś rezerwuje D2D na 90 min i dodaję RC+ o nazwie "Tuzin Burgerów (Sharing)". Tak się składa, że jest wyceniony na 120 min. System powinien rozszerzyć rezerwację o różnicę 120-90 min, czyli o 30 min (90 + 30) > :cherries: Na start w wersji v0 możemy przyjąć że każdy R+ będzie się mieścił w defaultowym slocie. Przygotować się na to na przyszłość. > [name=Paweł][color=red] ## Oczekiwane typy "dodatków": - degustacja - zbudowana z dań, ma jedno menu (X dań w ramach menu) :cherries: Od tego zaczniemy. Reszta ma niższe prio. - danie flagowe - raczej jedno danie (może więcej?), opis, cena - shareing - na ile to jest osób, cena, dla ilu osób (+ od ilu osób go pokazujemy - żarłoki) - menu lunchowe > :cherries: Jak dla mnie z tego wynika że potrzebujemy dodać encję `Dish`, Danie, czy cokolwiek. > Degustacja has many Dania i DanieFlagowe has_one Danie :-) > Sharing być może też has_one Danie > i Menu Lunchowe pewnie has_many Dania > [name=Janek][color=green] > Zdaje się że dania muszą należeć do restauracji - każda ma inne... > [name=Krzysiek][color=green] dania muszą posiadać tagi składników (ryba, mięso, krewetki) Dochodzi cały moduł transakcyjności w D2D / anulacji i zwrotów (do ustalenia na jakich warunkach) > :cherries: Jak dla mnie z tego wynika że potrzebujemy STI > [name=Janek][color=green] > :cherries: Zastanawiam się czy czyściej / wygodniej nie było by tagować całego R+ a nie dań. To ma służyć do szukania R+ które zawierają dane skłądniki w całym zestawie. Nie widzę w tej chwili zysku nad tagowaniem poszczególnych dań - a tylko utrudnienie w dodawaniu nowy R+ gdzie przy 7-daniowym R+ trzeba będzie otagować aż 7 dań - gdzie składniki mogą się powtarzać > [name=Paweł][color=red] ```ruby CrossSellPlus self.abstract_class = true has_many :cross_sell_plus_rules has_many :dishes # lub has_one :dish belongs_to :reservation # must be Daily has_many :dish_tags, through: :dishes, source :tag end ``` ```plantuml @startuml skinparam stereotypeCBackgroundColor<<Done>> Green class ReservableExtra <<Done>>{ + name + pictureUrls + type: string // STI sub class + restaurant <---- + eating_duration: int // minutes + rules[] + price: decimal + show_as_upsell: bool //TBC urżnąć } class Reservation {} note top of ReservationCrossSellPlus #0F0: zakodzone class ReservationCrossSellPlus { + reservation_id + cross_sell_plus_id } class Dish <<Done>> { + name + description + tags[] } note top of Dish #0F0: zakodzone class DishTag { + name } class ReservableExtraRule { + reservable_extra } note top of ReservableExtra : STI Ober-Class Dish ||--|{ DishTag Restaurant <|-- ReservableExtra ReservableExtra ||--|{ ReservableExtraRule : RC+ has many rules ReservableExtra }|--|{ Dish : HABTM Reservation }|--|| ReservationCrossSellPlus ReservableExtra }|--|| ReservationCrossSellPlus package ReservableExtras <<Node>> { .ReservableExtra <|-- Degustation .ReservableExtra <|-- FlagshipDish .ReservableExtra <|-- ShareableDish : STI subclasses .ReservableExtra <|-- LunchMenu } @enduml ``` ### Jak mogłaby wyglądać Rula, żeby nie było wielu zagnieżdżonych modeli Rule->WeekDay->HourRange (która to cecha mnie szczególnie wk...) ```plantuml @startuml class ReservableExtraRule { + cross_sell_plus -> FK + dows:char[7] + active:bool + starts_at:int + ends_at:int + date_from:date_with_zone + date_to:date_with_zone } @enduml ``` - char(7) na oznaczenie dni tygodnia np. '1110111' (wszystko oprócz czwartków), albo nawet to samo jako char(1) konwertowany na array bitów (mniej czytelne potem co prawda - date_from i date_to mogłyby być nullable i wtedy rozumiemy, że rule trwa w nieskończoność (jeśli enabled) A najlepiej wywalić daty w cholerę dopóki biznes tego nie zażąda. (niech operują enabled/disabled). Taniej będzie się to liczyło. > :cherries: No nie wiem. Ogarniczenia R+ mają być tez po to żeby go np ogarniczyć w trakcie trwania festiwalu. Wynika z tego że daty by się "przydały" bo inaczej musisz wyłączyć ograniczyć R+ i potem pamiętać zeby to cofnąć > [name=Paweł][color=red] ## Brudnopis #ignore #### O typach binarnych które pomogą z dows https://www.postgresql.org/docs/9.0/datatype-binary.html PG::TextDecoder::Bytea PG::Connection.unescape_bytea(raw) escape_bytea https://apidock.com/rails/v5.0.0.1/ActiveRecord/ConnectionAdapters/PostgreSQL/OID/Bytea/deserialize https://stackoverflow.com/questions/53808048/postgres-sql-read-binary-value-from-string-field ReservationExtras postgres bit mask ## Końcówki dodać obrazek do RC+ - listing doświadczeń (RC+) per region globalny per restauracja czyli jeden endpoint filtrowanie: region restauracja typ paginacja (zwracać connection) Mutacja: dodaj doświadczenie do Rezerwacji ReservationAttempt - reservation - permitted ReservationReservableExtras (RC+'s) query: rc+ details query: getReservationPossibilities( date!, approxStartHour!, numPeople!, definitiveStartHour, reservationExtrasIds) returns: ReservationAttempt: reservationPossible: bool (definitiveStartHour?) hours : [{ hour: "HH:MM", available: bool }] availableReservationExtras: [ - id - pic_url - title - desc: text - price: decimal ] ## Spotkanie 10 lutego - ustalenia - tagujemy R+y, nie Dania - rezygnujemy na razie z "rozpychania" slotów - rezygnujemy z Dish i modelujemy to jak Menu Festivalowe 1 R+ ma jedno menu, i to menu ma swoje tagi. A R+ sam z siebie nie ma tagów MenusTags Muszą być rule - dać ilość sztuk/miejsc