added invoices and status in cockpit, created info button for contract status types
This commit is contained in:
@@ -185,6 +185,24 @@ router.post(
|
||||
cachedEmailController.saveEmailAsPdf
|
||||
);
|
||||
|
||||
// E-Mail als PDF exportieren und als Rechnung speichern
|
||||
// POST /api/emails/:id/save-as-invoice { invoiceDate, invoiceType, notes? }
|
||||
router.post(
|
||||
'/emails/:id/save-as-invoice',
|
||||
authenticate,
|
||||
requirePermission('contracts:update'),
|
||||
cachedEmailController.saveEmailAsInvoice
|
||||
);
|
||||
|
||||
// Anhang als Rechnung speichern
|
||||
// POST /api/emails/:id/attachments/:filename/save-as-invoice { invoiceDate, invoiceType, notes? }
|
||||
router.post(
|
||||
'/emails/:id/attachments/:filename/save-as-invoice',
|
||||
authenticate,
|
||||
requirePermission('contracts:update'),
|
||||
cachedEmailController.saveAttachmentAsInvoice
|
||||
);
|
||||
|
||||
// ==================== VERTRAGSZUORDNUNG ====================
|
||||
|
||||
// E-Mail Vertrag zuordnen
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Router } from 'express';
|
||||
import * as invoiceController from '../controllers/invoice.controller.js';
|
||||
import { authenticate, requirePermission } from '../middleware/auth.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// ==================== INVOICE CRUD ====================
|
||||
|
||||
// Alle Rechnungen für ein EnergyContractDetails abrufen
|
||||
// GET /api/energy-details/:ecdId/invoices
|
||||
router.get(
|
||||
'/:ecdId/invoices',
|
||||
authenticate,
|
||||
requirePermission('contracts:read'),
|
||||
invoiceController.getInvoices
|
||||
);
|
||||
|
||||
// Einzelne Rechnung abrufen
|
||||
// GET /api/energy-details/:ecdId/invoices/:invoiceId
|
||||
router.get(
|
||||
'/:ecdId/invoices/:invoiceId',
|
||||
authenticate,
|
||||
requirePermission('contracts:read'),
|
||||
invoiceController.getInvoice
|
||||
);
|
||||
|
||||
// Neue Rechnung hinzufügen
|
||||
// POST /api/energy-details/:ecdId/invoices
|
||||
router.post(
|
||||
'/:ecdId/invoices',
|
||||
authenticate,
|
||||
requirePermission('contracts:update'),
|
||||
invoiceController.addInvoice
|
||||
);
|
||||
|
||||
// Rechnung aktualisieren
|
||||
// PUT /api/energy-details/:ecdId/invoices/:invoiceId
|
||||
router.put(
|
||||
'/:ecdId/invoices/:invoiceId',
|
||||
authenticate,
|
||||
requirePermission('contracts:update'),
|
||||
invoiceController.updateInvoice
|
||||
);
|
||||
|
||||
// Rechnung löschen
|
||||
// DELETE /api/energy-details/:ecdId/invoices/:invoiceId
|
||||
router.delete(
|
||||
'/:ecdId/invoices/:invoiceId',
|
||||
authenticate,
|
||||
requirePermission('contracts:delete'),
|
||||
invoiceController.deleteInvoice
|
||||
);
|
||||
|
||||
export default router;
|
||||
@@ -658,4 +658,99 @@ router.delete(
|
||||
(req: AuthRequest, res: Response) => handleContractDocumentDelete(req, res, 'cancellationConfirmationOptionsPath')
|
||||
);
|
||||
|
||||
// ==================== RECHNUNGS-DOKUMENTE ====================
|
||||
|
||||
// Upload für Rechnungs-Dokument
|
||||
router.post(
|
||||
'/invoices/:id',
|
||||
authenticate,
|
||||
requirePermission('contracts:update'),
|
||||
setUploadDir('invoices'),
|
||||
upload.single('document'),
|
||||
async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
if (!req.file) {
|
||||
res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
|
||||
return;
|
||||
}
|
||||
|
||||
const invoiceId = parseInt(req.params.id);
|
||||
const relativePath = `/uploads/invoices/${req.file.filename}`;
|
||||
|
||||
// Alte Datei löschen falls vorhanden
|
||||
const invoice = await prisma.invoice.findUnique({ where: { id: invoiceId } });
|
||||
if (!invoice) {
|
||||
res.status(404).json({ success: false, error: 'Rechnung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (invoice.documentPath) {
|
||||
const oldPath = path.join(process.cwd(), invoice.documentPath);
|
||||
if (fs.existsSync(oldPath)) {
|
||||
fs.unlinkSync(oldPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoice in der DB aktualisieren
|
||||
await prisma.invoice.update({
|
||||
where: { id: invoiceId },
|
||||
data: { documentPath: relativePath },
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
path: relativePath,
|
||||
filename: req.file.filename,
|
||||
originalName: req.file.originalname,
|
||||
size: req.file.size,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Invoice upload error:', error);
|
||||
res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Löschen von Rechnungs-Dokument
|
||||
router.delete(
|
||||
'/invoices/:id',
|
||||
authenticate,
|
||||
requirePermission('contracts:update'),
|
||||
async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const invoiceId = parseInt(req.params.id);
|
||||
|
||||
const invoice = await prisma.invoice.findUnique({ where: { id: invoiceId } });
|
||||
if (!invoice) {
|
||||
res.status(404).json({ success: false, error: 'Rechnung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!invoice.documentPath) {
|
||||
res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Datei löschen
|
||||
const filePath = path.join(process.cwd(), invoice.documentPath);
|
||||
if (fs.existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
|
||||
// documentPath in DB auf null setzen
|
||||
await prisma.invoice.update({
|
||||
where: { id: invoiceId },
|
||||
data: { documentPath: null },
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Invoice delete error:', error);
|
||||
res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user