Skip to content

Rental management software: from website to counter

How we built AFKnuoma, rental management software with online booking, counter check-out, immutable invoices and a database that rules out double booking.

AFKzona Group · 6 min read

Real screens from the product

The short answer

  • Money is stored as whole euro cents, so invoices, the deposit ledger and the day close add up to the cent.
  • Double booking is prevented by a PostgreSQL exclusion constraint, and a test fires fifty simultaneous reservations at the last unit: exactly one succeeds.
  • The database itself locks every issued invoice; corrections go through a credit invoice, and numbering runs without gaps or duplicates.
  • Every electronic device passes a complete data-wipe checklist before its next rental.

AFKnuoma is a rental management system we designed and built for our own rental business: tools, drones, games consoles and VR headsets, booked online and handed out at a counter. It combines a bilingual Lithuanian and English public site with booking and payment, and a back office for stock, reservations, check-out and returns, invoices, deposits and maintenance. Its most important rule, that nothing can be booked twice, is enforced by the database itself and proved by a test.

This case study describes what the system does, the rules we chose to put in the database rather than in code, and how we test them. The system has 69 pages, 45 data models and 74 test files.

What problem does a rental system have to solve?

A rental business sells time on physical objects. Every item can be in one place at once, and every mistake costs money: a double booking loses a customer, a lost deposit record loses cash, and an invoice with a gap in its numbering causes trouble with the accountant. The system has to make these errors impossible, not merely unlikely.

Spreadsheets and calendar apps break down on exactly these points. They show availability, but nothing stops two people saving overlapping bookings at the same moment, and nothing ties the booking to the hand-out, the deposit and the invoice. We wanted one record that follows an item from the website to the counter and back.

What does AFKnuoma include?

AFKnuoma is one system with two faces: a public site where customers find equipment and book it, and a back office where staff manage stock, reservations, the counter, money and maintenance. Both work on the same data, so availability on the website is the availability at the counter.

AreaWhat it does
Public site (LT and EN)Catalogue with live availability and prices for chosen dates, online booking and payment
InventoryEvery physical, serialised unit tracked: out, in, in maintenance or in quarantine
Reservations calendarWeb and staff bookings, kits, consumables sold with a rental, change requests
CounterCheck-out and returns, walk-in bookings, deposits taken and paid back
InvoicesImmutable once issued, gap-free numbering, corrections by credit invoice
MaintenanceBlocks that take a unit out of circulation, with no overlaps
Data wipingElectronics stay unrentable until the wipe checklist is complete
Day closeCash register Z-report compared with what the system recorded; counted drawer against expected

A kit is a bundle rented as one product but made of several stock items. When a kit is booked, each component is held separately, so a drone kit cannot go out if one of its batteries is already rented.

Two details show the care that runs through the whole system. Search finds "vejapjovė" (lawnmower) when a customer types "vejapjove" without Lithuanian diacritics. And when a booking is refused because nothing is free, the system records what was wanted, so the owner can see which items are worth buying more of.

How is double booking made impossible?

Double booking is prevented by a PostgreSQL exclusion constraint on each physical unit and its time range: the database refuses any second active allocation that overlaps an existing one, whatever the application code does. The same kind of constraint stops maintenance blocks from overlapping on a unit.

An exclusion constraint is a database rule that rejects a new row if it conflicts with an existing row under a stated comparison, here "same unit and overlapping time". It uses the btree_gist extension to combine an equality check on the unit with an overlap check on a time range.

Why in the database? Application code checks availability first and then saves. Between the check and the save there is a gap of milliseconds, and two customers booking the last unit at the same moment can both pass the check. Only the database sees both writes, so only the database can refuse one of them reliably.

The proof is a concurrency test. It sends fifty simultaneous reservation requests for the last available unit and asserts four things: exactly one reservation is created, the other forty-nine are refused with a "not available" error, exactly one stock hold exists, and the forty-nine refusals are recorded as unmet demand. The test runs against a real PostgreSQL database, not a mock.

Why are invoices immutable?

Issued invoices in AFKnuoma cannot be edited or deleted, because an accounting document that can be changed after issue is not a reliable record. Database triggers reject any update or deletion of an issued invoice, its lines, payments and deposit transactions. A mistake is corrected the way an accountant expects: with a credit invoice.

The invoice's lines and amounts are fixed from the moment it is issued, and the stored PDF is attached to that same record. As with double booking, the rule lives in the database, so it holds whatever the application does.

Gap-free numbering means invoice numbers run 1, 2, 3 without missing or repeated numbers, per document series. It is harder than it sounds: if the system reserves a number and the transaction then fails, a naive design leaves a hole. Our tests cover three cases:

  • separate series for separate document types, with the year in the number when a series asks for it;
  • a failed issuing transaction does not use up a number;
  • one hundred simultaneous issues receive the numbers 1 to 100, each exactly once.

Money is stored as whole euro cents, never as floating-point numbers, so totals on the invoice, the deposit ledger and the day close always add up to the cent.

How is the system tested?

AFKnuoma has 74 test files. Integration tests run the domain rules against a real PostgreSQL database; browser tests click through the public site, the counter and the back office the way a person would. A feature is counted as done when it works against a real database, not when the code compiles.

The integration tests read like the business rules they protect. A few, quoted from the test names:

  • a walk-in customer may give only a phone number, is matched by phone and receives no e-mails;
  • cancelling frees the stock at once, is recorded in the audit log, and a second tap changes nothing;
  • a reservation cannot be cancelled once it has been handed over;
  • a returning customer is found by e-mail or phone, and what the shop already knows is never overwritten.

Browser tests cover staff sign-in, documents, inventory, maintenance, reservations, the counter, the catalogue, booking, and accessibility of the public site.

What we would build the same way for another business

The pattern carries over to any business that books physical things or time: equipment and vehicle hire, rooms and venues, appointments with limited staff. Put the rules that must never break into the database, test them under simultaneous load, and make money documents immutable from the first version.

What changes from business to business is the catalogue, the pricing rules, the deposits and the counter process. What should not change is that one record follows each booking from the website to the invoice. We treat a booking system as a small accounting system with a calendar attached, and design it that way from the data model up.

Build a booking or rental system with us

The kinds of booking, rental and back-office systems we build are described under booking and rental systems, with AFKnuoma's screens on our work page. A product build starts at €12,000 with a written scope and a fixed price; see pricing and product builds. To talk through your own process, book a free 30-minute call.

Common questions

What should rental management software include?

At minimum: a catalogue with live availability for chosen dates, online booking and payment, a reservations calendar, check-out and returns at the counter, deposits, invoices, and maintenance tracking. For electronics, also a data-wipe step before the next rental. AFKnuoma covers all of these in one system, so a booking, a hand-out and an invoice always refer to the same record.

How do you prevent double bookings in a rental system?

Enforce it in the database, not only in the application. AFKnuoma uses a PostgreSQL exclusion constraint on each physical unit and its time range, so two active rentals of the same unit cannot overlap whatever the code does. A test sends fifty simultaneous reservations for the last available unit and checks that exactly one is accepted.

How does rental software keep invoices tamper-proof?

AFKnuoma locks them in the database. Triggers refuse any change or deletion of an issued invoice, its lines, payments and deposit transactions, whatever the application does, and a mistake is corrected with a credit invoice. Numbering runs without gaps or duplicates in every document series.

When is a custom rental system worth building?

When your rules are your own: kits built from separate items, deposits by customer tier, counter cash reconciliation, or data wiping for electronics. A custom system follows your process from the website to the invoice, so your staff work with the software instead of around it.

How do you test a rental management system?

Against a real database. AFKnuoma has 74 test files. Integration tests run the booking, invoice and deposit rules against PostgreSQL, including one hundred simultaneous invoice issues that receive the numbers 1 to 100 exactly once, and browser tests click through the public site, the counter and the back office the way a person would.

Sources

  1. PostgreSQL documentation — Exclusion constraints
  2. PostgreSQL documentation — btree_gist extension
  3. PostgreSQL documentation — Range types

Tell us what you need built.

A free 30-minute call with the engineer who would lead it. You leave with a scope outline and a price range.