Strona główna / Blog / Pieniądze
PieniądzeEdycja wydatku musi na nowo określić podział
Domyślne wartości przy edycji to błędy w rozliczeniach, dlatego Dimesum wymaga pól participants i split_type w każdym żądaniu PATCH wydatku, obok base_version, które odrzuca nieaktualną edycję zamiast ją scalać.
Poprawienie literówki nie powinno zmieniać tego, kto komu jest winien pieniądze. W Dimesum edycja wspólnego wydatku na nowo określa cały podział. Pola participants i split_type są wymagane w każdym żądaniu PATCH, a edycja, która pomija którekolwiek z nich, wraca z kodem 400, zamiast uzupełniać wartość domyślną. Domyślne wartości przy tworzeniu to wszyscy obecni członkowie i równy podział, co przy edycji staje się błędem w rozliczeniach.
Dwie usterki pokazują to konkretnie. Współlokator, który dołączył w sierpniu, zostaje dopisany do lipcowej kolacji, ponieważ zwrot „wszyscy obecni członkowie" jest liczony w chwili zapisania edycji, a nie w chwili utworzenia wydatku. Celowy podział czynszu 70/30 spłaszcza się do 50/50, ponieważ brak pola split_type oznacza EQUAL. Żadna z tych usterek nie zgłasza błędu, a obie przesuwają prawdziwe pieniądze.
Domyślne wartości przy edycji to błędy w rozliczeniach. Wartość domyślna z chwili tworzenia zgaduje na temat grupy, którą autor widzi w tym momencie. Edycja przychodzi później, wobec grupy, która się zmieniła, i to samo zgadywanie po cichu zmienia to, ile kto jest winien.
Wartości domyślne przy tworzeniu opisują nowy wydatek, nie stary
W chwili tworzenia wartości domyślne są uczciwe. Autor patrzy na grupę w jej obecnym kształcie, a równy podział na wszystkich jest częstym przypadkiem, więc Dimesum uzupełnia oba pola. Wydatek zapisuje swoje dane wejściowe, a nie tylko wyniki: pola splits.percent_bp, splits.weight i splits.exact_minor zachowują to, co wpisał użytkownik, dzięki czemu późniejsza edycja może je otworzyć na nowo.
Edycja to inna czynność. Ten sam wydatek można poprawić kilka tygodni później, gdy dołączy nowy współlokator albo ktoś przejmie konto widmo. Skład grupy się zmienia, a podział nie. Ponowne użycie domyślnych wartości z chwili tworzenia każe dzisiejszej grupie odpowiadać na pytanie, na które stary wydatek już odpowiedział.
Odmowa zgadywania nie jest tu niczym nowym. Wydatek z wieloma płatnikami również musi na nowo określić swoich płatników. soleStoredPayer używa ponownie zapisanego płatnika tylko wtedy, gdy wydatek ma dokładnie jednego, więc edycja, która milczy o dwóch płatnikach, jest odrzucana, zamiast przypisywać ich na nowo. Edycja, która nic nie mówi o płatnikach, zachowuje własnego płatnika wydatku, nigdy osoby dokonującej edycji.
API odrzuca edycję, która nie określa na nowo swojego podziału
Sprawdzenie w bramie odbywa się, zanim policzone zostaną jakiekolwiek pieniądze. Gdy pole participants jest puste lub split_type jest niewypełnione, żądanie wraca z kodem 400, kodem invalid_expense i komunikatem „an edit must restate the split: participants and split_type are required". Usługa wydatków powtarza tę regułę w validateAmend, więc wywołujący, który dotrze do usługi inną drogą, spotyka tę samą odmowę.
| Pole | Przy tworzeniu | Przy edycji | Ile kosztowałaby wartość domyślna |
|---|---|---|---|
participants | Opcjonalne. Domyślnie wszyscy obecni członkowie | Wymagane | Członek, który dołączył później, trafia do starego wydatku |
split_type | Opcjonalne. Domyślnie EQUAL | Wymagane | Podział 70/30 spłaszcza się do 50/50 |
payers | Opcjonalne. Domyślnie autor | Pominięcie zachowuje jedynego płatnika wydatku; dwóch płatników trzeba określić na nowo | Edytujący staje się płatnikiem, odwracając to, kto komu jest winien |
base_version | Nie jest wysyłane | Wymagane i musi być równe bieżącej wersji | Nieaktualna edycja nadpisuje zmianę, której jej autor nigdy nie przeczytał |
revision_id | UUIDv7 od klienta, klucz idempotentności | To samo, jeden na wersję | Ponowiona edycja obciąża grupę dwa razy |
currency | Podawana dla każdego wydatku | Musi się zgadzać; zmiana jest odrzucana | Wiersz salda przechowuje jedną walutę na członka |
Waluta należy do tej samej rodziny odmów. Edycja nie może zmienić waluty wydatku, ponieważ wiersz salda przechowuje jedną walutę na członka. Strona zapisu odrzuca zmianę, a księga tylko do dopisywania odkłada taką poprawkę na bok, gdyby kiedykolwiek do niej dotarła. Odmowa już przy wejściu sprawia, że obie połowy się nie rozjeżdżają.
Nieaktualna edycja jest odrzucana do jej autora, nigdy scalana
base_version to druga połowa kontraktu. Każdy PATCH niesie wersję, którą przeczytał jego autor, a checkTransition porównuje ją z wierszem, który transakcja właśnie zablokowała. Gdy są równe, edycja stosuje się na wersji o jeden wyższej. Gdy się różnią, wywołujący otrzymuje HTTP 409 z kodem stale_version.
Scalanie to kusząca alternatywa i jest błędne. Dwie edycje jednego wydatku to dwa kompletne stwierdzenia tego, co oznacza rachunek. Ich scalenie tworzy trzecie stwierdzenie, którego nikt nie napisał, z udziałami, których żaden z autorów by nie rozpoznał. Odrzucenie oddaje konflikt z powrotem jednej osobie, która potrafi go rozwiązać.
Idempotentność i współbieżność są rozdzielone celowo. Wstawienie rewizji odbywa się przed sprawdzeniem wersji, ponieważ ponowiona edycja niesie wersję bazową, którą pierwotnie przeczytała, a ta jest już nieaktualna. Powtórzenie musi zostać odczytane jako powtórzenie, a nie jako konflikt, więc revision_id odpowiada jako pierwsze i zwraca zapisany wynik.
Odpowiedź już niesie to, czego potrzebuje następna edycja
Wymaganie większej liczby pól w żądaniu PATCH jest uczciwe tylko wtedy, gdy klient może je zdobyć tanio. Każda odpowiedź dotycząca wydatku niesie version, więc klient, który właśnie zapisał wydatek, może go edytować bez drugiego odczytu. Odpowiedź tworzenia, odpowiedź edycji i każdy wiersz listy niosą to samo pole.
Dla klienta, który nie zapisał właśnie wydatku, GET /v1/groups/{id}/expenses/{id} zwraca wersję, wyliczone udziały oraz dane wejściowe, które za nimi stoją. Dane wejściowe wracają pod tymi samymi nazwami, które przyjmuje PATCH: participants, split_type, percents, weights, shares, items, pools. Klient czyta jeden kształt i odsyła go z edycjami, zamiast tłumaczyć między dwoma słownikami dla jednego rachunku.
Symetria ma największe znaczenie dla podziałów, których nie da się odtworzyć. Podziału PERCENT ani rachunku z pozycjami nie da się określić na nowo z samych wyliczonych udziałów, ponieważ zaokrąglenie zostało już zastosowane, a punkty bazowe i pozycje rachunku zniknęły. Migawki rewizji niosą także dane wejściowe, więc arkusz historii może pokazać, co zostało rozpisane na pozycje w dowolnej przeszłej wersji.
Wymagane teraz, ponieważ wymogu nie da się dodać później
Wymaganie pola od pierwszego dnia to decyzja o przyszłości, a nie o dniu dzisiejszym. Późniejsze złagodzenie wymaganego pola jest wstecznie zgodne: klienci już je wysyłają, a serwer zaczyna przyjmować żądania bez niego. Późniejsze dodanie wymogu psuje każdego klienta, który polegał na starej wartości domyślnej.
Dlatego kierunek wybiera się raz, wcześnie. Dimesum wymaga participants, split_type i base_version przy edycji, dopóki liczba klientów jest jeszcze na tyle mała, by można było ją zmienić. Jeśli kiedyś znajdzie się bezpieczna wartość domyślna dla edycji, pola staną się opcjonalne i nic, co już zostało wdrożone, nie przestanie działać.
Niech edycja na nowo określa to, co oznacza
Wartości domyślne należą do tworzenia, gdzie autor widzi grupę, na którą się zgadza. Przy edycji te same wartości domyślne są zgadywaniem na temat grupy, która od tamtej pory się zmieniła. Twój następny krok: otwórz własny punkt odczytu i sprawdź, czy oddaje dane wejściowe podziału pod dokładnie tymi nazwami pól, które przyjmuje twój punkt zapisu. Klient, który musi tłumaczyć między tymi dwoma, prędzej czy później przetłumaczy jedno z nich błędnie.
Często zadawane pytania
Dlaczego edycja wspólnego wydatku wymaga participants i split_type?
Dimesum wymaga obu pól, ponieważ domyślne wartości z tworzenia są błędne przy edycji. Przy tworzeniu Dimesum przyjmuje domyślnie wszystkich obecnych członków i równy podział, co odpowiada grupie, na którą patrzy autor. Edycja może pojawić się kilka tygodni później, gdy ktoś już dołączył. Ponowne użycie tych wartości domyślnych wciągnęłoby nowego współlokatora do starej kolacji i spłaszczyło celowy podział czynszu 70/30 z powrotem do 50/50, bez żadnego pokazanego błędu.
Co się dzieje, gdy dwie osoby edytują ten sam wydatek naraz?
Druga edycja zostaje odrzucona z HTTP 409 i kodem błędu stale_version. Każdy PATCH niesie base_version, wersję, którą przeczytał jego autor, a ścieżka edycji porównuje ją z zablokowanym wierszem. Niezgodność oznacza, że wydatek się zmienił, więc edycja wraca do autora, by zastosował ją ponownie wobec wersji, którą teraz widzi. Nic nie jest scalane.
Czy edycja wydatku aktualizuje wiersze księgi w miejscu?
Nie, edycja wydatku nigdy nie aktualizuje wiersza księgi w Dimesum. Edycja księguje dwa zapisy w jednej transakcji: EXPENSE_REVERSAL, który znosi starą wersję pozycja po pozycji, a następnie zapis EXPENSE dla nowej wersji. Operacje UPDATE i DELETE są odebrane własnej roli bazodanowej księgi, więc zmiana jest niemożliwa nawet dla wadliwego kodu. Widzisz oznaczenie edytowania oraz arkusz historii.
Czy przed edycją wspólnego wydatku potrzebuję drugiego wywołania API?
Nie, klient, który właśnie zapisał wydatek, już ma wersję, której potrzebuje edycja. Każda odpowiedź dotycząca wydatku niesie version, które następny PATCH wysyła jako base_version. Klient, który nie zapisał wydatku, wywołuje GET /v1/groups/{id}/expenses/{id}, co zwraca wersję oraz dane wejściowe podziału pod tymi samymi nazwami pól, które przyjmuje PATCH.
Dlaczego wymagać participants i split_type teraz, a nie dodać ich później?
Wymaganie pola od pierwszego dnia jest odwracalne, a dodanie go później nie. Późniejsze złagodzenie wymaganego pola jest wstecznie zgodne: klienci już je wysyłają, a serwer zaczyna przyjmować żądania bez niego. Późniejsze dodanie wymogu psuje każdego klienta, który polegał na starej wartości domyślnej, a w API obsługującym pieniądze awaria jest cicha, dopóki czyjeś saldo nie okaże się błędne.
Popularne wpisy
- Dopisywalna księga dla dokładnych sald wydatków8 min czytania
- Sześć błędów walutowych w podziale wydatków8 min czytania
- Rozliczenie: wspólne wydatki w kilku przelewach4 min czytania
- Jak sprawiedliwie podzielić rachunek w restauracji8 min czytania
- Jak sprawiedliwie podzielić czynsz między współlokatorów5 min czytania