Inventory Management Software

Kardex Tauro

Kardex Tauro® Inventory Software is designed to efficiently manage your warehouse or storage facility, and it is quick and easy to learn.

Kardex Tauro is free for non-commercial use.
It does not require an internet connection; it runs on Windows.

Python code: journal with validated double entry (free download)

Python code: journal with validated double entry (free download)

An entry that does not tie is the most expensive and the quietest mistake in the bookkeeping of a small business: it gets posted, nobody notices, and three months later the accounts will not close. This console program reads your journal from a text file, checks every entry against the double entry rules and sets aside the ones that do not tie before they reach your system. It was written for the owner of a small business who wants to understand their own numbers, for the clerk who types entries all day long and for the accountant who receives documents from third parties and needs a first automatic check before going through them by hand. It is a single file, it installs nothing and it runs the same way on Windows, Linux and Mac.

⬇ Descargar el código (ZIP)

What the ZIP brings

FileWhat it is for
libro_diario.pyThe whole program, commented line by line.
datos/asientos.csvSix sample entries: one comes out of balance on purpose so you can watch the rejection live.
salida_ejemplo.txtThe output you should get when you run it, so you can compare it with yours.
README.mdThe guide of the package: the steps to run it and the notice on responsible use.

The input uses a format anyone can prepare in a spreadsheet: one line per entry line, holding the entry number, the date, the account code, the account name and the two sides of the movement. When you run it, two output files appear with plain numbers, ready to open in Excel: salida/diario.csv with the accepted entries, and salida/rechazados.csv with the number of every rejected entry and its reason written in words.

What the program does

  1. It reads datos/asientos.csv. Every line holds the entry number, the date, the account, the account name, the debit and the credit: one line is one line of the entry, not the whole entry.
  2. It groups the lines by entry number, because one entry may carry several debit and credit lines. That is the compound entry, the daily bread of any business.
  3. It adds up the debits and the credits of the entry and checks four things: that both sums are exactly equal, that every line carries one amount only and above zero, that the account is digits only with a minimum of four, and that the date really exists in the calendar.
  4. If it finds a single mistake, it rejects the whole entry and writes the reason in plain words. It never posts half a truth: either the entry goes in complete or it stays out.
  5. It prints the accepted entries one by one with their balance line, the list of rejected ones and the summary by account with a debit or credit balance.
  6. It closes with the global check of debits against credits and saves the two output files so you can go through them calmly.

How to run it

You need Python 3.11 or above and nothing else. The program uses the standard library only, so there are no packages to install, no virtual environments to create and no dependencies that break a year later.

  1. Download the ZIP and extract it into a folder, for example on your desktop.
  2. If you do not have Python yet, install it from the official page. On Windows, tick the box that adds Python to the PATH during the installation.
  3. Open the terminal: on Windows the command prompt or PowerShell, on Mac and Linux the usual terminal.
  4. Change into the folder where you extracted the package with the cd command.
  5. Run python libro_diario.py. You will see the journal on screen and the two new files inside the salida folder.

The code, explained

Four fragments are enough: the header, the toolbox, the heart of the validation and the decision about what enters the journal. Everything else is printing results and writing files.

The header. The program introduces itself, states the Python version it was tested with and makes clear that there is nothing to install. It is the sentence that saves the most support questions: whoever downloads the package knows from the first line that Python is all they need.

# ==========================================================================
#  JOURNAL WITH VALIDATED DOUBLE ENTRY
#  Didactic Python code for accounting · Kardex Tauro · kardex-tauro.muisca.co
#  What it does: reads the entries in datos/asientos.csv, validates each one with the
#  double-entry rules, prints the journal and saves salida/diario.csv and salida/rechazados.csv
#  Tested with Python 3.11. Standard library only: nothing to install.
# ==========================================================================

The toolbox. Three imports and no surprises. Decimal is the key of the exercise: money is not added with binary decimals, because the rounding of the computer produces ghost cents that nobody can explain later. pathlib builds paths that behave the same on Windows, Linux and Mac. And the comment that follows states the idea behind everything: debit and credit are not good and bad, they are the two sides of one scale.

from decimal import Decimal, ROUND_HALF_UP          # Decimal: money is never computed with binary decimals (float)
from pathlib import Path                            # pathlib: paths that work on Windows, Linux and Mac

# DOUBLE ENTRY: whatever is debited on one side is credited on the other, same value
# One entry may carry several debit and credit lines: that is a compound entry
# Debit is not good and credit is not bad: they are the two sides of one scale

The validation. Here is the part that is worth money. The function walks the lines of the entry, accumulates debits and credits and returns a list of reasons: if the list comes back empty, the entry is fine. Every rule is checked on its own and all of them are written in human language, because the error message is the only thing the user sees when something fails. The last one is the heart of it: if debits and credits are not equal, the entry stays out.

def validar(lineas: list[dict]) -> list[str]:
    """Checks one entry and returns the list of rejection reasons (empty = accepted)."""
    errores = []
    debitos = CERO
    creditos = CERO
    for numero, linea in enumerate(lineas, start=1):
        debito = linea["debito"]
        credito = linea["credito"]
        # Rule 2: every line carries ONE amount only (debit or credit) and above zero
        if (debito != "") == (credito != ""):
            errores.append(f"Line {numero}: carries debit and credit at once, or neither of them")
        else:
            importe = debito or credito
            if not importe.replace(".", "").isdigit() or Decimal(importe) <= CERO:
                errores.append(f"Line {numero}: the amount must be a number greater than zero")
            elif debito != "":
                debitos += Decimal(debito)
            else:
                creditos += Decimal(credito)
        # Rule 3: the account is digits only, four at least (no letters, no symbols)
        if not (linea["cuenta"].isdigit() and len(linea["cuenta"]) >= 4):
            errores.append(f"Line {numero}: the account must be digits only, four at least")
        # Rule 4: the date must really exist in the calendar
        try:
            date.fromisoformat(linea["fecha"])
        except ValueError:
            errores.append(f"Line {numero}: the date must be YYYY-MM-DD and exist in the calendar")
    # Rule 1, the heart of it: debits = credits. If it does not tie, the entry stays out
    if debitos != creditos:
        errores.append(f"Debits and credits do not tie: DEBITS {miles(debitos)} <> CREDITS {miles(creditos)}")
    return errores

The decision. This block of the main program sets the character of the exercise: entries with mistakes go into a separate list and the rest go into the journal. There is no halfway state. An entry out of balance is rejected whole, its reason is saved, and the journal never ends up split between a line that went in and one that did not.

    aceptados = {}
    rechazados = []
    for numero, lineas in asientos.items():
        errores = validar(lineas)
        if errores:
            # An unbalanced entry is never posted halfway: it is rejected whole
            rechazados.append((numero, lineas, errores))
        else:
            aceptados[numero] = lineas
    print(f"Entries accepted: {len(aceptados)}")
    print(f"Entries rejected: {len(rechazados)}")

What you will see on screen

With the sample data the program reads six entries, accepts five and rejects one. The header of the output sums it up without decoration:

Entries read: 6
Entries accepted: 5
Entries rejected: 1

The entry that does not go in is number 4, dated March 12: rent paid from the bank. Exactly as it is written in datos/asientos.csv, its two lines are these:

EntryDateAccountAccount nameDebitCredit
42026-03-125145Rent expense500000
42026-03-121110Bank450000

The debit line records 500000 and the credit line records 450000: 50000 are missing somewhere and the entry does not tie. The program says so bluntly and points at the whole entry, not at a single line:

ENTRY 4   DATE 2026-03-12
  Reason: Debits and credits do not tie: DEBITS 500000 <> CREDITS 450000

That is the teaching moment of the exercise, and it is what almost no system shows you: the two figures facing each other on the same screen, with the missing amount in plain sight. With that message the mistake is fixed in two minutes; without it, the imbalance shows up three months later as a mystery in the accounts.

After the rejected list comes the summary by account: every account shows what it added to the debit side, what it added to the credit side and which side its balance sits on, debit or credit. The totals add up to 2220800 on each side, and the last line confirms it: TOTAL DEBITS = TOTAL CREDITS: TIES.

Common mistakes and tips

  • The file must be UTF-8. If you rewrite it with an old editor and save it in another encoding, the names with accents come out wrong and the program notices.
  • Run it from the package folder. The program works out its own folder from the path of the file, so it finds its data no matter where you call it from.
  • Amounts stay plain in the input file. Write the amount as a whole number, with no thousands separator and no decimals: the validation asks for digits only, with an optional decimal point.
  • One amount per line. Never fill debit and credit on the same line, and never leave both empty: that line is flagged as an error and drags the whole entry into the rejected list.
  • Accounts are codes. Digits only, four at least. If you need hierarchy, add more digits, not letters or dashes.
  • Do not reuse one entry number on different dates. Because the program groups by number, it would join lines that do not belong to the same entry.
  • Start with your own data. Replace the sample file with ten entries of your own and compare the output with your books: it is the best way to see how entries are typed on your team.

When this is not enough

This program is an entry filter, not an accounting system: it does not keep third parties, receivables, inventory, consecutive numbers or per user permissions. It works while the volume is small and while one person reviews the file before posting it. When the business grows and several hands work at the same time, the natural step is software that validates double entry as the entry is typed and that keeps a trail of who did what. That is where Kardex Tauro makes sense, a free program that brings order to inventory and movements. The rule is simple: the script to understand and control; the software for when a spreadsheet and a text file are no longer enough.

⬇ Descargar el código (ZIP)

Keep the package as the base of your own internal control: swap the validation rules for the rules of your business, add a column with the cost centre and you will have a journal made to measure in one afternoon.

Share
Link copied
Microsoft Store from Microsoft StoreDownload free
Chatea por WhatsApp