lxw-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. lxw_cli-0.1.0/.claude/scheduled_tasks.lock +1 -0
  2. lxw_cli-0.1.0/.env.example +6 -0
  3. lxw_cli-0.1.0/.gitattributes +2 -0
  4. lxw_cli-0.1.0/.github/workflows/publish.yml +39 -0
  5. lxw_cli-0.1.0/.github/workflows/test.yml +36 -0
  6. lxw_cli-0.1.0/.gitignore +40 -0
  7. lxw_cli-0.1.0/LICENSE +21 -0
  8. lxw_cli-0.1.0/PKG-INFO +403 -0
  9. lxw_cli-0.1.0/README.md +368 -0
  10. lxw_cli-0.1.0/docs/tui-screenshot.svg +177 -0
  11. lxw_cli-0.1.0/pyproject.toml +71 -0
  12. lxw_cli-0.1.0/src/lxw_cli/__init__.py +1 -0
  13. lxw_cli-0.1.0/src/lxw_cli/__main__.py +4 -0
  14. lxw_cli-0.1.0/src/lxw_cli/cli.py +207 -0
  15. lxw_cli-0.1.0/src/lxw_cli/commands/__init__.py +0 -0
  16. lxw_cli-0.1.0/src/lxw_cli/commands/_common.py +40 -0
  17. lxw_cli-0.1.0/src/lxw_cli/commands/articles.py +110 -0
  18. lxw_cli-0.1.0/src/lxw_cli/commands/contacts.py +215 -0
  19. lxw_cli-0.1.0/src/lxw_cli/commands/delivery_notes.py +114 -0
  20. lxw_cli-0.1.0/src/lxw_cli/commands/invoices.py +179 -0
  21. lxw_cli-0.1.0/src/lxw_cli/commands/mcp.py +167 -0
  22. lxw_cli-0.1.0/src/lxw_cli/commands/orders.py +117 -0
  23. lxw_cli-0.1.0/src/lxw_cli/commands/quotations.py +117 -0
  24. lxw_cli-0.1.0/src/lxw_cli/commands/vouchers.py +121 -0
  25. lxw_cli-0.1.0/src/lxw_cli/config.py +235 -0
  26. lxw_cli-0.1.0/src/lxw_cli/core/__init__.py +10 -0
  27. lxw_cli-0.1.0/src/lxw_cli/core/client.py +200 -0
  28. lxw_cli-0.1.0/src/lxw_cli/core/constants.py +25 -0
  29. lxw_cli-0.1.0/src/lxw_cli/core/errors.py +19 -0
  30. lxw_cli-0.1.0/src/lxw_cli/core/models.py +30 -0
  31. lxw_cli-0.1.0/src/lxw_cli/core/services.py +598 -0
  32. lxw_cli-0.1.0/src/lxw_cli/mcp_server.py +367 -0
  33. lxw_cli-0.1.0/src/lxw_cli/output.py +191 -0
  34. lxw_cli-0.1.0/src/lxw_cli/tui/__init__.py +7 -0
  35. lxw_cli-0.1.0/src/lxw_cli/tui/app.py +391 -0
  36. lxw_cli-0.1.0/src/lxw_cli/tui/detail.py +220 -0
  37. lxw_cli-0.1.0/src/lxw_cli/tui/entities.py +174 -0
  38. lxw_cli-0.1.0/src/lxw_cli/tui/order_form.py +286 -0
  39. lxw_cli-0.1.0/tests/__init__.py +0 -0
  40. lxw_cli-0.1.0/tests/conftest.py +31 -0
  41. lxw_cli-0.1.0/tests/snapshots/contacts_flat.txt +7 -0
  42. lxw_cli-0.1.0/tests/snapshots/contacts_grouped.txt +14 -0
  43. lxw_cli-0.1.0/tests/snapshots/invoices_list.txt +5 -0
  44. lxw_cli-0.1.0/tests/test_cli.py +372 -0
  45. lxw_cli-0.1.0/tests/test_cli_snapshots.py +138 -0
  46. lxw_cli-0.1.0/tests/test_client.py +136 -0
  47. lxw_cli-0.1.0/tests/test_config.py +145 -0
  48. lxw_cli-0.1.0/tests/test_mcp_server.py +154 -0
  49. lxw_cli-0.1.0/tests/test_output.py +116 -0
  50. lxw_cli-0.1.0/tests/test_resolve.py +120 -0
  51. lxw_cli-0.1.0/tests/test_services.py +257 -0
  52. lxw_cli-0.1.0/tests/test_tui.py +622 -0
@@ -0,0 +1 @@
1
+ {"sessionId":"89a7173f-ca25-480d-9741-339a7e21c739","pid":3945,"procStart":"Thu Jul 16 09:04:14 2026","acquiredAt":1784194733658}
@@ -0,0 +1,6 @@
1
+ # Lexware Office API Key
2
+ # Generate at https://app.lexware.de/addons/public-api
3
+ LEXWARE_API_KEY=your-api-key-here
4
+
5
+ # Optional: override the API base URL (default: https://api.lexware.io)
6
+ # LEXWARE_API_BASE_URL=https://api.lexware.io
@@ -0,0 +1,2 @@
1
+ # Snapshots werden byte-genau verglichen — niemals EOL-konvertieren.
2
+ tests/snapshots/** -text
@@ -0,0 +1,39 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+
13
+ - name: Install uv
14
+ uses: astral-sh/setup-uv@v5
15
+
16
+ - name: Build sdist + wheel
17
+ run: uv build
18
+
19
+ - uses: actions/upload-artifact@v4
20
+ with:
21
+ name: dist
22
+ path: dist/
23
+
24
+ publish:
25
+ needs: build
26
+ runs-on: ubuntu-latest
27
+ environment: pypi
28
+ # Trusted Publishing: kein API-Token nötig — auf pypi.org unter
29
+ # "Publishing" diesen Repo/Workflow als Trusted Publisher eintragen.
30
+ permissions:
31
+ id-token: write
32
+ steps:
33
+ - uses: actions/download-artifact@v4
34
+ with:
35
+ name: dist
36
+ path: dist/
37
+
38
+ - name: Publish to PyPI
39
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,36 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ name: py${{ matrix.python-version }} · ${{ matrix.os }}
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, macos-latest, windows-latest]
16
+ python-version: ["3.11", "3.12", "3.13"]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+
26
+ - name: Install dependencies
27
+ # --clear: setup-uv legt je nach Plattform bereits ein .venv an
28
+ run: |
29
+ uv venv --clear
30
+ uv pip install -e ".[dev]"
31
+
32
+ - name: Ruff
33
+ run: uv run --no-project ruff check src tests
34
+
35
+ - name: Pytest
36
+ run: uv run --no-project pytest -v
@@ -0,0 +1,40 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ .eggs/
7
+ dist/
8
+ build/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ .coverage
12
+ htmlcov/
13
+ *.egg
14
+
15
+ # Virtual environments
16
+ .venv/
17
+ venv/
18
+ env/
19
+
20
+ # Environment files
21
+ .env
22
+ .env.local
23
+
24
+ # Claude Code (lokale Einstellungen)
25
+ .claude/settings.local.json
26
+
27
+ # IDE
28
+ .vscode/
29
+ .idea/
30
+ *.swp
31
+ *.swo
32
+
33
+ # OS
34
+ .DS_Store
35
+ Thumbs.db
36
+
37
+ # Downloads / Outputs
38
+ *.pdf
39
+ *.csv
40
+ !tests/**/*.csv
lxw_cli-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Markus Oeffling
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
lxw_cli-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,403 @@
1
+ Metadata-Version: 2.4
2
+ Name: lxw-cli
3
+ Version: 0.1.0
4
+ Summary: Inoffizielles CLI/TUI/MCP-Tool für die Lexware Office API (vormals lexoffice)
5
+ Project-URL: Homepage, https://github.com/OEM-Mrks/lxw-cli
6
+ Project-URL: Documentation, https://developers.lexware.io/
7
+ Author: Markus Oeffling
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: api,cli,lexoffice,lexware,mcp,tui
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Office/Business :: Financial :: Accounting
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: fastmcp>=2.10
21
+ Requires-Dist: httpx>=0.27
22
+ Requires-Dist: pydantic>=2.6
23
+ Requires-Dist: python-dotenv>=1.0
24
+ Requires-Dist: rich>=13.7
25
+ Requires-Dist: tenacity>=8.2
26
+ Requires-Dist: textual>=0.58
27
+ Requires-Dist: typer>=0.12
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
30
+ Requires-Dist: pytest-cov>=4.1; extra == 'dev'
31
+ Requires-Dist: pytest>=8.0; extra == 'dev'
32
+ Requires-Dist: respx>=0.21; extra == 'dev'
33
+ Requires-Dist: ruff>=0.4; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # lxw-cli
37
+
38
+ Ein Kommandozeilen-Tool für die [Lexware Office API](https://developers.lexware.io/) (vormals lexoffice). Liest Rechnungen, Kontakte, Belege, Artikel, Angebote, Aufträge und Lieferscheine — und legt Drafts neu an.
39
+
40
+ > **Hinweis:** Inoffizielles Community-Tool — kein Produkt der Haufe-Lexware
41
+ > GmbH & Co. KG und nicht mit ihr verbunden. „Lexware" ist eine Marke der
42
+ > Haufe Group.
43
+
44
+ ## Features
45
+
46
+ - Zwei Frontends auf einem UI-freien Core: **CLI** (skriptbar) und **interaktive TUI** (`lxw` ohne Argumente)
47
+ - Lesen: `list` (paginiert + Filter), `get` (Detail), `pdf` (Download)
48
+ - Schreiben: `create-draft` für Belege (Rechnungen, Angebote, Aufträge, Lieferscheine, Belege), `create` für Stammdaten (Kontakte, Artikel)
49
+ - Paginierung: `--limit N`, `--all`/`-a` bzw. `--limit 0` für **alle** Treffer über alle Seiten
50
+ - Artikel-Volltextsuche: `articles list --search/-q` (Bezeichnung, Beschreibung, Teil-Artikelnummer)
51
+ - Kontakte: `--customer` / `--vendor` (nur Kunden/Lieferanten), optional `--grouped`
52
+ - Ausgabe: Tabelle (Rich), JSON (pipe-fähig), CSV, Datei-Output
53
+ - PDF-Download nach Datei **oder** Verzeichnis (Auto-Dateiname); `-o` optional
54
+ - Komfort: API-Key-Abfrage beim ersten Start, Warte-Animation bei längeren Abrufen
55
+ - Eingebauter Rate-Limit-Schutz (2 req/s) + automatische Retries auf 429/5xx
56
+
57
+ ## Installation
58
+
59
+ Läuft auf **macOS, Linux und Windows** (Python ≥ 3.11). Empfohlen als
60
+ isoliertes Tool mit [uv](https://docs.astral.sh/uv/) oder
61
+ [pipx](https://pipx.pypa.io/):
62
+
63
+ ```bash
64
+ uv tool install lxw-cli # oder: pipx install lxw-cli
65
+ lxw profile
66
+ ```
67
+
68
+ Alternativ klassisch in ein Environment:
69
+
70
+ ```bash
71
+ pip install lxw-cli
72
+ ```
73
+
74
+ ### Aus dem Quellcode (Entwicklung)
75
+
76
+ ```bash
77
+ git clone https://github.com/OEM-Mrks/lxw-cli
78
+ cd lxw-cli
79
+ uv venv && source .venv/bin/activate
80
+ uv pip install -e ".[dev]"
81
+ ```
82
+
83
+ ## API-Key konfigurieren
84
+
85
+ Lege einen API-Key in deinem Lexware-Account an: <https://app.lexware.de/addons/public-api>
86
+
87
+ **Einfachste Variante:** Ruf `lxw` einfach auf. Findet das Tool keinen Key,
88
+ fragt es im Terminal danach, prüft ihn gegen die API und speichert ihn unter
89
+ `~/.config/lexware/.env` (Datei-Rechte `0600`, nur für dich lesbar; unter
90
+ Windows `%APPDATA%\lexware\.env`). Ab dann funktioniert `lxw` aus **jedem**
91
+ Verzeichnis, ohne weitere Einrichtung.
92
+
93
+ ```bash
94
+ lxw profile
95
+ # → Kein Lexware API-Key gefunden. Lexware API-Key: ********
96
+ # → ✓ API-Key gespeichert in ~/.config/lexware/.env — angemeldet als Acme GmbH
97
+ ```
98
+
99
+ Der Key wird in dieser Reihenfolge gesucht:
100
+
101
+ 1. gesetzte Environment-Variable `LEXWARE_API_KEY`
102
+ 2. projektlokale `.env` (vom aktuellen Verzeichnis aufwärts — praktisch für die Entwicklung)
103
+ 3. globale `~/.config/lexware/.env` (bzw. `$XDG_CONFIG_HOME/lexware/.env`; unter Windows `%APPDATA%\lexware\.env`)
104
+
105
+ Wer es manuell vorziehen will, kann den Key auch direkt setzen:
106
+
107
+ ```bash
108
+ cp .env.example .env # projektlokal
109
+ # LEXWARE_API_KEY=… eintragen
110
+ ```
111
+
112
+ In nicht-interaktiven Kontexten (Pipes, Cron, MCP-Server über stdio) wird **nicht**
113
+ gefragt — dort muss der Key vorab über eine der drei Quellen vorhanden sein.
114
+
115
+ ## Quickstart
116
+
117
+ ```bash
118
+ # Auth-Test: zeigt Firmenprofil
119
+ lxw profile
120
+
121
+ # Rechnungen (Tabelle) — Standard: 25 Einträge
122
+ lxw invoices list --limit 10
123
+
124
+ # ALLE Rechnungen laden (paginiert automatisch über alle Seiten)
125
+ lxw invoices list --all
126
+ lxw invoices list --limit 0 # gleichbedeutend
127
+
128
+ # Archivierte sind standardmäßig ausgeblendet — bei Bedarf einblenden
129
+ lxw invoices list --include-archived
130
+ lxw contacts list --include-archived
131
+
132
+ # Rechnungen als JSON in jq pipen
133
+ lxw --json invoices list --status open | jq '.[].voucherNumber'
134
+
135
+ # CSV-Export von Kunden
136
+ lxw --csv --output kunden.csv contacts list --customer --limit 200
137
+
138
+ # Artikel suchen — Teiltreffer in Bezeichnung, Beschreibung und Artikelnummer
139
+ lxw articles list --search "schraube"
140
+ lxw articles list -q "SCH-" # auch Teil-Artikelnummern
141
+ lxw articles list --number SCH-001 # exakte Artikelnummer (serverseitig, schnell)
142
+
143
+ # Rechnung per Belegnummer abrufen (UUID auch möglich)
144
+ lxw invoices get FB2600682
145
+ lxw --json invoices get FB2600682 | jq '.totalGrossAmount'
146
+
147
+ # PDF einer Rechnung herunterladen (UUID oder Belegnummer)
148
+ lxw invoices pdf FB2600682 # → ./invoice-FB2600682.pdf
149
+ lxw invoices pdf FB2600682 --output ~/Rechnungen # Verzeichnis: Dateiname automatisch
150
+ lxw invoices pdf FB2600682 --output rechnung.pdf # exakter Dateipfad
151
+
152
+ # Kontakt anlegen (Stammdaten — kein Draft)
153
+ lxw contacts create --body '{
154
+ "roles": {"customer": {}},
155
+ "company": {"name": "Test GmbH"}
156
+ }'
157
+
158
+ # Komplexere Bodies aus Datei
159
+ lxw invoices create-draft --body @invoice-template.json
160
+ ```
161
+
162
+ ## Verfügbare Befehle
163
+
164
+ | Befehl | Zweck |
165
+ |---|---|
166
+ | `lxw profile` | Firmenprofil abrufen (Auth-Test) |
167
+ | `lxw invoices` | Rechnungen: `list`, `get`, `pdf`, `create-draft` |
168
+ | `lxw contacts` | Kontakte: `list`, `get`, `create` |
169
+ | `lxw vouchers` | Belege: `list`, `get`, `create-draft` |
170
+ | `lxw articles` | Artikel: `list`, `get`, `create` (mit Volltextsuche) |
171
+ | `lxw quotations` | Angebote: `list`, `get`, `pdf`, `create-draft` |
172
+ | `lxw orders` | Aufträge (Auftragsbestätigungen): `list`, `get`, `pdf`, `create-draft` |
173
+ | `lxw delivery-notes` | Lieferscheine: `list`, `get`, `pdf`, `create-draft` |
174
+
175
+ Hinweis: `create-draft` legt **Belege** als Entwurf an (Draft, nicht finalisiert);
176
+ **Stammdaten** (Kontakte, Artikel) kennen keinen Draft-Status und werden mit
177
+ `create` direkt angelegt.
178
+
179
+ Detail-Hilfe mit `lxw <command> --help` bzw. `lxw <command> list --help`.
180
+
181
+ ## Suchen, Filtern & Paginierung
182
+
183
+ Alle `list`-Befehle teilen sich dasselbe Paginierungs-Verhalten und besitzen
184
+ befehlsspezifische Filter. Intern wird serverseitig seitenweise abgerufen —
185
+ immer mit dem API-Maximum von 250 Datensätzen/Request (mit Rate-Limit-Schutz),
186
+ damit so wenige Requests wie möglich nötig sind.
187
+
188
+ ### Menge: --limit und --all (für jeden `list`-Befehl)
189
+
190
+ | Option | Wirkung |
191
+ |---|---|
192
+ | `--limit N`, `-n N` | Maximal N Einträge (Standard: 25). |
193
+ | `--limit 0` | Unbegrenzt — lädt **alle** Treffer über alle Seiten. |
194
+ | `--all`, `-a` | Wie `--limit 0`; überschreibt ein gesetztes `--limit`. |
195
+
196
+ ```bash
197
+ lxw invoices list --all # alle Rechnungen
198
+ lxw contacts list --customer -a # alle Kunden
199
+ ```
200
+
201
+ Am Listenende wird die **Gesamtzahl** der Datensätze ausgegeben (aus dem
202
+ `totalElements` der API) — z.B. `→ 25 von 1234 Rechnungen angezeigt (mehr mit
203
+ --all)` bzw. `→ 1234 Kontakte gesamt`, wenn alles geladen wurde. Diese Zeile geht
204
+ auf **stderr**, stört also `--json`/`--csv`-Pipes nicht. Bei der clientseitigen
205
+ Artikelsuche wird stattdessen die Trefferzahl gezeigt (`→ 12 Treffer`).
206
+
207
+ ### Befehlsspezifische Filter
208
+
209
+ | Befehl | Filter-Optionen |
210
+ |---|---|
211
+ | `invoices list` | `--status`, `--number` (exakt), `--contact-id`, `--include-archived` |
212
+ | `vouchers list` | `--type`, `--status`, `--number` (exakt), `--contact-id`, `--include-archived` |
213
+ | `contacts list` | `--name` (≥3 Z.), `--email` (≥3 Z.), `--number`, `--customer`, `--vendor`, `--grouped/--flat`, `--include-archived` |
214
+ | `articles list` | `--search`/`-q` (Volltext), `--number` (exakt), `--type product\|service`, `--gtin` (exakt) |
215
+ | `quotations list` | `--status`, `--include-archived` |
216
+ | `orders list` | `--status`, `--include-archived` |
217
+ | `delivery-notes list` | `--status`, `--include-archived` |
218
+
219
+ `--status` und `--type` sind komma-separiert (z.B. `--status open,paid`).
220
+
221
+ ### Archivierte ausblenden (Standard)
222
+
223
+ Archivierte Datensätze werden bei **Belegen** (Rechnungen, Belege, Angebote,
224
+ Lieferscheine) **und Kontakten** standardmäßig ausgeblendet — `--include-archived`
225
+ zeigt sie. Bei Belegen filtert die API serverseitig (`archived=false`), die
226
+ Gesamtzahl bleibt also exakt; bei Kontakten geschieht es clientseitig (siehe
227
+ unten). Der Footer weist mit `· ohne archivierte (--include-archived zeigt alle)`
228
+ darauf hin.
229
+
230
+ ### Kontakte: nur Kunden oder nur Lieferanten
231
+
232
+ `contacts list` liefert standardmäßig **eine zusammenhängende Liste** (nicht
233
+ getrennt — gut für Pipes und Weiterverarbeitung durch LLMs). Auf Wunsch nur eine
234
+ Rolle oder optional gruppiert:
235
+
236
+ ```bash
237
+ lxw contacts list # aktive Kontakte, eine Liste
238
+ lxw contacts list --customer # nur Kunden (serverseitig gefiltert)
239
+ lxw contacts list --vendor # nur Lieferanten (serverseitig gefiltert)
240
+ lxw contacts list --grouped # Tabelle in Kunden-/Lieferanten-Abschnitte
241
+ lxw contacts list --include-archived # archivierte Kontakte einblenden
242
+ ```
243
+
244
+ Bei `--grouped` zeigt jede Tabelle die passende Kunden- bzw. Lieferantennummer;
245
+ Kontakte mit beiden Rollen erscheinen in beiden Abschnitten (`role`-Spalte =
246
+ `customer+vendor`). `--json` und `--csv` sind immer eine flache Liste mit
247
+ `role`-Spalte.
248
+
249
+ **Archivierte Kontakte** werden standardmäßig ausgeblendet — `--include-archived`
250
+ zeigt sie wieder. Da die Kontakt-API archivierte nicht serverseitig filtern kann,
251
+ geschieht das clientseitig: `lxw` blättert durch die Seiten und überspringt
252
+ archivierte, bis genug aktive für das `--limit` zusammen sind. Der Footer zeigt
253
+ dann z.B. `→ 298 aktive Kontakte gesamt (14 archivierte ausgeblendet)`.
254
+
255
+ ### Artikel-Volltextsuche: --search / -q
256
+
257
+ Die Lexware-API filtert Artikel serverseitig **nur exakt** (`--number`, `--gtin`,
258
+ `--type`). Für unscharfe Suche nach **Bezeichnung, Beschreibung oder
259
+ Teil-Artikelnummer** gibt es `--search`/`-q` — dabei werden Artikel clientseitig
260
+ durchsucht (Teiltreffer, Groß-/Kleinschreibung egal):
261
+
262
+ ```bash
263
+ lxw articles list -q "schraube" # Bezeichnung/Beschreibung
264
+ lxw articles list -q "SCH-" # Teil-Artikelnummer
265
+ lxw articles list --number SCH-001 # exakte Nummer (serverseitig, schnell)
266
+ lxw articles list -q "kabel" --type product --all # kombinierbar
267
+ ```
268
+
269
+ Hinweis: `--search` scannt im Zweifel alle Artikel (bricht ab, sobald genug
270
+ Treffer für `--limit` gefunden sind). Bei sehr großen Beständen entsprechend
271
+ langsamer als die exakten Server-Filter.
272
+
273
+ ## Globale Optionen
274
+
275
+ | Flag | Zweck |
276
+ |---|---|
277
+ | `--json` | JSON-Ausgabe (für Pipelines) |
278
+ | `--csv` | CSV-Ausgabe |
279
+ | `--output PATH`, `-o` | In Datei statt stdout schreiben |
280
+ | `--version`, `-V` | Version anzeigen |
281
+
282
+ ## Interaktive TUI
283
+
284
+ Neben der CLI gibt es eine **Terminal-UI** zum Durchstöbern deiner Daten
285
+ (Rechnungen, Kontakte, Belege, Artikel, Angebote, Aufträge, Lieferscheine) —
286
+ und zum Anlegen neuer Aufträge als Entwurf.
287
+
288
+ ```bash
289
+ lxw # ohne Argumente im Terminal → TUI startet automatisch
290
+ lxw-tui # oder explizit
291
+ ```
292
+
293
+ ![TUI](docs/tui-screenshot.svg)
294
+
295
+ - Links die Entitäten wählen (Pfeile + Enter), rechts die Liste; **Enter** auf
296
+ einer Zeile öffnet die Detailansicht, **Esc** schließt sie.
297
+ - Die Detailansicht zeigt die Felder **menschenlesbar** (deutsche Feldnamen,
298
+ Datumsangaben als TT.MM.JJJJ, ja/nein, verschachtelte Strukturen als Pfad wie
299
+ *Adressen › Rechnungsadresse › Ort*). Mit **j** wechselt man jederzeit auf das
300
+ **rohe JSON** der API und zurück.
301
+ - Tastenkürzel: **Tab** Fokus wechseln · **r** aktualisieren · **n** neuer
302
+ Auftrag · **m** mehr laden · **/** suchen · **q** beenden (immer als Leiste
303
+ unten sichtbar).
304
+ - **Paginierung**: Jede Liste lädt zunächst eine volle API-Seite (250
305
+ Datensätze — das Server-Maximum pro Request). Scrollt man auf die letzte
306
+ Zeile (oder drückt **m**), wird automatisch der nächste Schwung nachgeladen;
307
+ die Cursor-Position bleibt erhalten. Die Statuszeile zeigt den Stand, z.B.
308
+ `250 von 1234 Rechnungen — ans Ende scrollen oder m lädt mehr`.
309
+ - **Suchen** (**/**): öffnet eine Suchleiste über der Tabelle. **Tippen
310
+ filtert sofort** die bereits geladenen Zeilen (clientseitig, über alle
311
+ sichtbaren Spalten). **Enter sucht über die API** — bei Kontakten per Name
312
+ bzw. E-Mail (enthält die Eingabe ein `@`, wird die E-Mail-Suche verwendet;
313
+ min. 3 Zeichen), bei Artikeln per Volltextsuche. In den API-Treffern kann
314
+ anschließend weiter lokal gefiltert werden. **Esc** schließt die Suche und
315
+ stellt die normale Liste wieder her.
316
+ - **Auftrag anlegen** (**n**): Kunde per Namenssuche wählen, Artikel suchen und
317
+ mit Menge und (editierbarem) Netto-Einzelpreis als Positionen hinzufügen —
318
+ der Preis wird aus dem Artikel vorbelegt und kann vor dem Hinzufügen
319
+ überschrieben werden. Optional Einleitungs- und Schlusstext eintragen, dann
320
+ *„Auftrag anlegen"* — der Auftrag wird als **Entwurf** gespeichert und die
321
+ Auftragsliste geöffnet. Während Suchen und Anlegen laufen, zeigt das Formular
322
+ eine Lade-Animation. Finalisieren/Versenden bleibt bewusst der Lexware-UI
323
+ vorbehalten.
324
+ - Firmenname oben = Verbindungstest; Fehler aus der API werden als Hinweis und
325
+ in der Statuszeile angezeigt (nie verschluckt).
326
+
327
+ Die TUI startet **nur im interaktiven Terminal**. Sobald `lxw` mit
328
+ Argumenten aufgerufen wird oder die Ausgabe in eine Pipe/Datei geht, verhält es
329
+ sich unverändert wie die CLI — Skripte und `… | jq` bleiben also unberührt.
330
+
331
+ Technisch spricht die TUI ausschließlich den UI-freien Core (`lxw_cli.core`)
332
+ — exakt dieselbe API wie CLI und MCP-Server.
333
+
334
+ ## Claude-Integration (MCP-Server)
335
+
336
+ Das CLI bringt einen eingebauten MCP-Server mit, mit dem **Claude Code** (und Claude Desktop) deine Lexware-Daten direkt abfragen kann.
337
+
338
+ ### Setup in einem Schritt
339
+
340
+ ```bash
341
+ lxw mcp install-claude
342
+ ```
343
+
344
+ Das registriert den Server bei Claude Code (Scope `user`, also für alle Projekte). Der API-Key wird dabei **nicht** an Claude übergeben — der Server liest ihn selbst aus `~/.config/lexware/.env` (chmod 600); falls er dort noch fehlt, legt `install-claude` ihn einmalig ab. Danach:
345
+
346
+ ```bash
347
+ claude mcp list # 'lexware' muss in der Liste erscheinen
348
+ ```
349
+
350
+ Öffne Claude Code in einem Projekt und frag z.B.:
351
+
352
+ > *"Wie viele offene Rechnungen habe ich?"*
353
+ > *"Lade die PDF von Rechnung FB2600682 herunter."*
354
+ > *"Zeig mir alle Kunden, deren Name mit 'A' anfängt."*
355
+
356
+ Claude erkennt die Tools automatisch und ruft sie auf.
357
+
358
+ ### Verfügbare MCP-Tools
359
+
360
+ 26 Tools mit identischem Verhalten wie die CLI-Befehle:
361
+
362
+ - **Lesen**: `profile`, `list_invoices`, `get_invoice`, `download_invoice_pdf`, `list_contacts`, `get_contact`, `list_vouchers`, `get_voucher`, `list_articles`, `get_article`, `list_quotations`, `get_quotation`, `download_quotation_pdf`, `list_order_confirmations`, `get_order_confirmation`, `download_order_confirmation_pdf`, `list_delivery_notes`, `get_delivery_note`, `download_delivery_note_pdf`
363
+ - **Belege als Draft anlegen**: `create_invoice_draft`, `create_voucher_draft`, `create_quotation_draft`, `create_order_confirmation_draft`, `create_delivery_note_draft`
364
+ - **Stammdaten anlegen** (kein Draft): `create_contact`, `create_article`
365
+
366
+ Alle document-Tools (`get_*`, `download_*_pdf`) akzeptieren UUID **oder** Belegnummer (z.B. `FB2600682`). PDFs landen in `~/Downloads/lexware/`.
367
+
368
+ Die `list_*`-Tools bieten dieselben Optionen wie die CLI:
369
+
370
+ - `limit` begrenzt die Trefferzahl; `limit=0` lädt **alle** (paginiert intern).
371
+ - `list_articles` hat `search` für die Volltextsuche (Bezeichnung/Beschreibung/Teil-Artikelnummer) zusätzlich zum exakten `article_number`.
372
+ - `list_contacts` filtert mit `customer` / `vendor` nach Rolle.
373
+ - Belege-Tools (`list_invoices`, `list_vouchers`, `list_quotations`, `list_delivery_notes`) und `list_contacts` blenden archivierte standardmäßig aus; `include_archived=true` zeigt sie.
374
+
375
+ ### Weitere mcp-Befehle
376
+
377
+ ```bash
378
+ lxw mcp status # zeigt aktuelle Registrierung
379
+ lxw mcp install-claude --force # Re-Install (z.B. nach API-Key-Wechsel)
380
+ lxw mcp uninstall-claude # entfernen
381
+ lxw mcp serve # läuft direkt — wird von Claude Code intern aufgerufen
382
+ ```
383
+
384
+ ## Out of Scope (v1)
385
+
386
+ Bewusst nicht enthalten:
387
+
388
+ - Finalisierung von Rechnungen (`/finalize`)
389
+ - Stornierungen / Credit Notes als eigene Workflows
390
+ - Webhooks / Event-Subscriptions
391
+ - Multi-Account-Profile (nutze stattdessen verschiedene `.env`-Dateien)
392
+
393
+ ## Entwicklung
394
+
395
+ ```bash
396
+ uv pip install -e ".[dev]"
397
+ pytest -v
398
+ ruff check src tests
399
+ ```
400
+
401
+ ## Lizenz
402
+
403
+ MIT