feat(T06): Verkaufsmodul + Rechtsdokumente + DATEV-Export + Sales UI
This commit is contained in:
+42
-27
@@ -1,37 +1,52 @@
|
||||
# Current Status
|
||||
|
||||
## T05: Dateiablage pro Fahrzeug + File UI
|
||||
## T06: Verkaufsmodul + Rechtsdokumente + DATEV-Export + Sales UI
|
||||
|
||||
**Status:** COMPLETED
|
||||
|
||||
### Backend
|
||||
- ✅ File model (app/models/file.py) - UUID PK, vehicle_id FK, all fields
|
||||
- ✅ File schemas (app/schemas/file.py) - FileUploadResponse, FileResponse, FileListResponse, FileDeleteResponse
|
||||
- ✅ File service (app/services/file_service.py) - upload, get, list, delete, validate_mime_type, validate_file_size
|
||||
- ✅ Thumbnail utils (app/utils/thumbnails.py) - 200x200 thumbnails via Pillow for jpg/png/webp
|
||||
- ✅ Files router (app/routers/files.py) - GET/POST/GET/DELETE endpoints registered in main.py
|
||||
- ✅ Backend tests (tests/test_files.py) - 43 tests, all passing, 82% coverage
|
||||
- ✅ Sale model (app/models/sale.py) - UUID PK, vehicle_id FK, buyer_contact_id FK, seller_contact_id FK nullable, sale_price DECIMAL, sale_date, status enum, is_gwg BOOLEAN, contract_pdf_path
|
||||
- ✅ DATEVExport model (app/models/datev_export.py) - UUID PK, start_date, end_date, file_path, total_amount, created_at
|
||||
- ✅ Sale schemas (app/schemas/sale.py) - SaleCreate, SaleUpdate, SaleResponse, SaleListResponse, ContractResponse, UstIdVerifyResponse
|
||||
- ✅ DATEV schemas (app/schemas/datev.py) - DATEVExportCreate, DATEVExportResponse, DATEVExportListResponse
|
||||
- ✅ Sale service (app/services/sale_service.py) - create_sale, get_sale, list_sales, update_sale, cancel_sale, delete_sale, regenerate_contract_pdf, verify_ust_id
|
||||
- ✅ DATEV service (app/services/datev_service.py) - create_export, list_exports, get_export_csv
|
||||
- ✅ Contract PDF utils (app/utils/contract_pdf.py) - HTML template with WeasyPrint, GwG-Klausel, USt-IdNr. field, async via asyncio.to_thread
|
||||
- ✅ DATEV CSV utils (app/utils/datev.py) - Buchungsstapel format: Datum, Konto, Gegenkonto, Betrag, Belegfeld, Buchungstext
|
||||
- ✅ Sales router (app/routers/sales.py) - GET/POST/PUT/DELETE /sales, POST/GET /sales/:id/contract, POST /sales/:id/verify-ust-id
|
||||
- ✅ DATEV router (app/routers/datev.py) - POST /datev/export, GET /datev/exports, GET /datev/exports/:id/download
|
||||
- ✅ Config updated - BZST_API_ENABLED=False, WEASYPRINT_OUTPUT_DIR
|
||||
- ✅ main.py updated - sales + datev routers registered
|
||||
- ✅ requirements.txt - weasyprint>=62.0 added
|
||||
- ✅ models/__init__.py - all models imported for Base.metadata registration
|
||||
- ✅ Backend tests (tests/test_sales.py, tests/test_datev.py) - 34 tests, all passing
|
||||
|
||||
### Frontend
|
||||
- ✅ Files lib (lib/files.ts) - API functions, types, utilities
|
||||
- ✅ FileUpload component - Drag-and-drop multi-file upload
|
||||
- ✅ FileList component - File list with thumbnails, delete confirm dialog
|
||||
- ✅ FileGallery component - Gallery view for vehicle images
|
||||
- ✅ FilePreview component - File preview modal
|
||||
- ✅ Frontend tests (tests/files.test.tsx) - 25 tests, all passing
|
||||
- ✅ TypeScript build check passes
|
||||
- ✅ Sales lib (lib/sales.ts) - listSales, getSale, createSale, updateSale, deleteSale, regenerateContract, verifyUstId
|
||||
- ✅ DATEV lib (lib/datev.ts) - createDatevExport, listDatevExports, getDatevDownloadUrl
|
||||
- ✅ SaleList component - Sales table with status + date range filters, pagination
|
||||
- ✅ SaleForm component - Sale create form with vehicle select, buyer input, price, GwG toggle
|
||||
- ✅ ContractPreview component - PDF embed preview, regenerate button, download link
|
||||
- ✅ DatevExport component - Date range picker, export list table, CSV download
|
||||
- ✅ Pages: verkauf/page.tsx, verkauf/[id]/page.tsx, verkauf/neu/page.tsx
|
||||
- ✅ Frontend tests (tests/sales.test.tsx, tests/datev.test.tsx) - 16 tests, all passing
|
||||
|
||||
### Acceptance Criteria Met
|
||||
- ✅ GET /api/v1/vehicles/:id/files → 200 + list of files
|
||||
- ✅ POST /api/v1/vehicles/:id/files mit multipart image → 201 + file object
|
||||
- ✅ POST /api/v1/vehicles/:id/files mit >20MB file → 413
|
||||
- ✅ POST /api/v1/vehicles/:id/files mit invalid MIME type → 422
|
||||
- ✅ GET /api/v1/vehicles/:id/files/:fileId → 200 + file content (download)
|
||||
- ✅ DELETE /api/v1/vehicles/:id/files/:fileId → 200 + file deleted
|
||||
- ✅ File gespeichert in uploads_data volume, path in DB gespeichert
|
||||
- ✅ Image files → Thumbnail generiert (200x200)
|
||||
- ✅ Frontend File Upload akzeptiert Drag-and-Drop multi-file
|
||||
- ✅ Frontend File List zeigt Thumbnails für images
|
||||
- ✅ Frontend File Delete zeigt Confirm Dialog
|
||||
- ✅ Frontend Gallery view für Fahrzeug-Bilder
|
||||
- ✅ pytest coverage >= 80% für file module (82%)
|
||||
- ✅ GET /api/v1/sales → 200 + paginated list with filter (date range, status)
|
||||
- ✅ GET /api/v1/sales/:id → 200 + sale detail with vehicle + contact nested
|
||||
- ✅ POST /api/v1/sales mit valid data → 201 + sale object
|
||||
- ✅ POST /api/v1/sales ohne vehicle_id → 422
|
||||
- ✅ POST /api/v1/sales ohne buyer_contact_id → 422
|
||||
- ✅ PUT /api/v1/sales/:id → 200 + updated sale
|
||||
- ✅ DELETE /api/v1/sales/:id → 200 (sale cancelled, vehicle status back to available)
|
||||
- ✅ POST /api/v1/sales/:id/contract → 200 + regenerated contract PDF path
|
||||
- ✅ GET /api/v1/sales/:id/contract → 200 + PDF content (application/pdf)
|
||||
- ✅ Sale mit is_gwg=true und sale_price <= 800 → GwG-Klausel in contract
|
||||
- ✅ POST /api/v1/sales/:id/verify-ust-id → 200 + {verified: false, message: 'BZSt API not available'}
|
||||
- ✅ POST /api/v1/datev/export mit date range → 201 + DATEVExport object
|
||||
- ✅ POST /api/v1/datev/export mit invalid date range → 422
|
||||
- ✅ GET /api/v1/datev/exports → 200 + list of exports
|
||||
- ✅ GET /api/v1/datev/exports/:id/download → 200 + CSV content (text/csv)
|
||||
- ✅ DATEV CSV enthält korrekte Felder: Datum, Konto, Gegenkonto, Betrag, Belegfeld, Buchungstext
|
||||
- ✅ Sale creation → Vehicle status='sold'
|
||||
- ✅ Sale deletion → Vehicle status='available' (in_stock)
|
||||
|
||||
Reference in New Issue
Block a user