PDF-Auftragsvorlagen-System, Objekttyp/Lage-Felder, Eigentümer-Fallback bei Bankverbindung

- PDF-Template-Editor in Einstellungen: Vorlagen hochladen, Formularfelder automatisch auslesen, CRM-Felder zuordnen
- PDF-Vorschau mit annotierten Feldnamen, seitenweise Sortierung der Felder
- Auftrag generieren aus Vertragsdaten (Button im Vertrags-Detail)
- Dynamische Rufnummern-Felder mit Vorwahl-Extraktion und konfigurierbarer Maximalanzahl
- Nicht zugeordnete Felder bleiben editierbar im generierten PDF
- Eigentümer-Felder mit Namens-Kombinationen (Firma+Name etc.) und Fallback auf Kundendaten
- Stressfrei-E-Mail als Feld-Option im Template-Editor
- Objekttyp, Lage und Lage des Anschlusses als neue Felder bei Festnetz-Verträgen (DSL, Glasfaser, Kabel)
- Bankverbindung-Fallback: wenn keine am Vertrag verknüpft, wird automatisch die neueste aktive des Kunden genommen

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 19:16:47 +02:00
parent 9fa1cbc591
commit 9a84e2d3cb
16 changed files with 1881 additions and 21 deletions
+49
View File
@@ -1307,6 +1307,55 @@ export const auditLogApi = {
},
};
// ==================== PDF TEMPLATES ====================
export const pdfTemplateApi = {
getAll: async () => {
const res = await api.get<ApiResponse<import('../types').PdfTemplate[]>>('/pdf-templates');
return res.data;
},
getById: async (id: number) => {
const res = await api.get<ApiResponse<import('../types').PdfTemplate>>(`/pdf-templates/${id}`);
return res.data;
},
create: async (formData: FormData) => {
const res = await api.post<ApiResponse<import('../types').PdfTemplate & { pdfFields?: import('../types').PdfField[] }>>('/pdf-templates', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return res.data;
},
update: async (id: number, data: Record<string, unknown>) => {
const res = await api.put<ApiResponse<import('../types').PdfTemplate>>(`/pdf-templates/${id}`, data);
return res.data;
},
delete: async (id: number) => {
const res = await api.delete<ApiResponse<void>>(`/pdf-templates/${id}`);
return res.data;
},
getFields: async (id: number) => {
const res = await api.get<ApiResponse<import('../types').PdfField[]>>(`/pdf-templates/${id}/fields`);
return res.data;
},
getCrmFields: async (maxPhoneFields?: number) => {
const res = await api.get<ApiResponse<import('../types').CrmField[]>>('/pdf-templates/crm-fields', { params: { maxPhoneFields } });
return res.data;
},
getRequiredInputs: async (templateId: number, contractId: number) => {
const res = await api.get<ApiResponse<{
needsStressfreiEmail: boolean;
stressfreiEmails: { id: number; email: string }[];
manualFields: { key: string; pdfFieldName: string }[];
}>>(`/pdf-templates/${templateId}/generate/${contractId}/inputs`);
return res.data;
},
generatePdf: async (templateId: number, contractId: number, extras?: { stressfreiEmailId?: number; manualValues?: Record<string, string> }) => {
const res = await api.post(`/pdf-templates/${templateId}/generate/${contractId}`, extras || {}, { responseType: 'blob' });
return res.data;
},
generateUrl: (templateId: number, contractId: number) =>
`/api/pdf-templates/${templateId}/generate/${contractId}`,
};
// ==================== EMAIL LOG ====================
export interface EmailLog {