Files
opencrm/backend/src/services/invoice.service.ts
T

182 lines
4.6 KiB
TypeScript

import { InvoiceType } from '@prisma/client';
import prisma from '../lib/prisma.js';
import fs from 'fs';
import path from 'path';
export interface CreateInvoiceData {
invoiceDate: Date;
invoiceType: InvoiceType;
documentPath?: string;
notes?: string;
}
export interface UpdateInvoiceData {
invoiceDate?: Date;
invoiceType?: InvoiceType;
documentPath?: string;
notes?: string;
}
/**
* Alle Rechnungen für ein EnergyContractDetails abrufen
*/
export async function getInvoices(energyContractDetailsId: number) {
return prisma.invoice.findMany({
where: { energyContractDetailsId },
orderBy: { invoiceDate: 'desc' },
});
}
/**
* Einzelne Rechnung abrufen
*/
export async function getInvoice(energyContractDetailsId: number, invoiceId: number) {
return prisma.invoice.findFirst({
where: { id: invoiceId, energyContractDetailsId },
});
}
/**
* Neue Rechnung hinzufügen
*
* Hinweis: Die Validierung ob ein Dokument vorhanden ist, erfolgt NICHT hier,
* da der typische Flow so aussieht:
* 1. Invoice erstellen (ohne Dokument) → Invoice-ID zurückbekommen
* 2. Dokument hochladen mit der Invoice-ID
*
* Die Validierung ob alle Rechnungen Dokumente haben, erfolgt im Cockpit.
*/
export async function addInvoice(energyContractDetailsId: number, data: CreateInvoiceData) {
// Prüfen ob EnergyContractDetails existiert
const energyDetails = await prisma.energyContractDetails.findUnique({
where: { id: energyContractDetailsId },
});
if (!energyDetails) {
throw new Error('Energievertrag nicht gefunden');
}
return prisma.invoice.create({
data: {
energyContractDetailsId,
contractId: energyDetails.contractId,
invoiceDate: data.invoiceDate,
invoiceType: data.invoiceType,
documentPath: data.documentPath,
notes: data.notes,
},
});
}
/**
* Rechnung direkt über contractId hinzufügen (für alle Vertragstypen)
*/
export async function addInvoiceByContract(contractId: number, data: CreateInvoiceData) {
return prisma.invoice.create({
data: {
contractId,
invoiceDate: data.invoiceDate,
invoiceType: data.invoiceType,
documentPath: data.documentPath,
notes: data.notes,
},
});
}
export async function getInvoicesByContract(contractId: number) {
return prisma.invoice.findMany({
where: { contractId },
orderBy: { invoiceDate: 'desc' },
});
}
/**
* Rechnung aktualisieren
*/
export async function updateInvoice(
energyContractDetailsId: number,
invoiceId: number,
data: UpdateInvoiceData
) {
// Prüfen ob Rechnung existiert und zum EnergyContractDetails gehört
const invoice = await prisma.invoice.findFirst({
where: { id: invoiceId, energyContractDetailsId },
});
if (!invoice) {
throw new Error('Rechnung nicht gefunden');
}
// Validierung bei Typ-Änderung
const newType = data.invoiceType ?? invoice.invoiceType;
const newPath = data.documentPath !== undefined ? data.documentPath : invoice.documentPath;
if (newType !== 'NOT_AVAILABLE' && !newPath) {
throw new Error('Dokument ist Pflicht (außer bei Typ "Nicht verfügbar")');
}
return prisma.invoice.update({
where: { id: invoiceId },
data: {
invoiceDate: data.invoiceDate,
invoiceType: data.invoiceType,
documentPath: data.documentPath,
notes: data.notes,
},
});
}
/**
* Rechnung löschen
*/
export async function deleteInvoice(energyContractDetailsId: number, invoiceId: number) {
const invoice = await prisma.invoice.findFirst({
where: { id: invoiceId, energyContractDetailsId },
});
if (!invoice) {
throw new Error('Rechnung nicht gefunden');
}
// Datei löschen falls vorhanden
if (invoice.documentPath) {
const filePath = path.join(process.cwd(), invoice.documentPath);
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
}
}
return prisma.invoice.delete({ where: { id: invoiceId } });
}
/**
* Rechnung direkt erstellen (für E-Mail-Integration)
* Erstellt eine Rechnung mit bereits vorhandenem Dokument
*/
export async function createInvoiceWithDocument(
energyContractDetailsId: number,
invoiceDate: Date,
invoiceType: InvoiceType,
documentPath: string,
notes?: string
) {
// Prüfen ob EnergyContractDetails existiert
const energyDetails = await prisma.energyContractDetails.findUnique({
where: { id: energyContractDetailsId },
});
if (!energyDetails) {
throw new Error('Energievertrag nicht gefunden');
}
return prisma.invoice.create({
data: {
energyContractDetailsId,
invoiceDate,
invoiceType,
documentPath,
notes,
},
});
}