dimesum

Strona główna / Blog / Pieniądze

Pieniądze

Jak sprawiedliwie podzielić rachunek w restauracji

· 8 min czytania ·

Podziel kolację za 2100 zł po równo, a jedna osoba po cichu płaci 280 zł za danie, którego nawet nie tknęła; rozwiązaniem jest jeden wydatek z dwiema regułami: wskaż, kto zjadł niewspółdzieloną pozycję, i pozwól, by podatek szedł za konsumpcją.

Podziel rachunek za kolację na 2100 zł po równo, a jedna osoba nadpłaci 280 zł. Dwie z trzech osób zjadły półmisek z owocami morza za 800 zł, a trzecia nie, jednak równy podział obciąża każdą z nich kwotą 700 zł. Dimesum traktuje ten rachunek jako jeden wydatek: równo na górnym poziomie, a pozycję za 800 zł ponoszą tylko te dwie osoby, które ją zamówiły.

Rachunki w większości dzielone po równo, z jedną niewspółdzieloną pozycją, to najczęstsze zadanie stawiane aplikacji do dzielenia kosztów, a pierwszy model danych Dimesum nie potrafił takiego opisać. Wcześniejszy projekt czynił z ITEMIZED osobny typ podziału, wykluczający się wzajemnie z EQUAL, PERCENT i SHARES. Prawdziwy rachunek z restauracji jest jednym i drugim naraz.

Rozpisanie na pozycje to szczegół wydatku, a nie inny rodzaj podziału

Wydatek rozpisany na pozycje w Dimesum to zwykły wydatek, który po prostu niesie ze sobą swoje pozycje. Wydatek zachowuje wszystko, co wydatki mają już wcześniej: sumę, uczestników, typ podziału, jednego lub kilku płatników. Do tego dodaje pozycje, czyli wiersze rachunku, oraz korekty, czyli podatek, napiwek, opłaty i rabaty wydrukowane pod nimi.

O każdym groszu decydują następnie dwa poziomy. Typ podziału wydatku dzieli każdą pozycję, przy której nikogo nie wskazano. Pozycję z przypisanymi osobami ponoszą dokładnie te osoby i nikt inny.

Dwa poziomy, które decydują o podziale pozycji, według docs/tech/18-itemized-expenses.md §1.
PoziomCo decydujeDotyczy
Typ podziału wydatkuJak dzieli się wspólny koszt: po równo, procentowo lub według ważonych udziałówKażda pozycja bez wskazanych osób
Osoby przypisane do pozycjiKto skonsumował tę pozycję i w jakiej proporcjiTylko ta pozycja
Pozycja bez przypisanych osób dzieli się według typu podziału wydatku; pozycję z przypisanymi osobami ponoszą tylko wskazane osoby POZIOM 1: NIKOGO NIE WSKAZANO PRZY POZYCJI Wspólne dania 1200 zł brak przypisanych osób EQUAL na 3 Asha 400 zł Bhavna 400 zł Chetan 400 zł POZIOM 2: POZYCJA WSKAZUJE, KTO JĄ ZJADŁ Danie niewegetariańskie 800 zł przypisani: Asha, Bhavna jej 2 przypisane osoby Asha 400 zł Bhavna 400 zł Chetan 0 zł
Dwa poziomy na jedzeniu za 2000 zł. Wspólne dania nie wskazują nikogo, więc EQUAL dzieli je na trzy części; danie z owocami morza wskazuje dwie osoby, więc suma częściowa jedzenia Chetana zatrzymuje się na 400 zł.

Kolacja za 2100 zł, na której osoba, która zjadła najmniej, płaci 420 zł

Asha, Bhavna i Chetan jedzą kolację, dzieloną po równo na górnym poziomie. Wspólne dania wychodzą na 1200 zł. Danie z owocami morza wychodzi na 800 zł i zjedli je tylko Asha i Bhavna. Obsługa wynosi 5%, a Chetan zapłacił całe 2100 zł.

Przykład z obliczeniami: jeden rachunek, dwie pozycje, jedna korekta i udział, który ponosi każda osoba.
PozycjaKwotaAshaBhavnaChetan
Wspólne dania, brak przypisanych osób1200 zł400 zł400 zł400 zł
Półmisek z owocami morza, Asha i Bhavna800 zł400 zł400 zł0 zł
Suma częściowa2000 zł800 zł800 zł400 zł
Obsługa 5%, według sumy częściowej100 zł40 zł40 zł20 zł
Razem2100 zł840 zł840 zł420 zł

Chetan zapłacił 2100 zł, a jest winien 420 zł, więc należy mu się 1680 zł: 840 zł od Ashy i 840 zł od Bhavny. To, kto zapłacił, jest niezależne od tego, kto jest winien. Fakt, że płatnikiem jest osoba, która ledwie jadła, nie zmienia żadnego z udziałów, dlatego Dimesum trzyma płatników na poziomie wydatku, a osoby przypisane na poziomie pozycji.

Podatek idzie za tym, co zjadłeś, a nie za tym, ile was jest

Udział Chetana w opłacie za obsługę wynoszącej 100 zł to 20 zł, a nie 33,33 zł. Każda korekta rozkłada się proporcjonalnie do sumy częściowej pozycji danej osoby, więc podział jedzenia w proporcji 800:800:400 decyduje też o podziale opłaty za obsługę. Rozłożenie według liczby osób po cichu obciążyłoby Chetana podatkiem od dania, którego nawet nie tknął.

Ktoś, kto nic nie zamówił, nie płaci więc żadnego podatku i nie dostaje żadnego rabatu. Wagami są sumy częściowe sprzed korekt, a nie suma bieżąca, co powstrzymuje też zaokrąglenie każdej korekty przed kumulowaniem się w wagach następnej.

Korekty stosuje się po kolei, więc rabat przesuwa podstawę GST

Rachunek o treści "4000 zł, minus 10%, plus 5% GST" nalicza GST od 3600 zł, a pozycja GST wynosi 180 zł. Odwróć kolejność tych dwóch, a GST naliczany jest od 4000 zł, co daje 200 zł. Korekty to lista uporządkowana, a procent stosuje się do sumy bieżącej na swojej własnej pozycji. Obie kolejności to prawdziwe rachunki, więc ta lista jest uporządkowana, a nie zbiorem.

Ten sam rabat i GST w dwóch kolejnościach, z podstawą, od której nalicza się każdy, oraz sumą, którą każdy daje Najpierw rabat Najpierw GST Suma częściowa pozycji 4000 zł minus 10% z 4000 zł rabat 400 zł 3600 zł plus 5% GST od 3600 zł GST 180 zł 3780 zł Suma rachunku 3780 zł Suma częściowa pozycji 4000 zł plus 5% GST od 4000 zł GST 200 zł 4200 zł minus 10% z 4200 zł rabat 420 zł 3780 zł Suma rachunku 3780 zł TEN SAM RACHUNEK, STAŁE 400 ZŁ ZAMIAST 10% 400 zł taniej, potem GST 3780 zł GST, potem 400 zł taniej 3800 zł
Oba procenty lądują na tych samych 3780 zł, bo mnożenie jest przemienne, jednak pozycja GST się różni: 180 zł wobec 200 zł. Zamień procentowy rabat na stałe 400 zł, a sumy też się rozejdą, 3780 zł wobec 3800 zł. Kolejność jest tu arytmetyką, a nie prezentacją.
Dlaczego kolejność jest zapisywana wprost

Każda korekta niesie własną position. Kolejność oparta na porządku wstawiania albo na tym, że generator identyfikatorów pozostaje monotoniczny, po cichu zmieniłaby to, co każdy jest winien, po odtworzeniu bazy danych.

Między literówką a arytmetyką stają trzy walidacje. Pula podaje albo kwotę stałą, albo stawkę w punktach bazowych, nigdy obie, bo przechowywanie obu przechowuje liczbę i jej własne wyprowadzenie. Kwota ujemna jest odrzucana, a błąd wskazuje DISCOUNT jako sposób na zapisanie obniżki. Stawka powyżej 100 000 punktów bazowych też jest odrzucana, przy limicie ustawionym daleko powyżej 10 000 punktów bazowych oznaczających 100%, bo sto procent rabatu to prawdziwy rabat.

Cztery rodzaje korekt w internal/platform/splitcalc i to, co każdy robi z sumą bieżącą.
RodzajWpływ na sumę bieżącąDlaczego jest osobnym rodzajem
TAXDodajeTylko nazewnictwo; identyczne w obliczeniach
TIPDodajeTylko nazewnictwo; identyczne w obliczeniach
FEEDodajeTylko nazewnictwo; identyczne w obliczeniach
DISCOUNTOdejmujeJedyny rodzaj, który zmienia arytmetykę, więc kierunek wynika z rodzaju, a nigdy ze znaku

Suma pochodzi z pozycji, a wpisana suma jest tylko sumą kontrolną

Suma pozycji jest wyprowadzana: suma pozycji plus suma korekt. Wiersze już mówią, ile kosztuje rachunek, więc osobno podana suma byłaby drugim źródłem prawdy, które może się nie zgadzać z pierwszym. Ktoś, kto błędnie wprowadzi rachunek, poprawia wiersz, czyli miejsce, w którym naprawdę jest błąd, a suma podąża za tym. Poprawianie rachunku, który jest już zaksięgowany, przechodzi przez edycję, która na nowo określa jego podział, więc poprawka ląduje jako nowa wersja, a nie nadpisanie.

Klient nadal może przesłać amount_minor, a Dimesum traktuje to wtedy jako sumę kontrolną, a nie jako odpowiedź. Zgodność oznacza, że klient odczytał ten sam rachunek. Niezgodność zatrzymuje wydatek, zanim jakiekolwiek pieniądze się przesuną.

Wcześniejsza wersja automatycznie dodawała pozycję "Inne" dla wszystkiego, czego podana suma nie uwzględniała, i usuwała tę pozycję, gdy różnica się domykała. Ta pozycja działała, i już jej nie ma. Wyprowadzanie sumy rozpuściło problem, do którego zarządzania istniała pozycja "Inne", a który brał się tylko stąd, że suma była podawana dwukrotnie.

Dlaczego EXACT i pozycje są odrzucane razem

EXACT podaje końcową kwotę każdego uczestnika. Pozycje wyprowadzają kwotę każdego uczestnika. Oba naraz są nadokreślone: albo się zgadzają, i wtedy jedno jest zbędne, albo się nie zgadzają, i wtedy wydatek ma dwie odpowiedzi, a żadna reguła nie mówi, która wygrywa. Dimesum odrzuca to połączenie już na wejściu, zamiast rozstrzygać je regułą pierwszeństwa, której nikt by nie zapamiętał.

EQUAL, PERCENT i SHARES łączą się z pozycjami, bo każde z nich jest regułą dzielenia wspólnego kosztu, a nie zestawem końcowych kwot.

Gdzie rabat kiedyś gubił grosz

Każde rozłożenie korzysta z metody największej reszty, i każde zachowuje swoją własną sumę dokładnie. Remisy w tej metodzie trafiały kiedyś do najniższego identyfikatora uczestnika, co wręczało najstarszemu członkowi grupy dodatkowy grosz przy każdym wydatku dzielonym po równo; teraz remis rotuje na haszu identyfikatora wydatku. Wspólne pozycje są łączone w pulę i dzielone raz, a nie wiersz po wierszu, więc nieparzysty grosz nie ląduje u tego samego uczestnika przy każdym wierszu rachunku.

Nasza funkcja apportion miała tu prawdziwą wadę. Dzielenie całkowite w Go obcina w stronę zera, więc suma ujemna była zaokrąglana w złą stronę i reszta nigdy nie była rozdawana: −40,00 zł przy wagach 100, 200 i 300 wracało jako −39,99 zł. Zniknięty grosz sprawiłby, że poprawnie zrabatowany rachunek nie przeszedłby własnego sprawdzenia sumy, a użytkownikowi powiedziano by, że jego arytmetyka jest błędna. Sumy ujemne są teraz rozkładane według wartości bezwzględnej i z powrotem negowane.

Wprowadź rachunek tak, jak jest wydrukowany

Wpisz pozycje, które widzisz, wskaż osoby, które zjadły te niewspółdzielone, i dodaj podatek, napiwek, opłatę i rabat w kolejności, w jakiej drukuje je paragon. Dimesum wyprowadza sumę, rozkłada każdą korektę według tego, co skonsumowała każda osoba, i pomija płatnika. Następnym razem, gdy jedno danie kosztuje dwa razy tyle, co zamówił każdy inny, dodaj je jako osobną pozycję z dwoma nazwiskami.

Często zadawane pytania

Jak podzielić rachunek w restauracji, gdy jedna osoba zamówiła coś drogiego?

Umieść to danie w osobnej pozycji i wskaż osoby, które je zjadły. W Dimesum reszta rachunku nadal dzieli się według własnej reguły wydatku, zwykle po równo, a wskazaną pozycję ponoszą tylko przypisane do niej osoby. Podatek i obsługa rozkładają się następnie według sumy częściowej każdej osoby, więc kto pominął to danie, płaci mniej jednego i drugiego.

Czy podatek i napiwek dzielić po równo, czy według tego, co każdy zamówił?

Według tego, co każdy zamówił. Dimesum rozkłada każdą korektę proporcjonalnie do sumy częściowej pozycji danej osoby, a nie według liczby osób. Na kolacji za 2100 zł, na której jedna osoba zjadła jedzenie za 400 zł, ta osoba ponosi 20 zł ze 100 zł opłaty za obsługę zamiast 33,33 zł. Kto nic nie zamówił, nie płaci żadnego podatku.

Czy kolejność rabatu i podatku zmienia to, ile kosztuje rachunek?

Tak. Korekty stosuje się po kolei wobec sumy bieżącej, więc rachunek o treści "4000 zł, minus 10%, plus 5% GST" nalicza GST od 3600 zł, a pozycja GST wynosi 180 zł. Ustaw GST jako pierwsze, a naliczy się od 4000 zł, co daje 200 zł. Przy stałym rabacie 400 zł sumy też się różnią, 3780 zł wobec 3800 zł.

Dlaczego nie można użyć dokładnych kwot na rachunku rozpisanym na pozycje?

EXACT podaje końcową kwotę każdej osoby, a pozycje ją wyprowadzają, więc oba naraz dają jednemu wydatkowi dwie odpowiedzi. Dimesum odrzuca to połączenie, zamiast wybierać zwycięzcę regułą pierwszeństwa, której nikt by nie zapamiętał. EQUAL, PERCENT i SHARES działają obok pozycji, bo każde z nich jest regułą dzielenia wspólnych pozycji, a nie zestawem końcowych kwot.

Czy trzeba wpisywać sumę rachunku rozpisanego na pozycje?

Nie. Dimesum wyprowadza sumę rozpisaną na pozycje jako sumę pozycji plus sumę korekt, bo wiersze już mówią, ile kosztuje rachunek. Suma przesłana przez klienta jest sprawdzana jako suma kontrolna, a niezgodność zatrzymuje wydatek, zanim pieniądze się przesuną. Poprawienie błędnej liczby oznacza poprawienie wiersza, z którego pochodzi.