1183 lines
44 KiB
TypeScript
1183 lines
44 KiB
TypeScript
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 } from '../types';
|
|
|
|
const api = axios.create({
|
|
baseURL: '/api',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
// Add auth token to requests
|
|
api.interceptors.request.use((config) => {
|
|
const token = localStorage.getItem('token');
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
return config;
|
|
});
|
|
|
|
// Handle auth errors and extract error messages
|
|
api.interceptors.response.use(
|
|
(response) => response,
|
|
(error) => {
|
|
// Bei 401 nur dann zur Login-Seite umleiten, wenn wir NICHT gerade auf der Login-Seite sind
|
|
// Login-Endpunkte ausschließen, da 401 dort "falsches Passwort" bedeutet
|
|
const isLoginEndpoint = error.config?.url?.includes('/auth/login') ||
|
|
error.config?.url?.includes('/auth/customer-login');
|
|
|
|
if (error.response?.status === 401 && !isLoginEndpoint) {
|
|
localStorage.removeItem('token');
|
|
localStorage.removeItem('user');
|
|
window.location.href = '/login';
|
|
}
|
|
// Extract error message from response
|
|
const message = error.response?.data?.error || error.message || 'Ein Fehler ist aufgetreten';
|
|
const enhancedError = new Error(message);
|
|
return Promise.reject(enhancedError);
|
|
}
|
|
);
|
|
|
|
// Auth
|
|
export const authApi = {
|
|
login: async (email: string, password: string) => {
|
|
const res = await api.post<ApiResponse<{ token: string; user: User }>>('/auth/login', { email, password });
|
|
return res.data;
|
|
},
|
|
customerLogin: async (email: string, password: string) => {
|
|
const res = await api.post<ApiResponse<{ token: string; user: User }>>('/auth/customer-login', { email, password });
|
|
return res.data;
|
|
},
|
|
me: async () => {
|
|
const res = await api.get<ApiResponse<User>>('/auth/me');
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Customers
|
|
export const customerApi = {
|
|
getAll: async (params?: { search?: string; type?: string; page?: number; limit?: number }) => {
|
|
const res = await api.get<ApiResponse<Customer[]>>('/customers', { params });
|
|
return res.data;
|
|
},
|
|
getById: async (id: number) => {
|
|
const res = await api.get<ApiResponse<Customer>>(`/customers/${id}`);
|
|
return res.data;
|
|
},
|
|
create: async (data: Partial<Customer>) => {
|
|
const res = await api.post<ApiResponse<Customer>>('/customers', data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<Customer>) => {
|
|
const res = await api.put<ApiResponse<Customer>>(`/customers/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/customers/${id}`);
|
|
return res.data;
|
|
},
|
|
// Portal-Einstellungen
|
|
getPortalSettings: async (customerId: number) => {
|
|
const res = await api.get<ApiResponse<PortalSettings>>(`/customers/${customerId}/portal`);
|
|
return res.data;
|
|
},
|
|
updatePortalSettings: async (customerId: number, data: { portalEnabled?: boolean; portalEmail?: string | null }) => {
|
|
const res = await api.put<ApiResponse<PortalSettings>>(`/customers/${customerId}/portal`, data);
|
|
return res.data;
|
|
},
|
|
setPortalPassword: async (customerId: number, password: string) => {
|
|
const res = await api.post<ApiResponse<void>>(`/customers/${customerId}/portal/password`, { password });
|
|
return res.data;
|
|
},
|
|
getPortalPassword: async (customerId: number) => {
|
|
const res = await api.get<ApiResponse<{ password: string | null }>>(`/customers/${customerId}/portal/password`);
|
|
return res.data;
|
|
},
|
|
// Vertreter-Verwaltung
|
|
getRepresentatives: async (customerId: number) => {
|
|
const res = await api.get<ApiResponse<CustomerRepresentative[]>>(`/customers/${customerId}/representatives`);
|
|
return res.data;
|
|
},
|
|
addRepresentative: async (customerId: number, representativeId: number, notes?: string) => {
|
|
const res = await api.post<ApiResponse<CustomerRepresentative>>(`/customers/${customerId}/representatives`, { representativeId, notes });
|
|
return res.data;
|
|
},
|
|
removeRepresentative: async (customerId: number, representativeId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/customers/${customerId}/representatives/${representativeId}`);
|
|
return res.data;
|
|
},
|
|
searchForRepresentative: async (customerId: number, search: string) => {
|
|
const res = await api.get<ApiResponse<CustomerSummary[]>>(`/customers/${customerId}/representatives/search`, { params: { search } });
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Addresses
|
|
export const addressApi = {
|
|
getByCustomer: async (customerId: number) => {
|
|
const res = await api.get<ApiResponse<Address[]>>(`/customers/${customerId}/addresses`);
|
|
return res.data;
|
|
},
|
|
create: async (customerId: number, data: Partial<Address>) => {
|
|
const res = await api.post<ApiResponse<Address>>(`/customers/${customerId}/addresses`, data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<Address>) => {
|
|
const res = await api.put<ApiResponse<Address>>(`/addresses/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/addresses/${id}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Bank Cards
|
|
export const bankCardApi = {
|
|
getByCustomer: async (customerId: number, showInactive = false) => {
|
|
const res = await api.get<ApiResponse<BankCard[]>>(`/customers/${customerId}/bank-cards`, { params: { showInactive } });
|
|
return res.data;
|
|
},
|
|
create: async (customerId: number, data: Partial<BankCard>) => {
|
|
const res = await api.post<ApiResponse<BankCard>>(`/customers/${customerId}/bank-cards`, data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<BankCard>) => {
|
|
const res = await api.put<ApiResponse<BankCard>>(`/bank-cards/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/bank-cards/${id}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Identity Documents
|
|
export const documentApi = {
|
|
getByCustomer: async (customerId: number, showInactive = false) => {
|
|
const res = await api.get<ApiResponse<IdentityDocument[]>>(`/customers/${customerId}/documents`, { params: { showInactive } });
|
|
return res.data;
|
|
},
|
|
create: async (customerId: number, data: Partial<IdentityDocument>) => {
|
|
const res = await api.post<ApiResponse<IdentityDocument>>(`/customers/${customerId}/documents`, data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<IdentityDocument>) => {
|
|
const res = await api.put<ApiResponse<IdentityDocument>>(`/documents/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/documents/${id}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Meters
|
|
export const meterApi = {
|
|
getByCustomer: async (customerId: number, showInactive = false) => {
|
|
const res = await api.get<ApiResponse<Meter[]>>(`/customers/${customerId}/meters`, { params: { showInactive } });
|
|
return res.data;
|
|
},
|
|
create: async (customerId: number, data: Partial<Meter>) => {
|
|
const res = await api.post<ApiResponse<Meter>>(`/customers/${customerId}/meters`, data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<Meter>) => {
|
|
const res = await api.put<ApiResponse<Meter>>(`/meters/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/meters/${id}`);
|
|
return res.data;
|
|
},
|
|
getReadings: async (meterId: number) => {
|
|
const res = await api.get<ApiResponse<MeterReading[]>>(`/meters/${meterId}/readings`);
|
|
return res.data;
|
|
},
|
|
addReading: async (meterId: number, data: Partial<MeterReading>) => {
|
|
const res = await api.post<ApiResponse<MeterReading>>(`/meters/${meterId}/readings`, data);
|
|
return res.data;
|
|
},
|
|
updateReading: async (meterId: number, readingId: number, data: Partial<MeterReading>) => {
|
|
const res = await api.put<ApiResponse<MeterReading>>(`/meters/${meterId}/readings/${readingId}`, data);
|
|
return res.data;
|
|
},
|
|
deleteReading: async (meterId: number, readingId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/meters/${meterId}/readings/${readingId}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Invoice API
|
|
export const invoiceApi = {
|
|
getInvoices: async (ecdId: number) => {
|
|
const res = await api.get<ApiResponse<Invoice[]>>(`/energy-details/${ecdId}/invoices`);
|
|
return res.data;
|
|
},
|
|
addInvoice: async (ecdId: number, data: Partial<Invoice>) => {
|
|
const res = await api.post<ApiResponse<Invoice>>(`/energy-details/${ecdId}/invoices`, data);
|
|
return res.data;
|
|
},
|
|
updateInvoice: async (ecdId: number, invoiceId: number, data: Partial<Invoice>) => {
|
|
const res = await api.put<ApiResponse<Invoice>>(`/energy-details/${ecdId}/invoices/${invoiceId}`, data);
|
|
return res.data;
|
|
},
|
|
deleteInvoice: async (ecdId: number, invoiceId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/energy-details/${ecdId}/invoices/${invoiceId}`);
|
|
return res.data;
|
|
},
|
|
uploadDocument: async (invoiceId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(
|
|
`/upload/invoices/${invoiceId}`,
|
|
formData,
|
|
{ headers: { 'Content-Type': 'multipart/form-data' } }
|
|
);
|
|
return res.data;
|
|
},
|
|
deleteDocument: async (invoiceId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/invoices/${invoiceId}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Stressfrei-Wechseln E-Mail-Adressen
|
|
export interface StressfreiEmail {
|
|
id: number;
|
|
customerId: number;
|
|
email: string;
|
|
platform?: string;
|
|
notes?: string;
|
|
isActive: boolean;
|
|
hasMailbox: boolean;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
// Mailbox-Konto (für Dropdown-Auswahl)
|
|
export interface MailboxAccount {
|
|
id: number;
|
|
email: string;
|
|
notes?: string;
|
|
hasMailbox: boolean;
|
|
_count: {
|
|
cachedEmails: number;
|
|
};
|
|
}
|
|
|
|
// Gecachte E-Mail
|
|
export interface CachedEmail {
|
|
id: number;
|
|
stressfreiEmailId: number;
|
|
folder: 'INBOX' | 'SENT';
|
|
messageId: string;
|
|
uid: number;
|
|
subject?: string;
|
|
fromAddress: string;
|
|
fromName?: string;
|
|
toAddresses: string; // JSON Array
|
|
ccAddresses?: string; // JSON Array
|
|
receivedAt: string;
|
|
textBody?: string;
|
|
htmlBody?: string;
|
|
hasAttachments: boolean;
|
|
attachmentNames?: string; // JSON Array
|
|
contractId?: number;
|
|
assignedAt?: string;
|
|
assignedBy?: number;
|
|
isAutoAssigned?: boolean; // true = automatisch beim Senden aus Vertrag zugeordnet
|
|
isRead: boolean;
|
|
isStarred: boolean;
|
|
isDeleted: boolean;
|
|
deletedAt?: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
stressfreiEmail?: {
|
|
id: number;
|
|
email: string;
|
|
customerId: number;
|
|
};
|
|
contract?: {
|
|
id: number;
|
|
contractNumber: string;
|
|
} | null;
|
|
}
|
|
|
|
export interface SyncResult {
|
|
newEmails: number;
|
|
totalEmails: number;
|
|
}
|
|
|
|
export interface EmailAttachment {
|
|
filename: string;
|
|
content: string; // Base64-kodierter Inhalt
|
|
contentType?: string; // MIME-Type (z.B. 'application/pdf')
|
|
}
|
|
|
|
export interface SendEmailParams {
|
|
to: string | string[];
|
|
cc?: string | string[];
|
|
subject: string;
|
|
text?: string;
|
|
html?: string;
|
|
inReplyTo?: string;
|
|
references?: string[];
|
|
attachments?: EmailAttachment[];
|
|
contractId?: number; // Vertrag dem die gesendete E-Mail zugeordnet wird
|
|
}
|
|
|
|
// Anhang-Speicher-Ziele
|
|
export interface AttachmentTargetSlot {
|
|
key: string;
|
|
label: string;
|
|
field: string;
|
|
hasDocument: boolean;
|
|
currentPath?: string;
|
|
}
|
|
|
|
export interface AttachmentEntityWithSlots {
|
|
id: number;
|
|
label: string;
|
|
slots: AttachmentTargetSlot[];
|
|
}
|
|
|
|
export interface AttachmentTargetsResponse {
|
|
customer: {
|
|
id: number;
|
|
name: string;
|
|
type: 'PRIVATE' | 'BUSINESS';
|
|
slots: AttachmentTargetSlot[];
|
|
};
|
|
identityDocuments: AttachmentEntityWithSlots[];
|
|
bankCards: AttachmentEntityWithSlots[];
|
|
contract?: {
|
|
id: number;
|
|
contractNumber: string;
|
|
type: string;
|
|
energyDetailsId?: number;
|
|
slots: AttachmentTargetSlot[];
|
|
};
|
|
}
|
|
|
|
export const stressfreiEmailApi = {
|
|
getByCustomer: async (customerId: number, includeInactive = false) => {
|
|
const res = await api.get<ApiResponse<StressfreiEmail[]>>(`/customers/${customerId}/stressfrei-emails`, { params: { includeInactive } });
|
|
return res.data;
|
|
},
|
|
create: async (customerId: number, data: {
|
|
email: string;
|
|
platform?: string;
|
|
notes?: string;
|
|
provisionAtProvider?: boolean;
|
|
createMailbox?: boolean;
|
|
}) => {
|
|
const res = await api.post<ApiResponse<StressfreiEmail>>(`/customers/${customerId}/stressfrei-emails`, data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<StressfreiEmail>) => {
|
|
const res = await api.put<ApiResponse<StressfreiEmail>>(`/stressfrei-emails/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/stressfrei-emails/${id}`);
|
|
return res.data;
|
|
},
|
|
// Mailbox nachträglich aktivieren
|
|
enableMailbox: async (id: number) => {
|
|
const res = await api.post<ApiResponse<null>>(`/stressfrei-emails/${id}/enable-mailbox`);
|
|
return res.data;
|
|
},
|
|
// Mailbox-Status mit Provider synchronisieren
|
|
syncMailboxStatus: async (id: number) => {
|
|
const res = await api.post<ApiResponse<{ hasMailbox: boolean; wasUpdated: boolean }>>(`/stressfrei-emails/${id}/sync-mailbox-status`);
|
|
return res.data;
|
|
},
|
|
// Mailbox-Zugangsdaten abrufen (IMAP/SMTP)
|
|
getMailboxCredentials: async (id: number) => {
|
|
const res = await api.get<ApiResponse<{
|
|
email: string;
|
|
password: string;
|
|
imap: { server: string; port: number; encryption: string } | null;
|
|
smtp: { server: string; port: number; encryption: string } | null;
|
|
}>>(`/stressfrei-emails/${id}/credentials`);
|
|
return res.data;
|
|
},
|
|
// Passwort zurücksetzen (generiert neues Passwort beim Provider)
|
|
resetPassword: async (id: number) => {
|
|
const res = await api.post<ApiResponse<{ password: string }>>(`/stressfrei-emails/${id}/reset-password`);
|
|
return res.data;
|
|
},
|
|
// E-Mails synchronisieren
|
|
syncEmails: async (id: number, fullSync = false) => {
|
|
const res = await api.post<ApiResponse<SyncResult>>(`/stressfrei-emails/${id}/sync`, {}, { params: { full: fullSync } });
|
|
return res.data;
|
|
},
|
|
// E-Mail senden
|
|
sendEmail: async (id: number, params: SendEmailParams) => {
|
|
const res = await api.post<ApiResponse<{ messageId: string }>>(`/stressfrei-emails/${id}/send`, params);
|
|
return res.data;
|
|
},
|
|
// Ordner-Anzahlen abrufen (total und ungelesen pro Ordner)
|
|
getFolderCounts: async (id: number) => {
|
|
const res = await api.get<ApiResponse<{
|
|
inbox: number;
|
|
inboxUnread: number;
|
|
sent: number;
|
|
sentUnread: number;
|
|
trash: number;
|
|
trashUnread: number;
|
|
}>>(`/stressfrei-emails/${id}/folder-counts`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Cached Email API (E-Mail-Client)
|
|
export const cachedEmailApi = {
|
|
// E-Mails für Kunden abrufen
|
|
getForCustomer: async (customerId: number, options?: { accountId?: number; folder?: 'INBOX' | 'SENT'; limit?: number; offset?: number }) => {
|
|
const res = await api.get<ApiResponse<CachedEmail[]>>(`/customers/${customerId}/emails`, { params: options });
|
|
return res.data;
|
|
},
|
|
// E-Mails für Vertrag abrufen
|
|
getForContract: async (contractId: number, options?: { folder?: 'INBOX' | 'SENT'; limit?: number; offset?: number }) => {
|
|
const res = await api.get<ApiResponse<CachedEmail[]>>(`/contracts/${contractId}/emails`, { params: options });
|
|
return res.data;
|
|
},
|
|
// Ordner-Anzahlen für Vertrag abrufen (zugeordnete E-Mails)
|
|
getContractFolderCounts: async (contractId: number) => {
|
|
const res = await api.get<ApiResponse<{
|
|
inbox: number;
|
|
inboxUnread: number;
|
|
sent: number;
|
|
sentUnread: number;
|
|
}>>(`/contracts/${contractId}/emails/folder-counts`);
|
|
return res.data;
|
|
},
|
|
// Mailbox-Konten eines Kunden abrufen
|
|
getMailboxAccounts: async (customerId: number) => {
|
|
const res = await api.get<ApiResponse<MailboxAccount[]>>(`/customers/${customerId}/mailbox-accounts`);
|
|
return res.data;
|
|
},
|
|
// Einzelne E-Mail abrufen (mit Body)
|
|
getById: async (id: number) => {
|
|
const res = await api.get<ApiResponse<CachedEmail>>(`/emails/${id}`);
|
|
return res.data;
|
|
},
|
|
// E-Mail-Thread abrufen
|
|
getThread: async (id: number) => {
|
|
const res = await api.get<ApiResponse<CachedEmail[]>>(`/emails/${id}/thread`);
|
|
return res.data;
|
|
},
|
|
// Als gelesen/ungelesen markieren
|
|
markAsRead: async (id: number, isRead: boolean) => {
|
|
const res = await api.patch<ApiResponse<void>>(`/emails/${id}/read`, { isRead });
|
|
return res.data;
|
|
},
|
|
// Stern umschalten
|
|
toggleStar: async (id: number) => {
|
|
const res = await api.post<ApiResponse<{ isStarred: boolean }>>(`/emails/${id}/star`);
|
|
return res.data;
|
|
},
|
|
// Vertrag zuordnen
|
|
assignToContract: async (emailId: number, contractId: number) => {
|
|
const res = await api.post<ApiResponse<CachedEmail>>(`/emails/${emailId}/assign`, { contractId });
|
|
return res.data;
|
|
},
|
|
// Zuordnung aufheben
|
|
unassignFromContract: async (emailId: number) => {
|
|
const res = await api.delete<ApiResponse<CachedEmail>>(`/emails/${emailId}/assign`);
|
|
return res.data;
|
|
},
|
|
// E-Mail löschen (nur Admin)
|
|
delete: async (emailId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/emails/${emailId}`);
|
|
return res.data;
|
|
},
|
|
// Anhang-URL (view=true für inline anzeigen, sonst download)
|
|
getAttachmentUrl: (emailId: number, filename: string, view?: boolean) => {
|
|
const token = localStorage.getItem('token');
|
|
const encodedFilename = encodeURIComponent(filename);
|
|
const viewParam = view ? '&view=true' : '';
|
|
return `${api.defaults.baseURL}/emails/${emailId}/attachments/${encodedFilename}?token=${token}${viewParam}`;
|
|
},
|
|
// Ungelesene E-Mails zählen
|
|
getUnreadCount: async (params: { customerId?: number; contractId?: number }) => {
|
|
const res = await api.get<ApiResponse<{ count: number }>>('/emails/unread-count', { params });
|
|
return res.data;
|
|
},
|
|
// ==================== PAPIERKORB ====================
|
|
// Papierkorb-E-Mails für Kunden abrufen
|
|
getTrash: async (customerId: number) => {
|
|
const res = await api.get<ApiResponse<CachedEmail[]>>(`/customers/${customerId}/emails/trash`);
|
|
return res.data;
|
|
},
|
|
// Papierkorb-Anzahl für Kunden
|
|
getTrashCount: async (customerId: number) => {
|
|
const res = await api.get<ApiResponse<{ count: number }>>(`/customers/${customerId}/emails/trash/count`);
|
|
return res.data;
|
|
},
|
|
// E-Mail aus Papierkorb wiederherstellen
|
|
restore: async (emailId: number) => {
|
|
const res = await api.post<ApiResponse<void>>(`/emails/${emailId}/restore`);
|
|
return res.data;
|
|
},
|
|
// E-Mail endgültig löschen (aus Papierkorb)
|
|
permanentDelete: async (emailId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/emails/${emailId}/permanent`);
|
|
return res.data;
|
|
},
|
|
// ==================== ANHANG-SPEICHERUNG ====================
|
|
// Verfügbare Dokumenten-Ziele für Anhänge abrufen
|
|
getAttachmentTargets: async (emailId: number) => {
|
|
const res = await api.get<ApiResponse<AttachmentTargetsResponse>>(`/emails/${emailId}/attachment-targets`);
|
|
return res.data;
|
|
},
|
|
// Anhang in Dokumentenfeld speichern
|
|
saveAttachmentTo: async (emailId: number, filename: string, params: { entityType: string; entityId?: number; targetKey: string }) => {
|
|
const encodedFilename = encodeURIComponent(filename);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string; originalName: string; size: number }>>(
|
|
`/emails/${emailId}/attachments/${encodedFilename}/save-to`,
|
|
params
|
|
);
|
|
return res.data;
|
|
},
|
|
// E-Mail als PDF speichern
|
|
saveEmailAsPdf: async (emailId: number, params: { entityType: string; entityId?: number; targetKey: string }) => {
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string; size: number }>>(
|
|
`/emails/${emailId}/save-as-pdf`,
|
|
params
|
|
);
|
|
return res.data;
|
|
},
|
|
// E-Mail als Rechnung speichern (für Energieverträge)
|
|
saveEmailAsInvoice: async (emailId: number, params: { invoiceDate: string; invoiceType: string; notes?: string }) => {
|
|
const res = await api.post<ApiResponse<{ id: number; invoiceDate: string; invoiceType: string; documentPath: string }>>(
|
|
`/emails/${emailId}/save-as-invoice`,
|
|
params
|
|
);
|
|
return res.data;
|
|
},
|
|
// Anhang als Rechnung speichern (für Energieverträge)
|
|
saveAttachmentAsInvoice: async (emailId: number, filename: string, params: { invoiceDate: string; invoiceType: string; notes?: string }) => {
|
|
const encodedFilename = encodeURIComponent(filename);
|
|
const res = await api.post<ApiResponse<{ id: number; invoiceDate: string; invoiceType: string; documentPath: string }>>(
|
|
`/emails/${emailId}/attachments/${encodedFilename}/save-as-invoice`,
|
|
params
|
|
);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Contracts - Vertragsbaum für Kundenansicht
|
|
export interface ContractTreeNodeContract {
|
|
id: number;
|
|
contractNumber: string;
|
|
type: string;
|
|
status: string;
|
|
startDate: string | null;
|
|
endDate: string | null;
|
|
providerName: string | null;
|
|
tariffName: string | null;
|
|
previousContractId: number | null;
|
|
provider?: { id: number; name: string } | null;
|
|
tariff?: { id: number; name: string } | null;
|
|
contractCategory?: { id: number; name: string } | null;
|
|
}
|
|
|
|
export interface ContractTreeNode {
|
|
contract: ContractTreeNodeContract;
|
|
predecessors: ContractTreeNode[];
|
|
hasHistory: boolean;
|
|
}
|
|
|
|
export const contractApi = {
|
|
getAll: async (params?: { customerId?: number; type?: string; status?: string; search?: string; page?: number; limit?: number }) => {
|
|
const res = await api.get<ApiResponse<Contract[]>>('/contracts', { params });
|
|
return res.data;
|
|
},
|
|
getTreeForCustomer: async (customerId: number) => {
|
|
const res = await api.get<ApiResponse<ContractTreeNode[]>>('/contracts', { params: { customerId, tree: 'true' } });
|
|
return res.data;
|
|
},
|
|
getById: async (id: number) => {
|
|
const res = await api.get<ApiResponse<Contract>>(`/contracts/${id}`);
|
|
return res.data;
|
|
},
|
|
create: async (data: Partial<Contract> & { [key: string]: unknown }) => {
|
|
const res = await api.post<ApiResponse<Contract>>('/contracts', data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<Contract> & { [key: string]: unknown }) => {
|
|
const res = await api.put<ApiResponse<Contract>>(`/contracts/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/contracts/${id}`);
|
|
return res.data;
|
|
},
|
|
createFollowUp: async (id: number) => {
|
|
const res = await api.post<ApiResponse<Contract>>(`/contracts/${id}/follow-up`);
|
|
return res.data;
|
|
},
|
|
getPassword: async (id: number) => {
|
|
const res = await api.get<ApiResponse<{ password: string }>>(`/contracts/${id}/password`);
|
|
return res.data;
|
|
},
|
|
getSimCardCredentials: async (simCardId: number) => {
|
|
const res = await api.get<ApiResponse<{ pin: string | null; puk: string | null }>>(`/contracts/simcard/${simCardId}/credentials`);
|
|
return res.data;
|
|
},
|
|
getInternetCredentials: async (contractId: number) => {
|
|
const res = await api.get<ApiResponse<{ password: string | null }>>(`/contracts/${contractId}/internet-credentials`);
|
|
return res.data;
|
|
},
|
|
getSipCredentials: async (phoneNumberId: number) => {
|
|
const res = await api.get<ApiResponse<{ password: string | null }>>(`/contracts/phonenumber/${phoneNumberId}/sip-credentials`);
|
|
return res.data;
|
|
},
|
|
// Vertrags-Cockpit
|
|
getCockpit: async () => {
|
|
const res = await api.get<ApiResponse<import('../types').CockpitResult>>('/contracts/cockpit');
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Contract Tasks (Aufgaben)
|
|
export const contractTaskApi = {
|
|
// Alle Tasks über alle Verträge (für Task-Liste & Dashboard)
|
|
getAll: async (params?: { status?: ContractTaskStatus; customerId?: number }) => {
|
|
const res = await api.get<ApiResponse<ContractTask[]>>('/tasks', { params });
|
|
return res.data;
|
|
},
|
|
// Task-Statistik (offene Aufgaben)
|
|
getStats: async () => {
|
|
const res = await api.get<ApiResponse<{ openCount: number }>>('/tasks/stats');
|
|
return res.data;
|
|
},
|
|
// Tasks für einen spezifischen Vertrag
|
|
getByContract: async (contractId: number, status?: ContractTaskStatus) => {
|
|
const res = await api.get<ApiResponse<ContractTask[]>>(`/contracts/${contractId}/tasks`, { params: { status } });
|
|
return res.data;
|
|
},
|
|
create: async (contractId: number, data: { title: string; description?: string; visibleInPortal?: boolean }) => {
|
|
const res = await api.post<ApiResponse<ContractTask>>(`/contracts/${contractId}/tasks`, data);
|
|
return res.data;
|
|
},
|
|
update: async (taskId: number, data: { title?: string; description?: string; visibleInPortal?: boolean }) => {
|
|
const res = await api.put<ApiResponse<ContractTask>>(`/tasks/${taskId}`, data);
|
|
return res.data;
|
|
},
|
|
complete: async (taskId: number) => {
|
|
const res = await api.post<ApiResponse<ContractTask>>(`/tasks/${taskId}/complete`);
|
|
return res.data;
|
|
},
|
|
reopen: async (taskId: number) => {
|
|
const res = await api.post<ApiResponse<ContractTask>>(`/tasks/${taskId}/reopen`);
|
|
return res.data;
|
|
},
|
|
delete: async (taskId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/tasks/${taskId}`);
|
|
return res.data;
|
|
},
|
|
// Subtasks
|
|
createSubtask: async (taskId: number, title: string) => {
|
|
const res = await api.post<ApiResponse<ContractTaskSubtask>>(`/tasks/${taskId}/subtasks`, { title });
|
|
return res.data;
|
|
},
|
|
// Kundenportal: Antwort auf eigenes Ticket
|
|
createReply: async (taskId: number, title: string) => {
|
|
const res = await api.post<ApiResponse<ContractTaskSubtask>>(`/tasks/${taskId}/reply`, { title });
|
|
return res.data;
|
|
},
|
|
updateSubtask: async (subtaskId: number, title: string) => {
|
|
const res = await api.put<ApiResponse<ContractTaskSubtask>>(`/subtasks/${subtaskId}`, { title });
|
|
return res.data;
|
|
},
|
|
completeSubtask: async (subtaskId: number) => {
|
|
const res = await api.post<ApiResponse<ContractTaskSubtask>>(`/subtasks/${subtaskId}/complete`);
|
|
return res.data;
|
|
},
|
|
reopenSubtask: async (subtaskId: number) => {
|
|
const res = await api.post<ApiResponse<ContractTaskSubtask>>(`/subtasks/${subtaskId}/reopen`);
|
|
return res.data;
|
|
},
|
|
deleteSubtask: async (subtaskId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/subtasks/${subtaskId}`);
|
|
return res.data;
|
|
},
|
|
// Support-Ticket erstellen (für Kundenportal)
|
|
createSupportTicket: async (contractId: number, data: { title: string; description?: string }) => {
|
|
const res = await api.post<ApiResponse<ContractTask>>(`/contracts/${contractId}/support-ticket`, data);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// App Settings
|
|
export const appSettingsApi = {
|
|
getPublic: async () => {
|
|
const res = await api.get<ApiResponse<Record<string, string>>>('/settings/public');
|
|
return res.data;
|
|
},
|
|
getAll: async () => {
|
|
const res = await api.get<ApiResponse<Record<string, string>>>('/settings');
|
|
return res.data;
|
|
},
|
|
update: async (settings: Record<string, string>) => {
|
|
const res = await api.put<ApiResponse<void>>('/settings', settings);
|
|
return res.data;
|
|
},
|
|
updateOne: async (key: string, value: string) => {
|
|
const res = await api.put<ApiResponse<void>>(`/settings/${key}`, { value });
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Backup & Restore
|
|
export interface BackupInfo {
|
|
name: string;
|
|
timestamp: string;
|
|
totalRecords: number;
|
|
tables: { table: string; count: number }[];
|
|
sizeBytes: number;
|
|
hasUploads: boolean;
|
|
uploadSizeBytes: number;
|
|
}
|
|
|
|
export const backupApi = {
|
|
list: async () => {
|
|
const res = await api.get<ApiResponse<BackupInfo[]>>('/settings/backups');
|
|
return res.data;
|
|
},
|
|
create: async () => {
|
|
const res = await api.post<ApiResponse<{ backupName: string }>>('/settings/backup');
|
|
return res.data;
|
|
},
|
|
restore: async (name: string) => {
|
|
const res = await api.post<ApiResponse<{ restoredRecords: number; restoredFiles: number }>>(`/settings/backup/${name}/restore`);
|
|
return res.data;
|
|
},
|
|
delete: async (name: string) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/settings/backup/${name}`);
|
|
return res.data;
|
|
},
|
|
getDownloadUrl: (name: string) => {
|
|
return `/api/settings/backup/${name}/download`;
|
|
},
|
|
upload: async (file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('backup', file);
|
|
const res = await api.post<ApiResponse<{ backupName: string }>>('/settings/backup/upload', formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
factoryReset: async () => {
|
|
const res = await api.post<ApiResponse<void>>('/settings/factory-reset');
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Platforms
|
|
export const platformApi = {
|
|
getAll: async (includeInactive = false) => {
|
|
const res = await api.get<ApiResponse<SalesPlatform[]>>('/platforms', { params: { includeInactive } });
|
|
return res.data;
|
|
},
|
|
getById: async (id: number) => {
|
|
const res = await api.get<ApiResponse<SalesPlatform>>(`/platforms/${id}`);
|
|
return res.data;
|
|
},
|
|
create: async (data: Partial<SalesPlatform>) => {
|
|
const res = await api.post<ApiResponse<SalesPlatform>>('/platforms', data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<SalesPlatform>) => {
|
|
const res = await api.put<ApiResponse<SalesPlatform>>(`/platforms/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/platforms/${id}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Cancellation Periods
|
|
export const cancellationPeriodApi = {
|
|
getAll: async (includeInactive = false) => {
|
|
const res = await api.get<ApiResponse<CancellationPeriod[]>>('/cancellation-periods', { params: { includeInactive } });
|
|
return res.data;
|
|
},
|
|
getById: async (id: number) => {
|
|
const res = await api.get<ApiResponse<CancellationPeriod>>(`/cancellation-periods/${id}`);
|
|
return res.data;
|
|
},
|
|
create: async (data: Partial<CancellationPeriod>) => {
|
|
const res = await api.post<ApiResponse<CancellationPeriod>>('/cancellation-periods', data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<CancellationPeriod>) => {
|
|
const res = await api.put<ApiResponse<CancellationPeriod>>(`/cancellation-periods/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/cancellation-periods/${id}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Contract Durations
|
|
export const contractDurationApi = {
|
|
getAll: async (includeInactive = false) => {
|
|
const res = await api.get<ApiResponse<ContractDuration[]>>('/contract-durations', { params: { includeInactive } });
|
|
return res.data;
|
|
},
|
|
getById: async (id: number) => {
|
|
const res = await api.get<ApiResponse<ContractDuration>>(`/contract-durations/${id}`);
|
|
return res.data;
|
|
},
|
|
create: async (data: Partial<ContractDuration>) => {
|
|
const res = await api.post<ApiResponse<ContractDuration>>('/contract-durations', data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<ContractDuration>) => {
|
|
const res = await api.put<ApiResponse<ContractDuration>>(`/contract-durations/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/contract-durations/${id}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Contract Categories (Vertragstypen)
|
|
export const contractCategoryApi = {
|
|
getAll: async (includeInactive = false) => {
|
|
const res = await api.get<ApiResponse<ContractCategory[]>>('/contract-categories', { params: { includeInactive } });
|
|
return res.data;
|
|
},
|
|
getById: async (id: number) => {
|
|
const res = await api.get<ApiResponse<ContractCategory>>(`/contract-categories/${id}`);
|
|
return res.data;
|
|
},
|
|
create: async (data: Partial<ContractCategory>) => {
|
|
const res = await api.post<ApiResponse<ContractCategory>>('/contract-categories', data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<ContractCategory>) => {
|
|
const res = await api.put<ApiResponse<ContractCategory>>(`/contract-categories/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/contract-categories/${id}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Providers (Anbieter)
|
|
export const providerApi = {
|
|
getAll: async (includeInactive = false) => {
|
|
const res = await api.get<ApiResponse<Provider[]>>('/providers', { params: { includeInactive } });
|
|
return res.data;
|
|
},
|
|
getById: async (id: number) => {
|
|
const res = await api.get<ApiResponse<Provider>>(`/providers/${id}`);
|
|
return res.data;
|
|
},
|
|
create: async (data: Partial<Provider>) => {
|
|
const res = await api.post<ApiResponse<Provider>>('/providers', data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<Provider>) => {
|
|
const res = await api.put<ApiResponse<Provider>>(`/providers/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/providers/${id}`);
|
|
return res.data;
|
|
},
|
|
getTariffs: async (providerId: number, includeInactive = false) => {
|
|
const res = await api.get<ApiResponse<Tariff[]>>(`/providers/${providerId}/tariffs`, { params: { includeInactive } });
|
|
return res.data;
|
|
},
|
|
createTariff: async (providerId: number, data: Partial<Tariff>) => {
|
|
const res = await api.post<ApiResponse<Tariff>>(`/providers/${providerId}/tariffs`, data);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Tariffs (Tarife)
|
|
export const tariffApi = {
|
|
getById: async (id: number) => {
|
|
const res = await api.get<ApiResponse<Tariff>>(`/tariffs/${id}`);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<Tariff>) => {
|
|
const res = await api.put<ApiResponse<Tariff>>(`/tariffs/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/tariffs/${id}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Upload
|
|
export const uploadApi = {
|
|
uploadBankCardDocument: async (bankCardId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(`/upload/bank-cards/${bankCardId}`, formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
uploadIdentityDocument: async (documentId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(`/upload/documents/${documentId}`, formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
deleteBankCardDocument: async (bankCardId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/bank-cards/${bankCardId}`);
|
|
return res.data;
|
|
},
|
|
deleteIdentityDocument: async (documentId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/documents/${documentId}`);
|
|
return res.data;
|
|
},
|
|
uploadBusinessRegistration: async (customerId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(`/upload/customers/${customerId}/business-registration`, formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
deleteBusinessRegistration: async (customerId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/customers/${customerId}/business-registration`);
|
|
return res.data;
|
|
},
|
|
uploadCommercialRegister: async (customerId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(`/upload/customers/${customerId}/commercial-register`, formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
deleteCommercialRegister: async (customerId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/customers/${customerId}/commercial-register`);
|
|
return res.data;
|
|
},
|
|
uploadPrivacyPolicy: async (customerId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(`/upload/customers/${customerId}/privacy-policy`, formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
deletePrivacyPolicy: async (customerId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/customers/${customerId}/privacy-policy`);
|
|
return res.data;
|
|
},
|
|
// Contract Documents
|
|
uploadCancellationLetter: async (contractId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(`/upload/contracts/${contractId}/cancellation-letter`, formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
deleteCancellationLetter: async (contractId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/contracts/${contractId}/cancellation-letter`);
|
|
return res.data;
|
|
},
|
|
uploadCancellationConfirmation: async (contractId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(`/upload/contracts/${contractId}/cancellation-confirmation`, formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
deleteCancellationConfirmation: async (contractId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/contracts/${contractId}/cancellation-confirmation`);
|
|
return res.data;
|
|
},
|
|
uploadCancellationLetterOptions: async (contractId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(`/upload/contracts/${contractId}/cancellation-letter-options`, formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
deleteCancellationLetterOptions: async (contractId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/contracts/${contractId}/cancellation-letter-options`);
|
|
return res.data;
|
|
},
|
|
uploadCancellationConfirmationOptions: async (contractId: number, file: File) => {
|
|
const formData = new FormData();
|
|
formData.append('document', file);
|
|
const res = await api.post<ApiResponse<{ path: string; filename: string }>>(`/upload/contracts/${contractId}/cancellation-confirmation-options`, formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return res.data;
|
|
},
|
|
deleteCancellationConfirmationOptions: async (contractId: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/upload/contracts/${contractId}/cancellation-confirmation-options`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Users
|
|
export const userApi = {
|
|
getAll: async (params?: { search?: string; isActive?: boolean; roleId?: number; page?: number; limit?: number }) => {
|
|
const res = await api.get<ApiResponse<User[]>>('/users', { params });
|
|
return res.data;
|
|
},
|
|
getById: async (id: number) => {
|
|
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 }) => {
|
|
const res = await api.post<ApiResponse<User>>('/users', data);
|
|
return res.data;
|
|
},
|
|
update: async (id: number, data: Partial<User> & { password?: string; roleIds?: number[] }) => {
|
|
const res = await api.put<ApiResponse<User>>(`/users/${id}`, data);
|
|
return res.data;
|
|
},
|
|
delete: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/users/${id}`);
|
|
return res.data;
|
|
},
|
|
getRoles: async () => {
|
|
const res = await api.get<ApiResponse<Role[]>>('/users/roles/list');
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Developer
|
|
export const developerApi = {
|
|
getSchema: async () => {
|
|
const res = await api.get<ApiResponse<any[]>>('/developer/schema');
|
|
return res.data;
|
|
},
|
|
getTableData: async (tableName: string, page = 1, limit = 50) => {
|
|
const res = await api.get<ApiResponse<any[]>>(`/developer/table/${tableName}`, { params: { page, limit } });
|
|
return res.data;
|
|
},
|
|
updateRow: async (tableName: string, id: string, data: Record<string, any>) => {
|
|
const res = await api.put<ApiResponse<any>>(`/developer/table/${tableName}/${id}`, data);
|
|
return res.data;
|
|
},
|
|
deleteRow: async (tableName: string, id: string) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/developer/table/${tableName}/${id}`);
|
|
return res.data;
|
|
},
|
|
getReference: async (tableName: string) => {
|
|
const res = await api.get<ApiResponse<any[]>>(`/developer/reference/${tableName}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
// Email Provider (für Stressfrei-Wechseln Provisionierung)
|
|
export interface EmailProviderConfig {
|
|
id: number;
|
|
name: string;
|
|
type: 'PLESK' | 'CPANEL' | 'DIRECTADMIN';
|
|
apiUrl: string;
|
|
apiKey?: string;
|
|
username?: string;
|
|
passwordEncrypted?: string;
|
|
domain: string;
|
|
defaultForwardEmail?: string;
|
|
// IMAP/SMTP-Server (für E-Mail-Client)
|
|
imapServer?: string;
|
|
imapPort?: number;
|
|
smtpServer?: string;
|
|
smtpPort?: number;
|
|
// Verschlüsselungs-Einstellungen
|
|
imapEncryption?: 'SSL' | 'STARTTLS' | 'NONE';
|
|
smtpEncryption?: 'SSL' | 'STARTTLS' | 'NONE';
|
|
allowSelfSignedCerts?: boolean; // Selbstsignierte Zertifikate erlauben
|
|
isActive: boolean;
|
|
isDefault: boolean;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface EmailOperationResult {
|
|
success: boolean;
|
|
message?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export const emailProviderApi = {
|
|
// Config CRUD
|
|
getConfigs: async () => {
|
|
const res = await api.get<ApiResponse<EmailProviderConfig[]>>('/email-providers/configs');
|
|
return res.data;
|
|
},
|
|
getConfig: async (id: number) => {
|
|
const res = await api.get<ApiResponse<EmailProviderConfig>>(`/email-providers/configs/${id}`);
|
|
return res.data;
|
|
},
|
|
createConfig: async (data: Partial<EmailProviderConfig> & { password?: string }) => {
|
|
const res = await api.post<ApiResponse<EmailProviderConfig>>('/email-providers/configs', data);
|
|
return res.data;
|
|
},
|
|
updateConfig: async (id: number, data: Partial<EmailProviderConfig> & { password?: string }) => {
|
|
const res = await api.put<ApiResponse<EmailProviderConfig>>(`/email-providers/configs/${id}`, data);
|
|
return res.data;
|
|
},
|
|
deleteConfig: async (id: number) => {
|
|
const res = await api.delete<ApiResponse<void>>(`/email-providers/configs/${id}`);
|
|
return res.data;
|
|
},
|
|
// Email Operations
|
|
testConnection: async (options?: {
|
|
id?: number;
|
|
testData?: {
|
|
type: 'PLESK' | 'CPANEL' | 'DIRECTADMIN';
|
|
apiUrl: string;
|
|
apiKey?: string;
|
|
username?: string;
|
|
password?: string;
|
|
domain: string;
|
|
};
|
|
}) => {
|
|
const body = options?.testData
|
|
? { ...options.testData }
|
|
: options?.id
|
|
? { id: options.id }
|
|
: {};
|
|
const res = await api.post<ApiResponse<EmailOperationResult>>('/email-providers/test-connection', body);
|
|
return res.data;
|
|
},
|
|
getDomain: async () => {
|
|
const res = await api.get<ApiResponse<{ domain: string | null }>>('/email-providers/domain');
|
|
return res.data;
|
|
},
|
|
checkEmailExists: async (localPart: string) => {
|
|
const res = await api.get<ApiResponse<{ exists: boolean; email?: string }>>(`/email-providers/check/${localPart}`);
|
|
return res.data;
|
|
},
|
|
provisionEmail: async (localPart: string, customerEmail: string) => {
|
|
const res = await api.post<ApiResponse<EmailOperationResult>>('/email-providers/provision', { localPart, customerEmail });
|
|
return res.data;
|
|
},
|
|
deprovisionEmail: async (localPart: string) => {
|
|
const res = await api.delete<ApiResponse<EmailOperationResult>>(`/email-providers/deprovision/${localPart}`);
|
|
return res.data;
|
|
},
|
|
};
|
|
|
|
export default api;
|