RevBank
"Banking in the Netherlands does correspond to Dutch stereotypes — which is a great thing. You can always split a check in a restaurant and they have some slick mobile apps to keep track of who paid for what during trips and outings that also provide ways for everyone to be reimbursed easily. So it’s no surprise to learn that a Dutch hackerspace has developed their own accounting and funds transfer system to help members pay and get paid. And that would be RevBank.
The public-facing part of RevBank is a terminal sitting right next to the fridge and the snacks, with a barcode scanner attached so you can scan your item, then scan or type your name, and you’re done. The source is here. It’s written in .. uhm, perl. Have fun with that.
I gave it a whirl while I was there, and was able to top up my account with a bank transfer (this statement makes sense in Europe — you can also do cash instead). And then I used it to pay for all my snacks that day. Worked great, quite efficient."
— NYCResistor - Hackerspace Envy - A Visit to RevSpace in The Hague
1. Source
https://github.com/revspace/revbank
2. Implementatie bij RevSpace
RevBank staat op de server gateway onder de gebruiker bar (we hadden ooit een bar).
Er draaien 3 permanente RevBank-instances:
- De oude seriële terminal, die met een aantal interessante hacks met GNU Screen een seriële barcodescanner als tweede input heeft.
- De laptop bij de statiegeldcontainer in de hoofdruimte, met USB-barcodescanner. Deze verbindt via mosh en draait revbank in statiegeld-teruggeef-modus.
- De laptop bij de vrieskisten in de keuken, met USB-barcodescanner. Deze verbindt via mosh.
3. Gebruikers
- Sinds 2011: RevSpace
- Sinds 2013: TechInc
- Sinds 2014: Bitlair
- Sinds 2014: eth0
- Sinds 2015: Pixelbar
- Sinds 2015: Maakplek
- Sinds 2017: Hackalot
- Sinds 2018: Hackerspace Nijmegen
- Sinds 2019: Frack
- Sinds 2019: Coredump
- Sinds 2020: TDvenlo
- Sinds 2021: Hackerspace Drenthe
- Sinds 2022: UmeHack
- Sinds 2023: PI4DEC
Voormalig gebruikers: Hack42, Sk1llz, Hackerspace Gent.
4. FAQ
- Is RevBank stabiel?
- In de betekenis van "werkt betrouwbaar": ja, we gebruiken het nu sinds 2011. In de betekenis van "wijzigt niet": nee, er wordt nog steeds wel eens aan gesleuteld. Daarbij wordt zo veel mogelijk geprobeerd om de commandostructuur gelijk te houden omdat veel gebruikers het systeem gebruiken zonder daar nog bij na te denken.
- Is een CLI niet te moeilijk voor newbies?
- Nee, zelfs absolute beginners leren hier binnen enkele minuten mee werken; we hebben hier nu vele jaren ervaring mee. Een GUI is soms makkelijker te verkennen, maar kan ook overweldigend werken doordat veel mogelijkheden tegelijk aangeboden worden.
- Maar touchscreens!!!1
- Touchscreens zijn bij hackerspaces in het algemeen "apparaat zoekt project". Als je een bank-GUI maakt ligt een touchscreen voor de hand, maar RevBank is nu eenmaal CLI-gebaseerd.
- Hoe installeer/upgrade je RevBank?
- Staat allemaal in de README.
- Kun je meerdere RevBanks tegelijk draaien op dezelfde databestanden?
- Ja, RevBank gebruikt een globale lockfile, en schrijft nieuwe dingen met een atomische rename voor de zekerheid.
- Is RevBank veilig?
- Nee, RevBank is volledig gebaseerd op vertrouwen. De revbank-terminal staat in het algemeen in de buurt van de voorraden en een open geldkistje, en is daarom alleen geschikt als je je bezoekers kunt vertrouwen. Je kunt afrekenen op naam van iemand anders ("Kun je voor mij een cola meenemen?"), geld van andere gebruikers afnemen, en de databestanden verpesten. Beheerders wordt geadviseerd veel backups te maken.
- Ondersteunt RevBank ook korting voor leden/deelnemers?
- Nee, want de maker vindt dat stom. Korting voor leden klinkt lief, maar is eigenlijk gewoon een middelvinger naar incidentele bezoekers, als de meeste transacties door leden/deelnemers worden gedaan.
- Hoe gaat RevBank om met Unicode/UTF-8?
- Belabberd. Alle input en output wordt opgevat als rauwe bytes. Dat betekent dat UTF-8 meestal goed in beeld komt in een UTF-8-terminal en je op zich best adduser ♥ kan doen, maar omdat RevBank het niet decodeert naar Unicode strings, kunnen dingen scheef gepositioneerd komen te staan in de full-screen-dingen zoals de ingebouwde editor. Dit oplossen is gedoe, want zelfs als je de bytes wel omzet naar codepoints, weet je nog niet welke codepoints samen één teken vormen, en vervolgens niet of dat teken één of twee posities inneemt in een terminal. Het gebruik van non-ASCII accountnamen, product-IDs, productomschrijvingen, etc., wordt daarom afgeraden.
- Waarom...
-
- Waarom gebruikt RevBank geen echte database?
- De data wordt opgeslagen in tekstbestanden omdat je die kunt gebruiken met tools zoals git en diff. Ze zijn ontzettend simpel, en daardoor wanneer dat nodig blijkt ook gewoon met een teksteditor te bewerken. Het scheelt ook een dependency, maar dat is bijzaak.
- Waarom eerst de producten en dan je naam, in plaats van eerst je naam en dan de producten?
- Omdat je dan zou moeten aangeven wanneer je klaar bent met je lijst producten. Doordat RevBank onderscheid maakt tussen product-id's en accountnamen, kan de accountnaam worden gebruikt als indicatie dat je klaar bent met de producten.
- Waarom is het take naam naam naam 4.20 en niet take 4.20 naam naam naam?
- Om dezelfde reden, maar dan omgekeerd: omdat je dan zou moeten aangeven dat je klaar bent met de namen. Door eerst de namen te doen, en dan pas het bedrag, kan het bedrag worden gebruikt als herkenning van het einde van de namen.
- Waarom is het give Juerd 4.20 en niet give 4.20 Juerd?
- Vanwege consistentie met take.
- Waarom zijn de commando's dan niet take-from en give-to?
- Dat zou wel duidelijker zijn, maar ook meer typwerk.
- Waarom mag ik geen negatieve bedragen gebruiken?
- Het is niet nodig, en zou verwarrend kunnen zijn.
- Waarom wordt "?" niet geaccepteerd als alternatief voor "help"?
- Veel systemen die "?" snappen, ondersteunen dat bij élke vraag. Als je dat gewend bent, en merkt dat "?" werkt in RevBank, denk je waarschijnlijk ook dat "?" je gaat uitleggen wat er bedoeld wordt met bijvoorbeeld de vraag "Beneficiary:" van het commando "give", maar zo geavanceerd is het hulpsysteem niet.
- Waarom zitten er foeilelijke regexes in o.a. de plugin "users"?
- Dat was makkelijker en leuker.
- Hoe...
-
- Hoe krijg ik een lijstje van alle commando's?
- Met het commando "help".
- Hoe maak ik een nieuw account?
- Met het commando "adduser".
- Hoe reken ik iets af?
- Scan eerst de producten, typ/scan daarna je accountnaam.
- Hoe reken ik iets af op andermans rekening?
- Door de naam van diegene te typen/scannen in plaats van die van jezelf.
- Hoe reken ik meerdere van hetzelfde af?
- Door voor het product "2x" of "2*" te typen, of na het product "x2" of "*2".
- Hoe bekijk ik mijn saldo van mijn account?
- Typ/scan je accountnaam, zonder eerst producten te scannen. Je krijgt dan je laatste transacties en je saldo.
- Hoe bekijk ik mijn laatste transacties?
- Typ/scan je accountnaam, zonder eerst producten te scannen. Je krijgt dan je laatste transacties en je saldo.
- Hoe kijk ik verder terug dan bovenstaande me laat zien?
- Met het commando "log".
- Hoe stort ik meer geld op mijn account?
- Zie de pagina Deposit voor de diverse manieren.
- Hoe neem ik geld op van mijn account?
- Met het commando "withdraw".
- Hoe geef ik geld aan een andere gebruiker?
- Met het commando "give".
- Hoe jat ik geld van een andere gebruiker?
- Met het commando "steal" (ook bekend als "take").
- Hoe deel ik de rekening van het eten dat ik in de supermarkt heb ingekocht voor een groep?
- Ook met het commando "take". Om de kookbonus toe te passen, type je "kookbonus" tussen de take en je accountnaam.
- Hoe deel ik de kosten van een pizza?
- Door na het scannen van de pizza, het commando "split" te typen.
- Hoe herstel ik een foutje als ik nog niks heb afgerekend?
- Met het commando "abort" begin je opnieuw met een schone lei. Dit commando werkt overal in RevBank, ongeacht de vraag die je krijgt.
- Hoe herstel ik een foutje nadat ik heb afgerekend?
- Met het commando "undo" kun je een recente transactie terugdraaien. Dat herstelt de saldi van de betrokken accounts met een correctieboeking.
- Hoe bied ik een product te koop aan in de market?
- Verzin een product-ID en check of die nog niet in RevBank wordt gebruikt. Plak op alle producten een barcode met dat ID. Met het commando "market" beland je in de editor. Daar kun je een regel aan het tekstbestand toevoegen. Let op: de prijs van een product in de market is de optelsom van het bedrag dat naar de verkoper gaat, en het bedrag dat naar de space gaat. Beide componenten van de prijs zijn verplicht hoger dan 0.
- Hoe sluit ik RevBank af?
- RevBank heeft daar opzettelijk geen commando voor, omdat de primaire betaalterminal altijd moet blijven werken. Als je een extra revbank-proces hebt gestart, kun je 'm veilig killen; als je via een shell werkt kom je terug in je shell door RevBank te stoppen met ctrl+Z; dat geeft een job id en die kun je met bijv. kill %1 afmaken.
5. Zeldzame transacties
5.1. Cash afromen
- Optie 1 (alleen bestuur): skim
Dit is een generieke optie waarbij je revbank niet vertelt hoe je het geld aan de stichting gaat geven.
> skim There should currently be (at least) 114.49 in the cash box. Amount to skim: 100 > jouwnaamhier Proceed to remove 100.00 from the cash box; it should then have (at least) 14.49 remaining.
- Optie 2: via je eigen account: withdraw + deposit. Op deze manier kan je een specifieke manier aangeven. Deelnemers kunnen deze methode ook gebruiken om de space als geldautomaat te gebruiken.
> withdraw 100 (betaal via https://deposit.revspace.nl/) > tr_abcd1234 Pending: 100.00 Withdrawal + 100.00 Deposit (online; tr_abcd1234) Enter username to deduct 0.00 from your account; type 'abort' to abort. > jouwnaamhier
5.2. Geld toevoegen aan de cashbox (alleen bestuur)
Geld dat al van de stichting is (bijv. ontvangen contributie/borg of ander geld dat buiten revbank om in de administratie staat) toevoegen aan de cashbox is het omgekeerde van afromen, en het commando heet daarom unskim
> unskim There should currently be (at least) 14.49 in the cash box. Amount to unskim: 12.34 > jouwnaamhier Proceed to put 12.34 into the cash box; it should then have (at least) 26.83 in it.
5.3. Kascontrole / -correctie
cash geeft aan hoeveel er volgens revbank in kas is. Je kunt het geld tellen en aangeven hoeveel het echt is; revbank doet dan een voorstel voor een correctieboeking.
> cash There should currently be (at least) 101.00 in the cash box. Please count the money to verify. How much is there, exactly? 100.10 Thank you for checking! That's a shortage of 0.90. Type 'fix pls' to apply a permanent correction, or 'abort' to abort: fix pls Done: 0.90 Cash shortage Discrepancy recorded; corrected cash box amount is 100.10.
5.4. goedbezig-account aanvullen (alleen bestuur)
goedbezig-account wordt aangevuld met reimburse, zodat het correct geboekt kan worden als kostenpost, in plaats van dat er spontaan magisch geld vanuit het niets ontstaat.
> deposit 100 How are we receiving this 100? reimburse Please provide a short description: goedbezig Which board member gave approval? Juerd > goedbezig New balance for goedbezig: +6.73 + 100.00 = +106.73
5.5. Tegoed uitbetalen op IBAN (alleen bestuur)
(bijv. bij einde deelnemerschap en deelnemer is al geëmigreerd)
Niet via withdraw, want dan klopt de kastelling niet meer. Gebruik undeposit (ja echt) met als tegenrekening -deposits/iban opgeven, afsluiten met accountnaam van deelnemer. Deze functie is nogal spartaans uitgevoerd.
> undeposit Note: this function is for internal use by board members ONLY. Enter 'abort' to abort. Contra: -deposits/iban Amount to withdraw: 13.37 > xyzzy New balance for xyzzy: +13.37 - 13.37 = 0.00
NB: in de praktijk heet de tegenrekening om redenen momenteel -deposits/iban_legacy_pleasedonotuse. Dit is wel een valide toepassing.
6. Online deposit (mollie-integratie)
Geld toevoegen aan je revbank-account ging ooit alleen contant, later kon je ook geld naar de rekening van de space overmaken. Dat werd onoverzichtelijk, dus toen openden we er een aparte rekening voor. Dat maakte het wat overzichtelijker, maar gebruikers maakten regelmatig kleine foutjes. De betaling was echter helemaal losgekoppeld van de deposit in revbank, en daardoor kwam het voor dat het bedrag niet overeenkwam, door denkfouten en door typo's (bijv 52 euro betaald en in revbank 25 ingetypt). Sommigen vergaten het depositcommando, of erger: de betaling.
Daarom doen we sinds 2021 online betalingen via iDeal. Daarvoor is er een backend website waarop mensen de betaling doen en daarna een barcode krijgen, die ze dan in revbank kunnen scannen. Minder foutgevoelig en ook makkelijker in gebruik. Het enige dat nu nog fout kan gaan, is dat mensen dat vergeten te scannen, maar daar komen ze snel genoeg zelf achter doordat hun revbank-saldo laag blijft.
In revbank is het geimplementeerd als de plugin revspace_mollie, de source van de betaalsite staat op https://github.com/revspace/revbank-mollie-deposit en is geschreven in een paarhonderd regels PHP omdat we toch al PHP moeten draaien voor de wiki. De betaalsite is volledig stateless, althans, alle state wordt bij Mollie opgeslagen. De barcode is dan ook gewoon de transactie-id van de molliebetaling.
Af en toe sluit een gebruiker de site te snel, en heeft die wel betaald maar de code niet afgewacht. In dat geval kan een bestuurslid makkelijk via het dashboard van Mollie de code opzoeken.
Er zitten bekende race conditions in, waardoor je met wat precieze timing een code wellicht 2x zou kunnen gebruiken. Dat is niet erg, want revbank heeft toch geen beveiliging (puur op vertrouwen gebaseerd).
Een andere space die dit ook wil gebruiken, zou dit kunnen doen:
- https://github.com/revspace/revbank-mollie-deposit (PHP) forken en aanpassen voor eigen gebruik
- Aanmelden bij Mollie
- Test API-key van Mollie in de config zetten
- revbank-plugin "revspace_mollie" forken en aanpassen (iig de URL veranderen!)
- Testen, en als het werkt de productiekey in de config zetten.
Transactiekosten van credit- en debitcards mogen niet worden doorberekend, net als pinbetalingen in winkels. Bij een onlinebetaling via iDeal mag het op zich (nog) wel, maar de manier waarop wij het gebruiken komt erg dicht in de buurt van een pinbetaling in een winkel, dus het is een grijs gebied. Daarom berekenen we de transactiekosten (ca. 0,35 € incl. 21% BTW voor een iDeal-betaling) niet 1-op-1 door, maar zitten die kosten in de verkoopprijzen verwerkt en hanteren we een minimumbedrag.
Door de pluginstructuur van revbank is het ook mogelijk om integraties voor andere betaalplatformen te schrijven. Bij het evenement eth0 wordt revbank bijvoorbeeld gebruikt in combinatie met betalingen via pretix.
7. Geschiedenis
- eind 2009: RevSpace wordt opgericht
- begin 2010: Het wordt gebruikelijk om vooraf te betalen en op een briefje je tegoed bij te houden
- half 2010: De briefjes worden vervangen door een terminal met Vim. Mensen snappen vim niet en lezen de tekstregels scheef, en verpesten continu het bestand.
- eind 2010: Toch maar nano, maar mensen lezen het nog steeds scheef en passen regelmatig het verkeerde saldo aan.
- ergens begin 2011: Versie 1: een perlscriptje van ca. 300 regels. De interface was simpel: typ het bedrag, typ dan je naam.
- 2 uur later: Het besef dat prijzen opzoeken in een tabel ook overgelaten kan worden aan een computer. Een productentabel en barcodescanner komen erbij, en voortaan wordt het: scan producten, typ/scan je naam.
- de dagen erna: Op verzoek van gebruikers komen er features bij zoals geld geven aan iemand anders.
- april 2011: De source komt eindelijk in git dus voor de rest van deze opsomming hoeven de datums niet gegokt te worden :)
- juni 2011: De prompt wordt nu afgehandeld door de readline library, met tab-completion.
- februari 2013: Versie 2: RevBank is grotendeels herschreven en heeft nu een modulaire structuur met plugins.
- februari 2013: Marketfunctie gemaakt als simpele demo (35 regels code) van de plugin-infra. Blijkt later een erg populaire feature te worden.
- oktober 2015: De eerste heftige bug die grootschalige schade veroorzaakt wordt gevonden. Gelukkig is de schade makkelijk te herstellen met het commando "undo".
- oktober 2015: De eerste (en vooralsnog enige) security bug wordt gevonden: een shell-injectie. Geen groot issue voor RevSpace, want we geven iedereen toch al shelltoegang op het account van RevBank...
- februari 2017: Tijdens Eth0:2017 Winter wordt een vieze hack gebouwd: een plugin genaamd "repeat" waarmee je makkelijk meerdere keren hetzelfde product kunt afrekenen. Het werkt door gewoon een regel van de transactie te dupliceren, want RevBank heeft nog geen concept van aantallen. Het kan ook nog niet werken met sommige soorten transacties die bestaan uit meerdere regels, omdat RevBank niet kan weten welke regels bij elkaar horen.
- november 2019: Versie 3: Gebruikers zien vooral de versimpelde overzichten, maar intern verandert er iets heel significants: transactieregels kunnen gegroepeerd worden, waardoor de "repeat"-plugin nu voor alles kan gaan werken. Transacties lijken nu intern meer op journaalposten van een boekhoudsysteem. Inclusief plugins is RevBank nu nog steeds maar ca. 2200 regels code.
- december 2021: Versie 3.2: Geen zichtbare veranderingen voor gebruikers, als het goed is, maar RevBank gebruikt nu intern bedragen in gehele centen in plaats van drijvendekommagetallen, want floating point is eigenlijk gewoon niet handig voor iets financieels. Voor revbank is het altijd "goed genoeg" geweest, maar het leidde tot rare artefacten zoals dat je een saldo van "-0.00" kon hebben.
- juni 2022: Versie 3.3: Een heel kleine update, maar een nieuw versienummer omdat het emotioneel een grote stap is. Weet je nog dat je in versie 1 een bedrag en je naam typte, nog voordat RevBank een productenlijst kreeg? Die functionaliteit heeft al die tijd nog gewerkt, maar het gebrek aan onderscheid tussen een product kopen of geld opnemen werkte verwarrend. Gewoon "rauw" een bedrag typen is er nu niet meer bij: je moet voortaan specifiek "unlisted" of "withdraw" gebruiken. RIP revbank-1-workflow.
- juni 2022: Versie 3.4: In versie 3 was het al voorbereid met de mogelijkheid om tegenrekeningen aan een transactie toe te voegen, maar de volgende stap is gezet richting "dubbel boekhouden": ALLES krijgt een tegenrekening (maar (nog) niet verplicht voor custom plugins). Om gebruikers te beschermen tegen informatie-overload, zijn de tegenrekeningen verborgen uit de user interface. Wel weet het systeem nu dus magisch hoeveel geld er in het geldkistje zou moeten zitten, en wordt dat bij een "undo" ook keurig teruggedraaid. Dit zou kascontrole een stuk makkelijker moeten maken. De codebase is nu net iets onder de 3000 regels, dus 10× zo groot als versie 1.
- augustus 2022: Versie 3.5: Tot nu toe startte revbank vim voor het aanpassen van de productenlijsten, maar lang niet iedereen snapt vim. In tegenstelling tot wat veel mensen denken, is een editor zoals nano ook niet per se zonder hulp te gebruiken door newbies (je moet maar net weten dat ^ betekent dat je ctrl moet indrukken), en er bleek geen enkele editor te zijn die volledig zelfverklarend is én goed werkt op echte oude terminals zoals de IBM 3151 die we bij RevSpace voor RevBank gebruiken. Dus moest RevBank maar een eigen interne editor krijgen die wel aan alle wensen voldoet.
- (Versies 3.5 t/m 3.9 zijn niet zo heel interessant)
- september 2023: Versie 4.0.0: Een poging om semantic versioning te gebruiken, dus nu twee puntjes in het versienummer. Transactienummers waren altijd eigenlijk stiekem timestamps (unix time minus 1.3e9), maar het is gangbaar om facturen e.d. doorlopend te nummeren zodat je kunt zien als er iets in je log ontbreekt. Kleine wijziging, maar bij upgrades wel een ding waar beheerders een keuze moeten maken welk schema ze voortaan willen aanhouden. Intussen heeft RevBank overigens ondersteuning voor BTW-administratie, sommige GS1-barcodes, en het bijhouden en teruggeven van statiegeld.
- november 2023: Versie 4.1.0 en 4.2.0: adduser wordt wat strikter, en verbiedt voortaan allerlei usernames die problemen kunnen geven. Commando's, producten, en gebruikersnamen delen immers by design allemaal dezelfde namespace. Garanties tegen clashes kunnen niet gegeven worden, maar sommige clashes kun je wel herkennen. Ook is er nu een speciaal accounttype voor accounts die uitgesloten moeten worden van het totaal generaal (grand total). Die accounts komen in beeld met een * aan het begin.
- november 2023: Versie 4.2.2: Bij PI4DEC hebben ze een interessante situatie ontdekt vanwege een custom plugin die stierf tijdens het afrekenen van een gegenereerd barcode-pasje. Ik vind het niet echt een bug in RevBank, want die plugin had fouten natuurlijk moeten afvangen, maar de manier waarop in RevBank de transactie wel gelogd, maar niet uitgevoerd werd, werkt natuurlijk wel erg verwarrend. Enfin, RevBank vangt nu uitzonderingen op die de plugin laat liggen.
- december 2023: Versie 4.3.0 en 5.0.0: Twee features waar regelmatig om gevraagd is, zijn nu eindelijk ingevoerd. Het heeft lang geduurd omdat het backwards incompatible zou zijn, en ik jarenlang geen goede manier kon bedenken om sierlijk om te gaan met invoer van gebruikers die een oudere versie gewend zijn. Je kunt nu op de plaats van een bedrag een simpele rekensom met + en - geven, en in de "geavanceerde modus" dingen tussen aanhalingstekens zetten, waardoor er bijvoorbeeld een spatie in een omschrijving kan (voorheen kon dat alleen in de "simpele modus"). En je kunt met een puntkomma opdrachten van elkaar scheiden, en in sommige gevallen moet dat voortaan zelfs, waardoor diverse bedieningsfouten kunnen worden gedetecteerd voordat ze een definitieve transactie veroorzaken - dit zou een aantal keren undo per jaar moeten schelen. Je kunt zelfs voor het eerst sinds het bestaan van RevBank "abort" als letterlijke tekst opgeven als invoer voor een plugin, namelijk door er aanhalingstekens omheen te zetten. Nuttig? Nauwelijks, behalve dat je nu eindelijk een barcode-print-plugin kunt gebruiken om een abort-barcode te maken :P
Voor veel meer detail, zie de git commit log...