Liczy się kasa

Od pewnego czasu w sklepach typu Lidl, Biedronka czy ostatnio Netto jest parcie na kasy samoobsługowe. W Lidlu do tego stopnia, że kierowani są tam wszyscy klienci, także ci z zakupami wymagającym potwierdzenia czy chcący zapłacić gotówką. Nie wiem jak to rozwiązują, aż chyba kiedyś wybiorę się specjalnie po to, aby to sprawdzić.

Powody są oczywiste – nie trzeba płacić kasjer(k)om, ich pracę przy kasie samoobsługowej wykona klient. Dodatkowo zmniejsza się narzut na logistykę związaną z obsługą fizycznych pieniędzy. Oczywiście koszt kasy samoobsługowej jakiś jest, ale tradycyjną też trzeba kupić. I wcale nie jestem przekonany, czy ta samoobsługowa jest droższa. Odpada choćby taśma transportowa. No a potem to już czysty zysk – nie trzeba zatrudniać obsługi i w dodatku przewidywać obciążenia na kasach w dany dzień/godzinę, co trywialne zapewne nie jest. Znaczy wystarczy jedna osoba do wszystkich kas, albo wręcz obsługa tradycyjnej kasy zajmie się kasami samoobsługowymi z doskoku.

Jak to wygląda z punktu widzenia klienta? Ano średnio. Już pal licho tę pracę wykonywaną za obsługę kasy, bo narzutu tyle, żeby zeskanować kody. Problemy zaczynają się, gdy ma się więcej produktów. Miejsca na odkładanie produktów w kasach samoobsługowych są zwyczajnie małe. I nie mówię o zakupach pakowanych do samochodu. One bywają za małe nawet do tego, co zabieram do plecaka i toreb.

Jednak nie tylko przy dużych zakupach jest problem. Ile razy zdarzało mi się robić drobne drobne zakupy na śniadanie, typu pieczywo i coś do niego? Wiecie, takie zakupy, gdy nawet nie bierze się koszyka. Ano wiele. No i sytuacja, jedna kasa z obsługą, stoją 2-3 osoby, więc myślę skasuję w samoobsługowej, będzie szybciej. A figę! Co prawda bułek mam kilka, wybieram prawidłowe, podaję ilość i… zonk. Nie zgadza się waga produktu, poczekaj, zaraz podejdzie asystent. Owszem, podejdzie. Tylko kiedy? Zwłaszcza, gdy asystentem jest osoba kasująca jednocześnie na zwykłej kasie…

Wszystkiemu winne są oczywiście nienormatywne produkty i niska tolerancja rozbieżności. Różnica wagi ponad 10% na bułkach nie jest rzadkością. A ostatnio w Biedronce mieli za duże ogórki. Dwa razy kupowałem i dwa razy po włożeniu do skasowanych od razu była blokada i wzywanie asystenta.

Rozwiązanie? Nie wiem, czy istnieje. Teoretycznie można zrobić rozpoznawanie obrazu przez AI i wyeliminować część przypadków. Na przykład ten z ogórkiem. Ale z pieczywem już będzie ciężko. W nieprzezroczystym, półpapierowym opakowaniu, albo nawet w przezroczystej reklamówce i kilku sztukach zwyczajnie trudno będzie o widoczność. Przy czym obecne rozwiązanie też jakby nie działa, bo w jakichś 8 przypadkach na 10 asystent nawet nie zerka na to, co odłożyłem, tylko odbija się na kasie i zatwierdza wyjątek.

Chargeback

Delegacja

Wszystko zaczęło się w połowie grudnia 2023 podczas delegacji z firmy. Hotel w Warszawie, znanej światowej sieci, nocleg zamówiła firma. Przy rejestracji na recepcji obsługiwała mnie osoba z dopiskiem stażysta. Czy tam praktykant. Zostałem poproszony o kartę płatniczą. Tłumaczę, że zamówienie przez firmę i moja prywatna karta do niczego potrzebna być nie powinna. Wizyta na zapleczu, zapewne konsultacja i… jednak karta płatnicza potrzebna. Do preautoryzacji. Nie chciało mi się walczyć, zresztą bywałem w tym hotelu wcześniej i było podobnie.

Ostatecznie więc dałem kartę. Co mi szkodzi blokada środków na dzień czy dwa? Teraz żałuję, że to zrobiłem. Trzeba było powiedzieć, że karty nie mam, pieniędzy nie mam, dowód osobisty to najwięcej co mogę zaoferować.

Deficyt

Parę dni po powrocie ze szkolenia spojrzałem w historię operacji w banku. A tam dwa obciążenia. 200 i 210 zł. Chyba tyle łącznie nocleg kosztuje. No ale święta za pasem, zapewne zaraz pójdzie zwrot, pomyślałem.

Nic bardziej mylnego. I święta minęły, i Sylwester, a zwrotu środków ani widu, ani słychu. Dopytałem kolegę, który był ze mną na delegacji i też dał kartę do preautoryzacji, tyle, że na innym stanowisku. On zwrot już dostał. Czyli nie jest tak, że mój pracodawca spóźnia się z opłaceniem faktury czy coś w ten deseń.

Hotel po raz pierwszy

Stwierdziłem, że zadzwonię do hotelu. Odebrała recepcja, po wysłuchaniu przeprosili za sytuację i przełączyli do księgowości. Tam sprawdzono sytuację i usłyszałem już zlecam zwrot. Podziękowałem i się rozłączyłem. Pomyłka może się zdarzyć każdemu, prawda?

Hotel po raz drugi

Odczekałem dłuższy okres czasu, sprawdziłem i… okazało się, że w historii konta nadal widać tylko obciążenie. Uznania ani widu, ani słychu. Zadzwoniłem ponownie do hotelu. Usłyszałem, że w systemie jest zlecony zwrot. Poprosiłem o jakieś potwierdzenie i wkrótce dostałem mailem dwa PDFy. Tyle, że nie bankowe z potwierdzeniem przelewu, jak się spodziewałem, tylko… potwierdzenia dokonania preautoryzacji. Z systemu hotelu.

Tym razem już nie dzwoniłem, tylko odpisałem na pytanie zawarte w mailu. Że owszem, mail dotarł, ale zawartość jakby pozostawia wiele do życzenia. Szybko otrzymałem kolejne potwierdzenie. Tym razem zwrotu. Ale nie w formie PDF, tylko… screenshota. Oczywiście nadal z wewnętrznego systemu hotelu. Powstrzymałem się i nie napisałem, ile czasu zajmuje mi zrobienie czegoś takiego w dowolnym programie graficznym.

Bank po raz pierwszy

Dla odmiany postanowiłem skontaktować się z bankiem. Po zweryfikowaniu mnie, sympatyczny pan z pomocy klienta stwierdził, że on w historii transakcji widzi tylko obciążenie, a uznania nie. Ucieszyłem się, że widzimy to samo. Człowiek, który mnie rozumie, znaczy.

Niestety, stwierdził, że w takim razie bank nic nie może zrobić i mam się kontaktować z hotelem. I tu przypomniałem sobie, jak to ludzie zachwalali płatność kartą bo jest chargeback, który chroni klienta, jest szybki i bezproblemowy. Gdy wspomniałem o tym, że chcę skorzystać, pan z obsługi klienta wyraźnie się ożywił i ucieszył. Powiedział, że oczywiście, nie ma problemu. I już wysyła papiery.

Papiery wypełniłem, pokorespondowałem także mailowo z bankiem, głównie w celu przesłania potwierdzeń, które otrzymałem z hotelu. W pewnym momencie niespodziewanie dostałem SMSem informację, że o wynikach postępowania zostanę poinformowany listem tradycyjnym. Cytuję odpowiedz wyslemy na adres korespondencyjny: ul. XXX. Swoje dane mozesz zmienic w bankowosci online. I że rozpatrywanie reklamacji może potrwać do 15 dni. Roboczych. Wot tiechnika! Nie drążyłem, bo nie znam regulacji operatorów kartowych.

Bank po raz drugi

Termin się zbliżył, sprawa z gatunku oczywistych: ja twierdzę, że kasa pobrana, hotel twierdzi, że była pobrana, ale oddali. Ja, że kasy nie dostałem. Dzwonię do banku. Sympatyczna pani z obsługi klienta informuje, że zaszła pomyłka, i że 15 dni roboczych to reklamacje dotyczące płatności, a to do 30 dni. Roboczych. Obiecuję uzbroić się w cierpliwość.

Przy okazji pytam, czy mogę zmienić formę korespondencji z listu tradycyjnego na maila. Bo podobno na życzenie klienta może być mail. No nie mogę, najwyraźniej klient może mieć takie życzenia tylko na początku reklamacji. Mimo, że złożenie reklamacji i dosyłanie szczegółów było mailem.

Ale jeszcze tego samego dnia dostaję odpowiedź na reklamację. Mailem! Z rozpatrzeniem mojej reklamacji. Negatywnym. Przydługi wywód o tym, że preautoryzacje były, ale zostały zwrócone. Zresztą są zwracane automagicznie po 10 dniach, ale tu jest płatność na rzecz hotelu. Brak podstaw do chargebacku, znaczy.

Cóż, widzę to nieco inaczej: teraz to dopiero jest podstawa do chargebacku! Bo ja tej płatności na rzecz hotelu ani nie robiłem, ani nie zgadzałem się na nią! Za nocleg miał płacić pracodawca.

Hotel po raz trzeci

Zanim jednak odpisałem do banku, postanowiłem zadzwonić po raz kolejny do hotelu i dowiedzieć się, za co ta płatność. Znowu księgowość, znowu inna sympatyczna osoba. Tłumaczę w czym problem i pytam, za co ta płatność niby. Ano za nocleg. Na co mówię, że przecież za nocleg płaciła firma. Ojej, to zaszła pomyłka! Mieli obciążyć pośrednika rezerwacji hotelowych, obciążyli mnie. I już zwraca pieniądze. Za parę dni powinny być.

Finał

Dziś, po kilku dniach od ostatniej rozmowy, dostałem zwrot środków. Przygoda skończyła się w marcu 2024. Znaczy trwało to wszystko dokładnie kwartał. Więc jeśli ktoś planuje zachwalać chargeback jako dobre zabezpieczenie, przyjazne klientowi i twierdzić, że płatności kartą są bezpieczne, to proponuję się jednak wstrzymać. Bo może mi się ulać.

Dziś dostałem też ankietę satysfakcji z reklamacji z banku. Nie, nie cisnąłem w niej. To sucha ankieta. Czas odpowiedzi przydługi, kontakt kilkukrotny, rozwiązanie niezgodne z oczekiwaniem. Ale OK, swoje zrobili i sprawdzili. Szkoda tylko, że nie dostałem kluczowej informacji, czyli że nie chodzi o preautoryzację, bo te zwracane są w ciągu 10 dni, od razu. Bo pewnie co innego byłoby w reklamacji. A może i nie byłaby potrzebna? NPS 4, bo wolno, bez sensu, dookoła i nie mam poczucia, że bank jest po stronie klienta. Gdyby komuś serio zależało na poprawie, pewnie więcej wyciągnąłby z tego wpisu.

Na list tradycyjny z zapowiedzianym rozpatrzeniem reklamacji nadal czekam. Coś mi mówi, że się nie doczekam. Może to i lepiej – szkoda papieru.

Dict, set, list!

Przy okazji niedawnego code review dostałem pytanie, czemu w skrypcie napisanym w Pythonie nie korzystam z obiektu typu set, tylko z dict. Chodziło o cache na kilka tysięcy elementów, odpytywany kilkaset tysięcy razy. Z przyzerowym hit ratio. Zdziwiłem się, bo kojarzyłem, że czytelna konstrukcja wykorzystująca in dla obiektu typu list

data = [x for x in range(1000)]
y = 1001
if y in data:
    print("Hit")

jest raczej wolna. Zwłaszcza w porównaniu z nieco mniej czytelnym wariantem z użyciem dict:

data = {x: True for x in range(1000)}
y = 1001
if data.get(y):
    print("Hit")

Odpisałem o co chodziło i usłyszałem, że przecież set jest szybki. Coś mi zaświtało. Bo niby set jest bardziej podobny w użyciu do listy, ale pod spodem ma parę ciekawych właściwości. Zresztą, gdy poprosimy LLM o optymalizację pod kątem szybkości, otrzymamy coś w stylu[1]:

data = {x for x in range(1000)} # Converted 'data' to a set
y = 1001
if y in data:  # Checking membership still works the same way
    print("Hit")

Różnice w czasie wykonania możemy zgrubnie i niezbyt elegancko sprawdzić w następujący sposób:

Jak już jesteśmy przy tego typu ciekawostkach. A co jeśli mamy w cache ciągi znaków i chcemy sprawdzić, czy nasz ciąg znaków nie kończy się jednym z ciągów z cache? LLM poproszony o optymalizację znowu podpowiada, że lepszy jest set. Ale nieoczekiwanie sugeruje też wykorzystanie regexpów. I co? Ku mojemu zaskoczeniu regexp w stylu

pattern = re.compile("("+"|".join(our_set)+")"$")
return bool(pattern.search(tested_value))

okazuje się najszybszym rozwiązaniem! Nie to, że uważam regexpy za szczególnie wolne, co to, to nie. Oczywiście pattern wykonujemy raz, nie dla każdej testowanej wartości.

Dalsza lektura:
O’reily High performance Python Dictionaries and Sets

[1] Tak, różnica niezbyt rzuca się w oczy przy takim zapisie. Mało widać różnicę między dict a set. Kiedyś już o tym wspominałem. Czytelniejszy zapis – którego chyba nikt nie używa – tamże.