Bewirtungsbeleg Creator
This skill analyzes restaurant receipts and creates tax-compliant German Bewirtungsbeleg PDFs.
Setup
Before using this skill for the first time:
Configure your details:
cd skills/bewirtungsbeleg
cp config.example.yml config.yml
Edit config.yml and replace the placeholder with your information:
gastgeber: "Your Name / Your Company Name"
Add your signature:
- Place your signature image as
assets/signature.png
- See
assets/signature.example.png for reference
Install dependencies:
uv sync
The config file is gitignored to keep your personal information private when publishing this skill.
Workflow
Follow this exact sequence when the user provides a restaurant receipt:
Step 1: Analyze the Receipt
Extract the following information from the uploaded receipt image or PDF:
Required from receipt:
- Restaurant name and full address
- Date of the meal (Rechnungsdatum) - This will be used as "Datum der Bewirtung"
- Location/City - Extract from restaurant address, this will be used as "Ort der Bewirtung"
- Total amount including VAT (Gesamtbetrag/Bruttobetrag) - this is the only amount needed
- Receipt/register number (Registriernummer or Rechnungsnummer)
Check carefully for tip (Trinkgeld) on receipt:
- Look for any handwritten notes on the receipt mentioning "Trinkgeld", "Tip", "TG" or similar
- Check for a separate line item labeled "Trinkgeld" on the receipt
- Tips are often added by hand after the printed total
- If the receipt shows TWO totals, the difference is likely the tip
- Common patterns:
- Original receipt shows €102, handwritten note "Trinkgeld €10", final amount €112
- Receipt has printed "Summe: €102" and handwritten "Gesamt: €112"
Important about tips:
- If you see ANY indication of a tip on the receipt, extract that amount
- The
gesamtbetrag in the JSON should be the FINAL total INCLUDING the tip
- The
trinkgeld field should contain the tip amount separately
- If NO tip is visible, ask the user in Step 2
Optional from receipt:
- Tax ID or VAT ID (Steuer-Nr. or USt-IdNr.) of the restaurant
Note:
- The date and location from the receipt will be automatically used for the Bewirtungsbeleg
- You only need the total amount (Gesamtbetrag) - no need to split into net and VAT amounts
- The detailed itemization is on the original receipt which will be attached
Tax ID Format Recognition:
German tax IDs come in two formats:
Steuernummer (Tax Number):
- 10-11 digits, often with slashes:
133/8150/8159
- Or 13 digits without separators:
5133081508159
- Varies by Bundesland (federal state)
Umsatzsteuer-Identifikationsnummer (VAT ID):
- Always starts with "DE" followed by 9 digits
- Format:
DE123456789
- Used for EU business transactions
Important: If no tax ID is found on the receipt, leave the field blank in the generated PDF. This is acceptable for tax purposes.
Step 2: Gather Additional Information
Ask the user for information not available on the receipt, but only if not part of the prompt already:
Always required:
Ask ONLY if not found on receipt:
- Trinkgeld (Tip): If you did NOT find any indication of a tip on the receipt, ask "Wurde ein Trinkgeld gegeben? Falls ja, wie viel?"
- If user says no tip was given, set trinkgeld to 0 in the JSON
- If user provides a tip amount, add it to the receipt total for the final gesamtbetrag
Note: Date and location are automatically extracted from the receipt, so don't ask the user for these.
Step 3: Create JSON Data Structure
Prepare a JSON file with all collected information:
{
"datum_bewirtung": "DD.MM.YYYY", // Automatically from receipt date
"ort_bewirtung": "City name", // Automatically from restaurant address
"gastgeber": "Full Name", // Will use config.yml value if not provided in data
"gaeste": [
{
"name": "Full Name",
"unternehmen": "Company Name (optional)"
},
{
"name": "Another Person"
}
],
"anlass": "Detailed business occasion",
"restaurant_name": "Restaurant Name",
"restaurant_adresse": "Full Address",
"restaurant_steuernr": "Tax/VAT ID (optional)",
"gesamtbetrag": 156.90, // FINAL total INCLUDING tip (if any)
"trinkgeld": 10.00 // Tip amount separately, use 0.0 if no tip
}
CRITICAL - Understanding gesamtbetrag and trinkgeld:
Example 1: Receipt WITH tip notation
Example 2: Receipt WITHOUT tip notation, user confirms tip
Example 3: No tip given
Important notes:
datum_bewirtung: Use the date from the receipt (Rechnungsdatum)
ort_bewirtung: Extract the city from the restaurant address
gastgeber: You can omit this field - the script will automatically use the value from config.yml
gesamtbetrag: ALWAYS the final total INCLUDING tip (if any)
trinkgeld: The tip amount separately; use 0.0 if no tip was given
- Net amount and VAT are NOT needed - they're already on the restaurant receipt
Step 4: Generate the PDF
Save the JSON data to a temporary file
Save the uploaded original receipt to a temporary file (keep original format - PDF or image)
Execute the PDF generation script:
python3 scripts/create_bewirtungsbeleg.py \
--json data.json \
--output bewirtungsbeleg.pdf \
--receipt /path/to/uploaded/receipt
Note: The signature is automatically loaded from assets/signature.png - no need to specify --signature parameter
The script will automatically:
- Convert the receipt image to PDF if needed
- Apply EXIF orientation correction to ensure the image is correctly oriented
- Add the original receipt as the first page(s)
- Create the Bewirtungsbeleg with the attached signature pre-filled
- Add the signed Bewirtungsbeleg as the last page
- Result: 2-page PDF (page 1 = original receipt, page 2 = signed Bewirtungsbeleg)
Move the generated PDF to /mnt/user-data/outputs/
Provide the download link to the user
Important:
- The
--receipt parameter must point to the uploaded receipt file from /mnt/user-data/uploads
- Supported formats: PNG, JPEG, JPG, GIF, BMP, WebP, TIFF, TIF, HEIC, HEIF, and PDF
- All color modes supported: RGB, RGBA, CMYK, Grayscale, Palette, LAB, YCbCr, HSV
- The receipt can be a photo, scan, or PDF
- The signature is automatically included - stored in
assets/signature.png
- The final PDF will have 2+ pages: original receipt first, then the signed Bewirtungsbeleg
Step 5: Provide Instructions
After creating the PDF, inform the user:
Document structure:
- Page 1: Original restaurant receipt
- Page 2: Signed Bewirtungsbeleg (with automatic signature)
What's already done:
- ✅ Signature is already included automatically
- ✅ Original receipt is attached as first page
- ✅ Date and location are filled in
User actions:
- Print the complete PDF and file for tax records
- No manual signature needed - it's already signed!
Tax note:
- Business meal expenses are only 70% tax-deductible in Germany
Important Notes
Tax Compliance Requirements
- The receipt must be machine-generated (not handwritten)
- Must contain a receipt/register number
- Itemization of food/beverages is required
- For receipts over €250, the company name must be on the receipt
- The occasion must clearly demonstrate business connection
- Tax ID (Steuer-Nr. or USt-IdNr.) is helpful but not mandatory if missing
For detailed tax requirements, see references/steuerliche_anforderungen.md.
Common Issues
Insufficient occasion description:
- ❌ Bad: "Geschäftsessen", "Besprechung"
- ✅ Good: "Projektbesprechung CRM-Implementation mit XY GmbH", "Vertragsverhandlung Cloud-Migration"
Missing information:
- If critical information is missing from the receipt (amounts, itemization), inform the user and explain what's needed
- If the tax ID is missing, that's acceptable - the field will be left blank on the Bewirtungsbeleg
Tips (Trinkgeld):
- Tips must be noted separately as they're usually not on the receipt
- Should be noted on the receipt and signed by the restaurant
- Must be included in the Bewirtungsbeleg
Resources
Scripts
scripts/create_bewirtungsbeleg.py - Generates the PDF from JSON data, merges with original receipt, and adds signature
References
references/steuerliche_anforderungen.md - Complete German tax requirements for Bewirtungsbelege
Assets
assets/signature.png - (automatically included in generated PDFs)
1---2name: bewirtungsbeleg3description: Creates German tax-compliant entertainment expense receipts (Bewirtungsbelege) from restaurant receipts with automatic signature and original receipt attachment. The generated PDF contains the original receipt as page 1 and the signed Bewirtungsbeleg as page 2. Use when the user uploads a restaurant receipt/bill and wants to create a formal Bewirtungsbeleg PDF for German tax purposes, or when they mention "Bewirtungsbeleg", "Geschäftsessen", "steuerlich absetzbar", or similar business meal expense documentation needs.4---5
6# Bewirtungsbeleg Creator
7
8This skill analyzes restaurant receipts and creates tax-compliant German Bewirtungsbeleg PDFs.
9
10## Setup
11
12Before using this skill for the first time:
13
141. **Configure your details:**
15 ```bash
16 cd skills/bewirtungsbeleg
17 cp config.example.yml config.yml
18 ```
19
202. **Edit `config.yml`** and replace the placeholder with your information:
21 ```yaml
22 gastgeber: "Your Name / Your Company Name"
23 ```
24
253. **Add your signature:**
26 - Place your signature image as `assets/signature.png`
27 - See `assets/signature.example.png` for reference
28
294. **Install dependencies:**
30 ```bash
31 uv sync
32 ```
33
34The config file is gitignored to keep your personal information private when publishing this skill.
35
36## Workflow
37
38Follow this exact sequence when the user provides a restaurant receipt:
39
40### Step 1: Analyze the Receipt
41
42Extract the following information from the uploaded receipt image or PDF:
43
44**Required from receipt:**
45- Restaurant name and full address
46- **Date of the meal (Rechnungsdatum)** - This will be used as "Datum der Bewirtung"
47- **Location/City** - Extract from restaurant address, this will be used as "Ort der Bewirtung"
48- Total amount including VAT (Gesamtbetrag/Bruttobetrag) - this is the only amount needed
49- Receipt/register number (Registriernummer or Rechnungsnummer)
50
51**Check carefully for tip (Trinkgeld) on receipt:**
52- Look for any handwritten notes on the receipt mentioning "Trinkgeld", "Tip", "TG" or similar
53- Check for a separate line item labeled "Trinkgeld" on the receipt
54- Tips are often added by hand after the printed total
55- If the receipt shows TWO totals, the difference is likely the tip
56- Common patterns:
57 - Original receipt shows €102, handwritten note "Trinkgeld €10", final amount €112
58 - Receipt has printed "Summe: €102" and handwritten "Gesamt: €112"
59
60**Important about tips:**
61- If you see ANY indication of a tip on the receipt, extract that amount
62- The `gesamtbetrag` in the JSON should be the FINAL total INCLUDING the tip
63- The `trinkgeld` field should contain the tip amount separately
64- If NO tip is visible, ask the user in Step 2
65
66**Optional from receipt:**
67- Tax ID or VAT ID (Steuer-Nr. or USt-IdNr.) of the restaurant
68
69**Note:**
70- The date and location from the receipt will be automatically used for the Bewirtungsbeleg
71- You only need the total amount (Gesamtbetrag) - no need to split into net and VAT amounts
72- The detailed itemization is on the original receipt which will be attached
73
74**Tax ID Format Recognition:**
75
76German tax IDs come in two formats:
77
781. **Steuernummer (Tax Number)**:
79 - 10-11 digits, often with slashes: `133/8150/8159`
80 - Or 13 digits without separators: `5133081508159`
81 - Varies by Bundesland (federal state)
82
832. **Umsatzsteuer-Identifikationsnummer (VAT ID)**:
84 - Always starts with "DE" followed by 9 digits
85 - Format: `DE123456789`
86 - Used for EU business transactions
87
88**Important:** If no tax ID is found on the receipt, leave the field blank in the generated PDF. This is acceptable for tax purposes.
89
90### Step 2: Gather Additional Information
91
92Ask the user for information not available on the receipt, but only if not part of the prompt already:
93
94**Always required:**
95- **Bewirtete Personen (Guests):** Ask "Wer waren die bewirteten Personen?"
96 - Collect full names
97 - Company names are OPTIONAL - only ask if relevant or if the user mentions them
98 - **CRITICAL**: THe host has to be added to the guest list as well
99
100- **Anlass (Occasion):** Ask "Was war der Anlass der Bewirtung?"
101 - The occasion must clearly demonstrate business context
102 - Vague answers like "Geschäftsessen" are NOT sufficient for tax purposes
103 - Guide the user to provide specific details, for example:
104 - "Projektbesprechung zur Implementierung des CRM-Systems mit Kunde XY"
105 - "Vertragsverhandlung über Cloud-Migration-Projekt"
106 - "Akquisegespräch mit potenziellem Neukunden"
107
108**Ask ONLY if not found on receipt:**
109- **Trinkgeld (Tip):** If you did NOT find any indication of a tip on the receipt, ask "Wurde ein Trinkgeld gegeben? Falls ja, wie viel?"
110 - If user says no tip was given, set trinkgeld to 0 in the JSON
111 - If user provides a tip amount, add it to the receipt total for the final gesamtbetrag
112
113**Note:** Date and location are automatically extracted from the receipt, so don't ask the user for these.
114
115### Step 3: Create JSON Data Structure
116
117Prepare a JSON file with all collected information:
118
119```json
120{
121 "datum_bewirtung": "DD.MM.YYYY", // Automatically from receipt date
122 "ort_bewirtung": "City name", // Automatically from restaurant address
123 "gastgeber": "Full Name", // Will use config.yml value if not provided in data
124 "gaeste": [
125 {
126 "name": "Full Name",
127 "unternehmen": "Company Name (optional)"
128 },
129 {
130 "name": "Another Person"
131 }
132 ],
133 "anlass": "Detailed business occasion",
134 "restaurant_name": "Restaurant Name",
135 "restaurant_adresse": "Full Address",
136 "restaurant_steuernr": "Tax/VAT ID (optional)",
137 "gesamtbetrag": 156.90, // FINAL total INCLUDING tip (if any)
138 "trinkgeld": 10.00 // Tip amount separately, use 0.0 if no tip
139}
140```
141
142**CRITICAL - Understanding gesamtbetrag and trinkgeld:**
143
144**Example 1: Receipt WITH tip notation**
145- Receipt shows: "Rechnung: 102,00 €"
146- Handwritten on receipt: "Trinkgeld: 10,00 €"
147- Your JSON should be:
148 ```json
149 {
150 "gesamtbetrag": 112.00, // 102 + 10
151 "trinkgeld": 10.00
152 }
153 ```
154
155**Example 2: Receipt WITHOUT tip notation, user confirms tip**
156- Receipt shows: "Summe: 102,00 €"
157- User says: "Yes, I gave 10 euros tip"
158- Your JSON should be:
159 ```json
160 {
161 "gesamtbetrag": 112.00, // Receipt + tip
162 "trinkgeld": 10.00
163 }
164 ```
165
166**Example 3: No tip given**
167- Receipt shows: "Summe: 102,00 €"
168- No tip notation, user confirms no tip
169- Your JSON should be:
170 ```json
171 {
172 "gesamtbetrag": 102.00,
173 "trinkgeld": 0.0
174 }
175 ```
176
177**Important notes:**
178- `datum_bewirtung`: Use the date from the receipt (Rechnungsdatum)
179- `ort_bewirtung`: Extract the city from the restaurant address
180- `gastgeber`: You can omit this field - the script will automatically use the value from config.yml
181- `gesamtbetrag`: ALWAYS the final total INCLUDING tip (if any)
182- `trinkgeld`: The tip amount separately; use 0.0 if no tip was given
183- Net amount and VAT are NOT needed - they're already on the restaurant receipt
184
185### Step 4: Generate the PDF
186
1871. Save the JSON data to a temporary file
1882. Save the uploaded original receipt to a temporary file (keep original format - PDF or image)
1893. Execute the PDF generation script:
190 ```bash
191 python3 scripts/create_bewirtungsbeleg.py \
192 --json data.json \
193 --output bewirtungsbeleg.pdf \
194 --receipt /path/to/uploaded/receipt
195 ```
196
197 **Note:** The signature is automatically loaded from `assets/signature.png` - no need to specify `--signature` parameter
198
1994. The script will automatically:
200 - Convert the receipt image to PDF if needed
201 - Apply EXIF orientation correction to ensure the image is correctly oriented
202 - Add the original receipt as the first page(s)
203 - Create the Bewirtungsbeleg with the attached signature pre-filled
204 - Add the signed Bewirtungsbeleg as the last page
205 - Result: 2-page PDF (page 1 = original receipt, page 2 = signed Bewirtungsbeleg)
206
2075. Move the generated PDF to `/mnt/user-data/outputs/`
2086. Provide the download link to the user
209
210**Important:**
211- The `--receipt` parameter must point to the uploaded receipt file from `/mnt/user-data/uploads`
212- **Supported formats**: PNG, JPEG, JPG, GIF, BMP, WebP, TIFF, TIF, HEIC, HEIF, and PDF
213- **All color modes supported**: RGB, RGBA, CMYK, Grayscale, Palette, LAB, YCbCr, HSV
214- The receipt can be a photo, scan, or PDF
215- The signature is automatically included - stored in `assets/signature.png`
216- The final PDF will have 2+ pages: original receipt first, then the signed Bewirtungsbeleg
217
218### Step 5: Provide Instructions
219
220After creating the PDF, inform the user:
221
222**Document structure:**
223- Page 1: Original restaurant receipt
224- Page 2: Signed Bewirtungsbeleg (with automatic signature)
225
226**What's already done:**
227- ✅ Signature is already included automatically
228- ✅ Original receipt is attached as first page
229- ✅ Date and location are filled in
230
231**User actions:**
232- Print the complete PDF and file for tax records
233- No manual signature needed - it's already signed!
234
235**Tax note:**
236- Business meal expenses are only 70% tax-deductible in Germany
237
238## Important Notes
239
240### Tax Compliance Requirements
241
242- The receipt must be machine-generated (not handwritten)
243- Must contain a receipt/register number
244- Itemization of food/beverages is required
245- For receipts over €250, the company name must be on the receipt
246- The occasion must clearly demonstrate business connection
247- Tax ID (Steuer-Nr. or USt-IdNr.) is helpful but not mandatory if missing
248
249For detailed tax requirements, see `references/steuerliche_anforderungen.md`.
250
251### Common Issues
252
253**Insufficient occasion description:**
254- ❌ Bad: "Geschäftsessen", "Besprechung"
255- ✅ Good: "Projektbesprechung CRM-Implementation mit XY GmbH", "Vertragsverhandlung Cloud-Migration"
256
257**Missing information:**
258- If critical information is missing from the receipt (amounts, itemization), inform the user and explain what's needed
259- If the tax ID is missing, that's acceptable - the field will be left blank on the Bewirtungsbeleg
260
261**Tips (Trinkgeld):**
262- Tips must be noted separately as they're usually not on the receipt
263- Should be noted on the receipt and signed by the restaurant
264- Must be included in the Bewirtungsbeleg
265
266## Resources
267
268### Scripts
269- `scripts/create_bewirtungsbeleg.py` - Generates the PDF from JSON data, merges with original receipt, and adds signature
270
271### References
272- `references/steuerliche_anforderungen.md` - Complete German tax requirements for Bewirtungsbelege
273
274### Assets
275- `assets/signature.png` - (automatically included in generated PDFs)