Metadata-Version: 2.4
Name: christophorus
Version: 1.3.2
Summary: Christophorus - Fahrtenbuch als Terminal-Anwendung mit Plausibilitätsprüfung
Author: Michael Blaess
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/michaelblaess/christophorus
Project-URL: Repository, https://github.com/michaelblaess/christophorus
Project-URL: Issues, https://github.com/michaelblaess/christophorus/issues
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Intended Audience :: End Users/Desktop
Classifier: Topic :: Office/Business
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: textual>=0.40
Requires-Dist: rich>=13.0
Requires-Dist: openpyxl>=3.1
Requires-Dist: holidays>=0.40
Requires-Dist: textual-fspicker>=0.4.0
Requires-Dist: textual-themes[textual]>=0.15.1
Requires-Dist: textual-widgets>=0.32.1
Provides-Extra: web
Requires-Dist: python-fasthtml>=0.12; extra == "web"
Provides-Extra: dev
Requires-Dist: christophorus[web]; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: pytest-xdist>=3.5; extra == "dev"
Requires-Dist: mypy>=1.8; extra == "dev"
Requires-Dist: poethepoet>=0.29; extra == "dev"
Requires-Dist: ruff>=0.3; extra == "dev"
Requires-Dist: import-linter>=2.0; extra == "dev"
Requires-Dist: types-openpyxl>=3.1.5.20260518; extra == "dev"
Dynamic: license-file

# Christophorus

<p align="center">
  <img src="https://raw.githubusercontent.com/michaelblaess/christophorus/8f7ed70373669ba84d0f5ba7613e44f8366ba471/docs/flags/gb.svg" height="13" alt=""> <b>English</b> ·
  <img src="https://raw.githubusercontent.com/michaelblaess/christophorus/8f7ed70373669ba84d0f5ba7613e44f8366ba471/docs/flags/de.svg" height="13" alt=""> <a href="https://github.com/michaelblaess/christophorus/blob/8f7ed70373669ba84d0f5ba7613e44f8366ba471/README.de.md">Deutsch</a>
</p>

---

<p align="center">
  <img src="https://raw.githubusercontent.com/michaelblaess/christophorus/8f7ed70373669ba84d0f5ba7613e44f8366ba471/docs/christophorus.png" width="200" alt="Christophorus logo">
</p>

A terminal application for keeping a vehicle logbook (German: *Fahrtenbuch*),
for leased and owned vehicles alike. Christophorus records every trip, keeps the
odometer chain consistent, checks the entries for plausibility and exports
the logbook as Excel, JSON or Markdown.

The user interface is available in German and English.

Project page: [michaelblaess.github.io/christophorus](https://michaelblaess.github.io/christophorus/)

The name comes from Saint Christopher, the patron saint of travellers and
drivers. In the terminal it is shorter: `christo` starts the same program.
Up to version 1.2.1 the project was called "Death Proof", before that
"fahrtenbuch". On the first start Christophorus picks up settings and logbooks
stored under the old names on its own.

> **Note:** Whether a logbook is accepted for tax purposes is decided solely by
> the tax office. Christophorus does not guarantee that acceptance and does not
> replace tax advice. On first start the program asks you to confirm this notice.

## Features

- **Trips:** date, travel time, destination, purpose, odometer start and end,
  business and private kilometres, category, round trip, fuel in litres.
- **Views:** list per month and per year, calendar, year overview, blocked days
  (blacklist), receipts and working hours.
- **Plausibility checks:** odometer chain, fuel consumption against the vehicle
  data, business trips on weekends and public holidays, suspected duplicate
  entries, yearly share of business kilometres.
- **Repair the odometer chain:** rebuilds start and end values chronologically
  without changing the distance of any trip.
- **Export** through a save dialog: Excel with live formulas, JSON with every
  field, Markdown table. The format follows the file extension.
- **Several logbooks:** each logbook is a folder with its own SQLite database.
  Open, create, back up, or copy the settings of an existing logbook.
- **Settings:** vehicle and lease data, home address, customers, petrol
  stations, shops, tax adviser, restaurants, categories, federal state for
  public holidays, SQLite journal mode (safe for Dropbox and OneDrive).
- **Keyboard:** classic letters or function keys F1 to F10, optional Vim
  navigation in tables, overview on `?`.
- **Anonymize** for screenshots: destinations, purposes, vehicle, number plate
  and folder are replaced in the display. Database and export stay untouched,
  dialogs showing real data are locked while it is on.
- **Themes** from [textual-themes](https://github.com/michaelblaess/textual-themes).

## Screenshots

All screenshots show made-up data.

| Month list | Calendar |
|---|---|
| ![Month list](https://raw.githubusercontent.com/michaelblaess/christophorus/8f7ed70373669ba84d0f5ba7613e44f8366ba471/docs/screenshots/en/01-month-list.png) | ![Calendar](https://raw.githubusercontent.com/michaelblaess/christophorus/8f7ed70373669ba84d0f5ba7613e44f8366ba471/docs/screenshots/en/02-calendar.png) |
| **Year overview** | **Plausibility check** |
| ![Year overview](https://raw.githubusercontent.com/michaelblaess/christophorus/8f7ed70373669ba84d0f5ba7613e44f8366ba471/docs/screenshots/en/03-year-overview.png) | ![Plausibility check](https://raw.githubusercontent.com/michaelblaess/christophorus/8f7ed70373669ba84d0f5ba7613e44f8366ba471/docs/screenshots/en/04-plausicheck.png) |
| **New trip** | |
| ![New trip](https://raw.githubusercontent.com/michaelblaess/christophorus/8f7ed70373669ba84d0f5ba7613e44f8366ba471/docs/screenshots/en/05-new-trip.png) | |

## Installation

### One-click install

The installer downloads the prebuilt package of the latest release. No Python
and no git required. Running it again updates the program, your settings and
logbooks stay untouched.

**Windows (PowerShell):**

```powershell
irm https://raw.githubusercontent.com/michaelblaess/christophorus/main/install.ps1 | iex
```

**Linux (x86_64) and macOS (Apple Silicon):**

```bash
curl -fsSL https://raw.githubusercontent.com/michaelblaess/christophorus/main/install.sh | bash
```

Afterwards start `christophorus` or the short form `christo`. On Windows open a
new terminal first so the updated PATH takes effect.

### Download manually

Every release on the [Releases page](https://github.com/michaelblaess/christophorus/releases)
contains standalone builds for Windows (x64), Linux (x86_64) and macOS (Apple Silicon).
Unpack the archive and start `christophorus`.

### From source

Requires Python 3.12 or newer and [uv](https://docs.astral.sh/uv/).

```powershell
# Windows
.\bootstrap.ps1
.\run.ps1
```

```bash
# Linux / macOS
./bootstrap.sh
./run.sh
```

## Usage

```bash
christophorus                 # opens the last logbook, otherwise the start screen
christophorus --year 2024     # start in a specific year
christophorus --lang en       # switch the language (saved for the next start)
christophorus --version
```

## Key bindings

The style is chosen under Settings -> Keyboard. With function keys the letters
stay available, only the log moves from `L` to `F4`.

| Action | Classic | With function keys |
|---|---|---|
| Info | `I` | `F1` |
| Settings | `S` | `F2` |
| Manage logbooks | `V` | `F3` |
| Log on/off | `L` | `F4` / `Alt+L` |
| Refresh | `F5` | `F5` |
| Repair odometer chain | `R` | `F6` |
| New trip | `N` | `F7` |
| Plausibility check | `P` | `F8` |
| Blacklist on/off | `B` | `F9` |
| Export | `E` | `F10` |
| Delete trip | `DEL` | `DEL` |
| Next theme | `T` | `T` |
| Anonymize display | `A` | `A` |
| Previous / next month | `<` / `>` | `<` / `>` |
| Key overview | `?` | `?` |
| Quit | `Q` | `Q` |

Custom bindings go into `config.json` under `keymap_custom`, for example
`{"toggle_log": ["alt+l"]}`.

## Where the data lives

| What | Where |
|---|---|
| Application settings | `~/.christo/config.json` |
| Acceptance of the notice | `~/.christo/disclaimer.json` |
| Logbook | a folder of your choice with `christo.db` and a `belege/` folder for receipts |

## Web interface (preview)

Besides the TUI there is a web interface, built to try out Tabler, Tabulator and FastHTML. It
covers the same ground as the TUI: the trips of a month or a year, a calendar, the year at a
glance, blocked days, receipts, working hours, settings and the export to Excel, JSON or
Markdown.

```bash
uv sync --extra web
uv run python -m christo.web            # last logbook opened in the TUI
uv run python -m christo.web <folder>   # a specific logbook
```

- **It always works on a copy** under `~/.christo/web/<name>/`. The file the TUI uses is never
  changed. `--neu-kopieren` fetches the current state and discards the copy.
- Runs on `127.0.0.1:5056` only, without login, and loads nothing from the internet.
- Colors come from [web-themes](https://github.com/michaelblaess/web-themes), the same themes as
  in the TUI.
- What carried over from building it is written down in [docs/WEB-MUSTER.md](https://github.com/michaelblaess/christophorus/blob/8f7ed70373669ba84d0f5ba7613e44f8366ba471/docs/WEB-MUSTER.md)
  (German).

## Development

```bash
uv run poe lint        # ruff
uv run poe typecheck   # mypy strict
uv run poe layers      # import-linter: layer boundaries
uv run poe test        # pytest
```

The core (`services`, `models`) does not import the user interface or Textual.
import-linter enforces this in CI and in the pre-commit hook.

## Tech stack

[Textual](https://textual.textualize.io/), SQLite, [openpyxl](https://openpyxl.readthedocs.io/),
[holidays](https://github.com/vacanza/holidays),
[textual-fspicker](https://github.com/davep/textual-fspicker),
[textual-widgets](https://github.com/michaelblaess/textual-widgets) and
[textual-themes](https://github.com/michaelblaess/textual-themes).

## License

[Apache License 2.0](https://github.com/michaelblaess/christophorus/blob/8f7ed70373669ba84d0f5ba7613e44f8366ba471/./LICENSE)

## Author

Michael Blaess
