gdpr audit implemented, email log, vollmachten, pdf delete cancel data privacy and vollmachten, removed message no id card in engergy car, and other contracts that are not telecom contracts, added insert counter for engery

This commit is contained in:
2026-03-21 11:59:53 +01:00
parent 89cf92eaf5
commit f2876f877e
1491 changed files with 265550 additions and 1292 deletions
+267 -2
View File
@@ -1,5 +1,5 @@
import axios from 'axios';
import type { ApiResponse, Customer, Contract, ContractTask, ContractTaskSubtask, ContractTaskStatus, SalesPlatform, CancellationPeriod, ContractDuration, ContractCategory, Provider, Tariff, User, Address, BankCard, IdentityDocument, Meter, MeterReading, Invoice, Role, PortalSettings, CustomerRepresentative, CustomerSummary, ContractHistoryEntry } from '../types';
import type { ApiResponse, Customer, Contract, ContractTask, ContractTaskSubtask, ContractTaskStatus, SalesPlatform, CancellationPeriod, ContractDuration, ContractCategory, Provider, Tariff, User, Address, BankCard, IdentityDocument, Meter, MeterReading, Invoice, Role, PortalSettings, CustomerRepresentative, CustomerSummary, ContractHistoryEntry, AuditLog, AuditSensitivity, AuditRetentionPolicy, CustomerConsent, ConsentType, ConsentStatus, DataDeletionRequest, DeletionRequestStatus, GDPRDashboardStats, RepresentativeAuthorization } from '../types';
const api = axios.create({
baseURL: '/api',
@@ -206,6 +206,20 @@ export const meterApi = {
const res = await api.delete<ApiResponse<void>>(`/meters/${meterId}/readings/${readingId}`);
return res.data;
},
// Portal: Zählerstand melden
reportReading: async (meterId: number, data: { value: number; readingDate?: string; notes?: string }) => {
const res = await api.post<ApiResponse<MeterReading>>(`/meters/${meterId}/readings/report`, data);
return res.data;
},
getMyMeters: async () => {
const res = await api.get<ApiResponse<Meter[]>>('/meters/my-meters');
return res.data;
},
// Status-Update
markTransferred: async (meterId: number, readingId: number) => {
const res = await api.patch<ApiResponse<MeterReading>>(`/meters/${meterId}/readings/${readingId}/transfer`);
return res.data;
},
};
// Invoice API
@@ -1070,7 +1084,7 @@ export const userApi = {
const res = await api.get<ApiResponse<User>>(`/users/${id}`);
return res.data;
},
create: async (data: { email: string; password: string; firstName: string; lastName: string; roleIds: number[]; customerId?: number; hasDeveloperAccess?: boolean }) => {
create: async (data: { email: string; password: string; firstName: string; lastName: string; roleIds: number[]; customerId?: number; hasDeveloperAccess?: boolean; hasGdprAccess?: boolean; whatsappNumber?: string; telegramUsername?: string; signalNumber?: string }) => {
const res = await api.post<ApiResponse<User>>('/users', data);
return res.data;
},
@@ -1132,6 +1146,9 @@ export interface EmailProviderConfig {
imapEncryption?: 'SSL' | 'STARTTLS' | 'NONE';
smtpEncryption?: 'SSL' | 'STARTTLS' | 'NONE';
allowSelfSignedCerts?: boolean; // Selbstsignierte Zertifikate erlauben
// System-E-Mail für automatisierten Versand
systemEmailAddress?: string;
systemEmailPasswordEncrypted?: string;
isActive: boolean;
isDefault: boolean;
createdAt: string;
@@ -1204,4 +1221,252 @@ export const emailProviderApi = {
},
};
// ==================== AUDIT-LOGS ====================
export interface AuditLogSearchParams {
page?: number;
limit?: number;
userId?: number;
action?: string;
resourceType?: string;
sensitivity?: AuditSensitivity;
dataSubjectId?: number;
startDate?: string;
endDate?: string;
search?: string;
}
export const auditLogApi = {
search: async (params?: AuditLogSearchParams) => {
const res = await api.get<ApiResponse<AuditLog[]>>('/audit-logs', { params });
return res.data;
},
getById: async (id: number) => {
const res = await api.get<ApiResponse<AuditLog>>(`/audit-logs/${id}`);
return res.data;
},
getByCustomer: async (customerId: number) => {
const res = await api.get<ApiResponse<AuditLog[]>>(`/audit-logs/customer/${customerId}`);
return res.data;
},
export: async (params?: AuditLogSearchParams & { format?: 'json' | 'csv' }) => {
const res = await api.get<ApiResponse<{ data: AuditLog[]; format: string }>>('/audit-logs/export', { params });
return res.data;
},
verifyIntegrity: async () => {
const res = await api.post<ApiResponse<{ valid: boolean; errors: string[] }>>('/audit-logs/verify');
return res.data;
},
getRetentionPolicies: async () => {
const res = await api.get<ApiResponse<AuditRetentionPolicy[]>>('/audit-logs/retention-policies');
return res.data;
},
updateRetentionPolicy: async (id: number, data: { retentionDays: number; isActive?: boolean }) => {
const res = await api.put<ApiResponse<AuditRetentionPolicy>>(`/audit-logs/retention-policies/${id}`, data);
return res.data;
},
runRetentionCleanup: async () => {
const res = await api.post<ApiResponse<{ deletedCount: number }>>('/audit-logs/cleanup');
return res.data;
},
};
// ==================== EMAIL LOG ====================
export interface EmailLog {
id: number;
fromAddress: string;
toAddress: string;
subject: string;
context: string;
customerId?: number;
triggeredBy?: string;
smtpServer: string;
smtpPort: number;
smtpEncryption: string;
smtpUser: string;
success: boolean;
messageId?: string;
errorMessage?: string;
smtpResponse?: string;
sentAt: string;
}
export const emailLogApi = {
getLogs: async (params?: { page?: number; limit?: number; success?: string; search?: string; context?: string }) => {
const query = new URLSearchParams();
if (params?.page) query.set('page', params.page.toString());
if (params?.limit) query.set('limit', params.limit.toString());
if (params?.success !== undefined) query.set('success', params.success);
if (params?.search) query.set('search', params.search);
if (params?.context) query.set('context', params.context);
const res = await api.get<ApiResponse<EmailLog[]> & { pagination: { page: number; limit: number; total: number; totalPages: number } }>(`/email-logs?${query}`);
return res.data;
},
getStats: async () => {
const res = await api.get<ApiResponse<{ total: number; success: number; failed: number; last24h: number }>>('/email-logs/stats');
return res.data;
},
getDetail: async (id: number) => {
const res = await api.get<ApiResponse<EmailLog>>(`/email-logs/${id}`);
return res.data;
},
};
// ==================== DSGVO ====================
export const gdprApi = {
// Dashboard
getDashboardStats: async () => {
const res = await api.get<ApiResponse<GDPRDashboardStats>>('/gdpr/dashboard');
return res.data;
},
// Datenexport (Art. 15)
exportCustomerData: async (customerId: number) => {
const res = await api.get<ApiResponse<unknown>>(`/gdpr/customer/${customerId}/export`);
return res.data;
},
// Löschanfragen
getDeletionRequests: async (params?: { status?: DeletionRequestStatus; page?: number; limit?: number }) => {
const res = await api.get<ApiResponse<DataDeletionRequest[]>>('/gdpr/deletions', { params });
return res.data;
},
getDeletionRequest: async (id: number) => {
const res = await api.get<ApiResponse<DataDeletionRequest>>(`/gdpr/deletions/${id}`);
return res.data;
},
createDeletionRequest: async (data: { customerId: number; requestSource: string; requestedBy: string }) => {
const res = await api.post<ApiResponse<DataDeletionRequest>>('/gdpr/deletions', data);
return res.data;
},
processDeletionRequest: async (id: number, data: { processedBy: string; action: 'complete' | 'partial' | 'reject'; retentionReason?: string }) => {
const res = await api.put<ApiResponse<DataDeletionRequest>>(`/gdpr/deletions/${id}/process`, data);
return res.data;
},
// Consent-Status prüfen (hat Kunde vollständig zugestimmt?)
checkConsentStatus: async (customerId: number) => {
const res = await api.get<ApiResponse<{ hasConsent: boolean; hasPaperConsent: boolean; hasOnlineConsent: boolean; consentDetails: { type: string; status: string }[]; consentHash: string | null }>>(`/gdpr/customer/${customerId}/consent-status`);
return res.data;
},
getMyConsentStatus: async () => {
const res = await api.get<ApiResponse<{ hasConsent: boolean; hasPaperConsent: boolean; hasOnlineConsent: boolean; consentDetails: { type: string; status: string }[]; consentHash: string | null }>>('/gdpr/my-consent-status');
return res.data;
},
// Einwilligungen
getCustomerConsents: async (customerId: number) => {
const res = await api.get<ApiResponse<CustomerConsent[]>>(`/gdpr/customer/${customerId}/consents`);
return res.data;
},
updateConsent: async (customerId: number, consentType: ConsentType, data: { status: ConsentStatus; source?: string }) => {
const res = await api.put<ApiResponse<CustomerConsent>>(`/gdpr/customer/${customerId}/consents/${consentType}`, data);
return res.data;
},
getConsentOverview: async () => {
const res = await api.get<ApiResponse<Record<string, { granted: number; withdrawn: number; pending: number }>>>('/gdpr/consents/overview');
return res.data;
},
// Datenschutzerklärung (Editor)
getPrivacyPolicy: async () => {
const res = await api.get<ApiResponse<{ html: string }>>('/gdpr/privacy-policy');
return res.data;
},
updatePrivacyPolicy: async (html: string) => {
const res = await api.put<ApiResponse<void>>('/gdpr/privacy-policy', { html });
return res.data;
},
// Vollmacht-Vorlage
getAuthorizationTemplate: async () => {
const res = await api.get<ApiResponse<{ html: string }>>('/gdpr/authorization-template');
return res.data;
},
updateAuthorizationTemplate: async (html: string) => {
const res = await api.put<ApiResponse<void>>('/gdpr/authorization-template', { html });
return res.data;
},
// Consent-Link senden
sendConsentLink: async (customerId: number, channel: string) => {
const res = await api.post<ApiResponse<{ url: string; channel: string; hash: string }>>(`/gdpr/customer/${customerId}/send-consent-link`, { channel });
return res.data;
},
// Portal: Eigene Datenschutzseite
getMyPrivacy: async () => {
const res = await api.get<ApiResponse<{ privacyPolicyHtml: string; consents: CustomerConsent[] }>>('/gdpr/my-privacy');
return res.data;
},
getMyPrivacyPdfUrl: '/api/gdpr/my-privacy/pdf',
// Vollmachten (Admin)
getAuthorizations: async (customerId: number) => {
const res = await api.get<ApiResponse<RepresentativeAuthorization[]>>(`/gdpr/customer/${customerId}/authorizations`);
return res.data;
},
sendAuthorizationRequest: async (customerId: number, representativeId: number, channel: string) => {
const res = await api.post<ApiResponse<{ channel: string; portalUrl: string; messageText: string }>>(`/gdpr/customer/${customerId}/authorizations/${representativeId}/send`, { channel });
return res.data;
},
grantAuthorization: async (customerId: number, representativeId: number, data?: { source?: string; notes?: string }) => {
const res = await api.post<ApiResponse<RepresentativeAuthorization>>(`/gdpr/customer/${customerId}/authorizations/${representativeId}/grant`, data || {});
return res.data;
},
withdrawAuthorization: async (customerId: number, representativeId: number) => {
const res = await api.post<ApiResponse<RepresentativeAuthorization>>(`/gdpr/customer/${customerId}/authorizations/${representativeId}/withdraw`);
return res.data;
},
uploadAuthorizationDocument: async (customerId: number, representativeId: number, file: File) => {
const formData = new FormData();
formData.append('document', file);
const res = await api.post<ApiResponse<RepresentativeAuthorization>>(
`/gdpr/customer/${customerId}/authorizations/${representativeId}/upload`,
formData,
{ headers: { 'Content-Type': 'multipart/form-data' } }
);
return res.data;
},
deleteAuthorizationDocument: async (customerId: number, representativeId: number) => {
const res = await api.delete<ApiResponse<RepresentativeAuthorization>>(`/gdpr/customer/${customerId}/authorizations/${representativeId}/document`);
return res.data;
},
// Vollmachten (Portal)
getMyAuthorizations: async () => {
const res = await api.get<ApiResponse<RepresentativeAuthorization[]>>('/gdpr/my-authorizations');
return res.data;
},
toggleMyAuthorization: async (representativeId: number, grant: boolean) => {
const res = await api.put<ApiResponse<RepresentativeAuthorization>>(`/gdpr/my-authorizations/${representativeId}`, { grant });
return res.data;
},
getMyAuthorizationStatus: async () => {
const res = await api.get<ApiResponse<{ customerId: number; hasAuthorization: boolean }[]>>('/gdpr/my-authorization-status');
return res.data;
},
};
// ==================== PUBLIC API (kein Auth-Token) ====================
const publicAxios = axios.create({
baseURL: '/api/public',
headers: { 'Content-Type': 'application/json' },
});
export const publicApi = {
getConsentPage: async (hash: string) => {
const res = await publicAxios.get<ApiResponse<{
customer: { firstName: string; lastName: string; customerNumber: string };
consents: Array<{
consentType: string;
status: string;
label: string;
description: string;
grantedAt: string | null;
}>;
privacyPolicyHtml: string;
}>>(`/consent/${hash}`);
return res.data;
},
grantAllConsents: async (hash: string) => {
const res = await publicAxios.post<ApiResponse<void>>(`/consent/${hash}/grant`);
return res.data;
},
getConsentPdfUrl: (hash: string) => `/api/public/consent/${hash}/pdf`,
};
export default api;