name: bewirtungsbeleg description: 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.
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.ymland 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.pngfor reference
- Place your signature image as
-
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
gesamtbetragin the JSON should be the FINAL total INCLUDING the tip - The
trinkgeldfield 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)
- 10-11 digits, often with slashes:
-
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:
-
Bewirtete Personen (Guests): Ask "Wer waren die bewirteten Personen?"
- Collect full names
- Company names are OPTIONAL - only ask if relevant or if the user mentions them
- CRITICAL: THe host has to be added to the guest list as well
-
Anlass (Occasion): Ask "Was war der Anlass der Bewirtung?"
- The occasion must clearly demonstrate business context
- Vague answers like "Geschäftsessen" are NOT sufficient for tax purposes
- Guide the user to provide specific details, for example:
- "Projektbesprechung zur Implementierung des CRM-Systems mit Kunde XY"
- "Vertragsverhandlung über Cloud-Migration-Projekt"
- "Akquisegespräch mit potenziellem Neukunden"
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
- Receipt shows: "Rechnung: 102,00 €"
- Handwritten on receipt: "Trinkgeld: 10,00 €"
- Your JSON should be:
{ "gesamtbetrag": 112.00, // 102 + 10 "trinkgeld": 10.00 }
Example 2: Receipt WITHOUT tip notation, user confirms tip
- Receipt shows: "Summe: 102,00 €"
- User says: "Yes, I gave 10 euros tip"
- Your JSON should be:
{ "gesamtbetrag": 112.00, // Receipt + tip "trinkgeld": 10.00 }
Example 3: No tip given
- Receipt shows: "Summe: 102,00 €"
- No tip notation, user confirms no tip
- Your JSON should be:
{ "gesamtbetrag": 102.00, "trinkgeld": 0.0 }
Important notes:
datum_bewirtung: Use the date from the receipt (Rechnungsdatum)ort_bewirtung: Extract the city from the restaurant addressgastgeber: You can omit this field - the script will automatically use the value from config.ymlgesamtbetrag: 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/receiptNote: The signature is automatically loaded from
assets/signature.png- no need to specify--signatureparameter -
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
--receiptparameter 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)