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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user