# Kassekladde (Supplier Invoices) - BMC Hub ## Overview BMC Hub's kassekladde module enables management of supplier invoices (incoming invoices that the company must pay) with full integration to e-conomic accounting system via the journals/vouchers API. ## Features ✅ **Complete CRUD Operations** - Create, view, update, and delete supplier invoices - Multi-line invoice support with VAT breakdown - Vendor linking and automatic creation in e-conomic ✅ **Approval Workflow** - Pending → Approved → Sent to e-conomic → Paid - Approval tracking with user and timestamp ✅ **e-conomic Integration** - Automatic supplier matching and creation - Journal/voucher posting to kassekladde - PDF attachment upload to vouchers - Configurable journal number and default accounts ✅ **VAT Handling** - Support for multiple VAT codes (I25, I0, IY25, etc.) - Automatic VAT calculation per line - VAT breakdown in e-conomic entries ✅ **Nordic Top UI** - Modern, clean design - Real-time statistics dashboard - Filter and search functionality - Responsive mobile support ## Architecture ### Database Schema **Main Tables:** - `supplier_invoices` - Invoice headers with e-conomic tracking - `supplier_invoice_lines` - Line items with VAT and account details - `supplier_invoice_settings` - System configuration - `vendors` - Supplier information with e-conomic IDs **Views:** - `overdue_supplier_invoices` - All overdue unpaid invoices - `pending_economic_sync` - Approved invoices ready for e-conomic ### Backend Structure ``` app/ billing/ backend/ supplier_invoices.py # FastAPI router with endpoints frontend/ supplier_invoices.html # Nordic Top UI views.py # Frontend routes services/ economic_service.py # e-conomic API integration ``` ### API Endpoints **CRUD Operations:** - `GET /api/v1/supplier-invoices` - List invoices with filters - `GET /api/v1/supplier-invoices/{id}` - Get invoice details - `POST /api/v1/supplier-invoices` - Create new invoice - `PUT /api/v1/supplier-invoices/{id}` - Update invoice - `DELETE /api/v1/supplier-invoices/{id}` - Delete invoice **Workflow Actions:** - `POST /api/v1/supplier-invoices/{id}/approve` - Approve invoice - `POST /api/v1/supplier-invoices/{id}/send-to-economic` - Send to e-conomic **Statistics:** - `GET /api/v1/supplier-invoices/stats/overview` - Payment overview - `GET /api/v1/supplier-invoices/stats/by-vendor` - Stats by vendor **e-conomic Integration:** - `GET /api/v1/supplier-invoices/economic/journals` - Available kassekladder ## Installation & Setup ### 1. Database Migration Run the migration to create tables: ```bash # Execute migration SQL psql -U bmc_hub -d bmc_hub < migrations/008_supplier_invoices.sql ``` Or via Docker: ```bash docker-compose exec postgres psql -U bmc_hub -d bmc_hub < /app/migrations/008_supplier_invoices.sql ``` ### 2. Configure e-conomic Credentials Add to `.env` file: ```env # e-conomic Integration ECONOMIC_API_URL=https://restapi.e-conomic.com ECONOMIC_APP_SECRET_TOKEN=your_app_secret_token ECONOMIC_AGREEMENT_GRANT_TOKEN=your_agreement_grant_token # Safety switches (ALWAYS start with these enabled) ECONOMIC_READ_ONLY=true ECONOMIC_DRY_RUN=true ``` ### 3. Configure Default Settings The default journal number and accounts can be configured via database: ```sql -- Update default kassekladde number UPDATE supplier_invoice_settings SET setting_value = '1' WHERE setting_key = 'economic_default_journal'; -- Update default expense account UPDATE supplier_invoice_settings SET setting_value = '5810' WHERE setting_key = 'economic_default_contra_account'; ``` ### 4. Restart Application ```bash docker-compose restart api ``` ## Usage Guide ### Creating a Supplier Invoice 1. Navigate to `/billing/supplier-invoices` 2. Click "Ny Faktura" button 3. Fill in required fields: - Invoice number (from supplier) - Vendor (select from dropdown) - Invoice date - Total amount (incl. VAT) 4. Add line items with: - Description - Quantity & price - VAT code (25%, 0%, reverse charge, etc.) 5. Click "Gem" to save ### Approval Workflow **Status Flow:** ``` pending → approved → sent_to_economic → paid ``` **Steps:** 1. Invoice created → Status: `pending` 2. Review and approve → Status: `approved` 3. Send to e-conomic → Status: `sent_to_economic` (voucher created) 4. Mark as paid → Status: `paid` ### Sending to e-conomic **Prerequisites:** - Invoice must be `approved` - Vendor must exist (auto-created if needed) - At least one line item **Process:** 1. Click "Send til e-conomic" button 2. System will: - Check/create vendor in e-conomic - Build VAT breakdown from lines - Create journal voucher entry - Upload PDF attachment (if available) - Update invoice with voucher number **Result:** - Voucher created in e-conomic kassekladde - Invoice status → `sent_to_economic` - Voucher number stored for reference ## e-conomic Integration Details ### Safety Modes **READ_ONLY Mode** (default: `true`) - Blocks ALL write operations to e-conomic - Only GET requests allowed - Use for testing API connection **DRY_RUN Mode** (default: `true`) - Logs all operations but doesn't send to e-conomic - Full payload preview in logs - Safe for development/testing **Production Mode** (both `false`) - Actually sends data to e-conomic - ⚠️ **Use with caution!** - Always test with dry-run first ### Journal Voucher Structure e-conomic vouchers use this format: ```json { "accountingYear": {"year": "2025"}, "journal": {"journalNumber": 1}, "entries": { "supplierInvoices": [ { "supplier": {"supplierNumber": 123}, "amount": 1250.00, "contraAccount": {"accountNumber": 5810}, "currency": {"code": "DKK"}, "date": "2025-12-06", "dueDate": "2026-01-05", "supplierInvoiceNumber": "INV-12345", "text": "Invoice description", "contraVatAccount": {"vatCode": "I25"}, "contraVatAmount": 250.00 } ] } } ``` ### VAT Code Mapping | VAT Code | Description | Rate | Use Case | |----------|-------------|------|----------| | `I25` | Indenlandsk købsmoms 25% | 25% | Standard Danish purchases | | `I0` | Momsfri køb | 0% | VAT exempt | | `IY25` | Omvendt betalingspligt 25% | 25% | Reverse charge | | `IYEU` | Omvendt EU | 0% | EU reverse charge | | `IVEU` | Erhvervelse EU | 25% | EU acquisition | ### Account Number Mapping Default expense accounts (can be customized per line): - `5810` - Drift og materialer (default) - `5820` - IT og software - `5830` - Telefoni og internet - `5840` - Kontorartikler - `6000` - Løn og honorarer ## Development Guide ### Adding New Features **1. Backend Endpoint:** ```python # app/billing/backend/supplier_invoices.py @router.post("/supplier-invoices/{invoice_id}/custom-action") async def custom_action(invoice_id: int): # Your logic here return {"success": True} ``` **2. Frontend Integration:** ```javascript // supplier_invoices.html async function customAction(invoiceId) { const response = await fetch(`/api/v1/supplier-invoices/${invoiceId}/custom-action`, { method: 'POST' }); // Handle response } ``` ### Testing e-conomic Integration **1. Test Connection:** ```python from app.services.economic_service import get_economic_service economic = get_economic_service() result = await economic.test_connection() # Should return True if credentials are valid ``` **2. Test Dry-Run Mode:** ```bash # In .env ECONOMIC_READ_ONLY=false ECONOMIC_DRY_RUN=true ``` Then create and approve an invoice, send to e-conomic. Check logs for full payload without actually posting. **3. Production Test:** ```bash # WARNING: This will create real data in e-conomic! ECONOMIC_READ_ONLY=false ECONOMIC_DRY_RUN=false ``` Start with a small test invoice to verify everything works. ## Troubleshooting ### Issue: "No journals found" **Solution:** Check e-conomic credentials and ensure user has access to journals/kassekladder. ### Issue: "Supplier not found in e-conomic" **Solution:** System will auto-create supplier if `ECONOMIC_DRY_RUN=false`. Verify vendor name is correct. ### Issue: "VAT validation failed" **Solution:** Ensure VAT codes match e-conomic settings. Check `vat_code` in line items (I25, I0, etc.). ### Issue: "Voucher creation failed" **Solution:** 1. Check e-conomic API logs in application logs 2. Verify journal number exists in e-conomic 3. Ensure all required fields are present (supplier, amount, date) 4. Check contra account number is valid ## Integration with OmniSync This module is based on OmniSync's proven kassekladde implementation with the following enhancements: - ✅ PostgreSQL instead of SQLite - ✅ Nordic Top design instead of custom CSS - ✅ Integrated with BMC Hub's vendor system - ✅ Simplified approval workflow - ✅ Better error handling and logging ## References - **e-conomic API Docs:** https://restdocs.e-conomic.com/ - **Journals API:** https://restdocs.e-conomic.com/#journals - **Vouchers API:** https://restdocs.e-conomic.com/#vouchers - **Suppliers API:** https://restdocs.e-conomic.com/#suppliers ## Support For issues or questions: 1. Check application logs: `docker-compose logs -f api` 2. Review e-conomic API response in logs 3. Test with DRY_RUN mode first 4. Contact system administrator --- **Last Updated:** December 6, 2025 **Version:** 1.0.0 **Maintained by:** BMC Networks Development Team