# 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
