frontend_nyla/src/api/trusteeApi.ts
ValueOn AG cae8386544 fix TS build errors and add position-documents API
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-22 22:51:29 +01:00

840 lines
21 KiB
TypeScript

/**
* Trustee API
*
* API-Funktionen für das Trustee-Feature.
* Alle Endpunkte erfordern eine instanceId für den Feature-Instanz-Kontext.
*
* URL-Struktur: /api/trustee/{instanceId}/{entity}
*/
import { ApiRequestOptions } from '../hooks/useApi';
// ============================================================================
// TYPES & INTERFACES
// ============================================================================
export interface TrusteeOrganisation {
id: string;
label: string;
enabled: boolean;
mandateId?: string;
_createdAt?: number;
_modifiedAt?: number;
_createdBy?: string;
_modifiedBy?: string;
[key: string]: any;
}
export interface TrusteeRole {
id: string;
desc: string;
mandateId?: string;
_createdAt?: number;
_modifiedAt?: number;
_createdBy?: string;
_modifiedBy?: string;
[key: string]: any;
}
export interface TrusteeAccess {
id: string;
organisationId: string;
roleId: string;
userId: string;
contractId?: string | null;
mandateId?: string;
_createdAt?: number;
_modifiedAt?: number;
_createdBy?: string;
_modifiedBy?: string;
[key: string]: any;
}
export interface TrusteeContract {
id: string;
organisationId: string;
label: string;
enabled: boolean;
mandateId?: string;
_createdAt?: number;
_modifiedAt?: number;
_createdBy?: string;
_modifiedBy?: string;
[key: string]: any;
}
export interface TrusteeDocument {
id: string;
organisationId: string;
contractId: string;
documentName: string;
documentMimeType: string;
documentData?: any;
mandateId?: string;
_createdAt?: number;
_modifiedAt?: number;
_createdBy?: string;
_modifiedBy?: string;
[key: string]: any;
}
export interface TrusteePosition {
id: string;
documentId?: string;
valuta?: string;
transactionDateTime?: number;
company: string;
desc: string;
tags: string;
bookingCurrency: string;
bookingAmount: number;
originalCurrency: string;
originalAmount: number;
vatPercentage: number;
vatAmount: number;
debitAccountNumber?: string;
creditAccountNumber?: string;
taxCode?: string;
costCenter?: string;
bookingReference?: string;
mandateId?: string;
_createdAt?: number;
_modifiedAt?: number;
_createdBy?: string;
_modifiedBy?: string;
[key: string]: any;
}
export interface AccountingConnectorInfo {
connectorType: string;
label: Record<string, string>;
configFields: Array<{
key: string;
label: Record<string, string>;
fieldType: string;
secret: boolean;
required: boolean;
placeholder?: string;
}>;
}
export interface AccountingConfig {
configured: boolean;
id?: string;
connectorType?: string;
displayLabel?: string;
isActive?: boolean;
lastSyncAt?: number;
lastSyncStatus?: string;
/** Error message when lastSyncStatus is "error". */
lastSyncErrorMessage?: string;
/** Masked config for form prefill: secret fields are "***", others have saved values. */
configMasked?: Record<string, string>;
}
export interface AccountingSyncStatus {
id: string;
positionId: string;
connectorType: string;
externalId?: string;
syncStatus: string;
syncedAt?: number;
errorMessage?: string;
}
export interface PaginationParams {
page?: number;
pageSize?: number;
sort?: Array<{ field: string; direction: 'asc' | 'desc' }>;
filters?: Record<string, any>;
search?: string;
}
export interface PaginatedResponse<T> {
items: T[];
pagination?: {
currentPage: number;
pageSize: number;
totalItems: number;
totalPages: number;
};
}
export type ApiRequestFunction = (options: ApiRequestOptions<any>) => Promise<any>;
// ============================================================================
// HELPER FUNCTIONS
// ============================================================================
function _buildPaginationParams(params?: PaginationParams): Record<string, any> {
const requestParams: any = {};
if (params) {
const paginationObj: any = {};
if (params.page !== undefined) paginationObj.page = params.page;
if (params.pageSize !== undefined) paginationObj.pageSize = params.pageSize;
if (params.sort) paginationObj.sort = params.sort;
if (params.filters) paginationObj.filters = params.filters;
if (params.search) paginationObj.search = params.search;
if (Object.keys(paginationObj).length > 0) {
requestParams.pagination = JSON.stringify(paginationObj);
}
}
return requestParams;
}
/**
* Erstellt die Basis-URL für Trustee-Endpunkte
*/
function _getTrusteeBaseUrl(instanceId: string): string {
return `/api/trustee/${instanceId}`;
}
// ============================================================================
// ORGANISATION API
// ============================================================================
export async function fetchOrganisations(
request: ApiRequestFunction,
instanceId: string,
params?: PaginationParams
): Promise<PaginatedResponse<TrusteeOrganisation> | TrusteeOrganisation[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/organisations`,
method: 'get',
params: _buildPaginationParams(params)
});
}
export async function fetchOrganisationById(
request: ApiRequestFunction,
instanceId: string,
orgId: string
): Promise<TrusteeOrganisation | null> {
try {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/organisations/${orgId}`,
method: 'get'
});
} catch (error: any) {
console.error('Error fetching organisation by ID:', error);
return null;
}
}
export async function createOrganisation(
request: ApiRequestFunction,
instanceId: string,
data: Partial<TrusteeOrganisation>
): Promise<TrusteeOrganisation> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/organisations`,
method: 'post',
data
});
}
export async function updateOrganisation(
request: ApiRequestFunction,
instanceId: string,
orgId: string,
data: Partial<TrusteeOrganisation>
): Promise<TrusteeOrganisation> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/organisations/${orgId}`,
method: 'put',
data
});
}
export async function deleteOrganisation(
request: ApiRequestFunction,
instanceId: string,
orgId: string
): Promise<void> {
await request({
url: `${_getTrusteeBaseUrl(instanceId)}/organisations/${orgId}`,
method: 'delete'
});
}
// ============================================================================
// ROLE API
// ============================================================================
export async function fetchRoles(
request: ApiRequestFunction,
instanceId: string,
params?: PaginationParams
): Promise<PaginatedResponse<TrusteeRole> | TrusteeRole[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/roles`,
method: 'get',
params: _buildPaginationParams(params)
});
}
export async function fetchRoleById(
request: ApiRequestFunction,
instanceId: string,
roleId: string
): Promise<TrusteeRole | null> {
try {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/roles/${roleId}`,
method: 'get'
});
} catch (error: any) {
console.error('Error fetching role by ID:', error);
return null;
}
}
export async function createRole(
request: ApiRequestFunction,
instanceId: string,
data: Partial<TrusteeRole>
): Promise<TrusteeRole> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/roles`,
method: 'post',
data
});
}
export async function updateRole(
request: ApiRequestFunction,
instanceId: string,
roleId: string,
data: Partial<TrusteeRole>
): Promise<TrusteeRole> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/roles/${roleId}`,
method: 'put',
data
});
}
export async function deleteRole(
request: ApiRequestFunction,
instanceId: string,
roleId: string
): Promise<void> {
await request({
url: `${_getTrusteeBaseUrl(instanceId)}/roles/${roleId}`,
method: 'delete'
});
}
// ============================================================================
// ACCESS API
// ============================================================================
export async function fetchAccess(
request: ApiRequestFunction,
instanceId: string,
params?: PaginationParams
): Promise<PaginatedResponse<TrusteeAccess> | TrusteeAccess[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/access`,
method: 'get',
params: _buildPaginationParams(params)
});
}
export async function fetchAccessById(
request: ApiRequestFunction,
instanceId: string,
accessId: string
): Promise<TrusteeAccess | null> {
try {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/access/${accessId}`,
method: 'get'
});
} catch (error: any) {
console.error('Error fetching access by ID:', error);
return null;
}
}
export async function fetchAccessByOrganisation(
request: ApiRequestFunction,
instanceId: string,
orgId: string
): Promise<TrusteeAccess[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/access/organisation/${orgId}`,
method: 'get'
});
}
export async function fetchAccessByUser(
request: ApiRequestFunction,
instanceId: string,
userId: string
): Promise<TrusteeAccess[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/access/user/${userId}`,
method: 'get'
});
}
export async function createAccess(
request: ApiRequestFunction,
instanceId: string,
data: Partial<TrusteeAccess>
): Promise<TrusteeAccess> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/access`,
method: 'post',
data
});
}
export async function updateAccess(
request: ApiRequestFunction,
instanceId: string,
accessId: string,
data: Partial<TrusteeAccess>
): Promise<TrusteeAccess> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/access/${accessId}`,
method: 'put',
data
});
}
export async function deleteAccess(
request: ApiRequestFunction,
instanceId: string,
accessId: string
): Promise<void> {
await request({
url: `${_getTrusteeBaseUrl(instanceId)}/access/${accessId}`,
method: 'delete'
});
}
// ============================================================================
// CONTRACT API
// ============================================================================
export async function fetchContracts(
request: ApiRequestFunction,
instanceId: string,
params?: PaginationParams
): Promise<PaginatedResponse<TrusteeContract> | TrusteeContract[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/contracts`,
method: 'get',
params: _buildPaginationParams(params)
});
}
export async function fetchContractById(
request: ApiRequestFunction,
instanceId: string,
contractId: string
): Promise<TrusteeContract | null> {
try {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/contracts/${contractId}`,
method: 'get'
});
} catch (error: any) {
console.error('Error fetching contract by ID:', error);
return null;
}
}
export async function fetchContractsByOrganisation(
request: ApiRequestFunction,
instanceId: string,
orgId: string
): Promise<TrusteeContract[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/contracts/organisation/${orgId}`,
method: 'get'
});
}
export async function createContract(
request: ApiRequestFunction,
instanceId: string,
data: Partial<TrusteeContract>
): Promise<TrusteeContract> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/contracts`,
method: 'post',
data
});
}
export async function updateContract(
request: ApiRequestFunction,
instanceId: string,
contractId: string,
data: Partial<TrusteeContract>
): Promise<TrusteeContract> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/contracts/${contractId}`,
method: 'put',
data
});
}
export async function deleteContract(
request: ApiRequestFunction,
instanceId: string,
contractId: string
): Promise<void> {
await request({
url: `${_getTrusteeBaseUrl(instanceId)}/contracts/${contractId}`,
method: 'delete'
});
}
// ============================================================================
// DOCUMENT API
// ============================================================================
export async function fetchDocuments(
request: ApiRequestFunction,
instanceId: string,
params?: PaginationParams
): Promise<PaginatedResponse<TrusteeDocument> | TrusteeDocument[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/documents`,
method: 'get',
params: _buildPaginationParams(params)
});
}
export async function fetchDocumentById(
request: ApiRequestFunction,
instanceId: string,
documentId: string
): Promise<TrusteeDocument | null> {
try {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/documents/${documentId}`,
method: 'get'
});
} catch (error: any) {
console.error('Error fetching document by ID:', error);
return null;
}
}
export async function fetchDocumentsByContract(
request: ApiRequestFunction,
instanceId: string,
contractId: string
): Promise<TrusteeDocument[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/documents/contract/${contractId}`,
method: 'get'
});
}
export async function createDocument(
request: ApiRequestFunction,
instanceId: string,
data: Partial<TrusteeDocument>
): Promise<TrusteeDocument> {
// If documentData is a File, convert to base64
let processedData = { ...data };
if (data.documentData instanceof File) {
const file = data.documentData as File;
const arrayBuffer = await file.arrayBuffer();
const base64 = btoa(
new Uint8Array(arrayBuffer).reduce((data, byte) => data + String.fromCharCode(byte), '')
);
processedData.documentData = base64 as any;
// Auto-set MIME type from file if not provided
if (!processedData.documentMimeType && file.type) {
processedData.documentMimeType = file.type;
}
// Auto-set name from file if not provided
if (!processedData.documentName && file.name) {
processedData.documentName = file.name;
}
}
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/documents`,
method: 'post',
data: processedData
});
}
export async function updateDocument(
request: ApiRequestFunction,
instanceId: string,
documentId: string,
data: Partial<TrusteeDocument>
): Promise<TrusteeDocument> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/documents/${documentId}`,
method: 'put',
data
});
}
export async function deleteDocument(
request: ApiRequestFunction,
instanceId: string,
documentId: string
): Promise<void> {
await request({
url: `${_getTrusteeBaseUrl(instanceId)}/documents/${documentId}`,
method: 'delete'
});
}
// ============================================================================
// POSITION API
// ============================================================================
export async function fetchPositions(
request: ApiRequestFunction,
instanceId: string,
params?: PaginationParams
): Promise<PaginatedResponse<TrusteePosition> | TrusteePosition[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/positions`,
method: 'get',
params: _buildPaginationParams(params)
});
}
export async function fetchPositionById(
request: ApiRequestFunction,
instanceId: string,
positionId: string
): Promise<TrusteePosition | null> {
try {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/positions/${positionId}`,
method: 'get'
});
} catch (error: any) {
console.error('Error fetching position by ID:', error);
return null;
}
}
export async function fetchPositionsByContract(
request: ApiRequestFunction,
instanceId: string,
contractId: string
): Promise<TrusteePosition[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/positions/contract/${contractId}`,
method: 'get'
});
}
export async function fetchPositionsByOrganisation(
request: ApiRequestFunction,
instanceId: string,
orgId: string
): Promise<TrusteePosition[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/positions/organisation/${orgId}`,
method: 'get'
});
}
export async function createPosition(
request: ApiRequestFunction,
instanceId: string,
data: Partial<TrusteePosition>
): Promise<TrusteePosition> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/positions`,
method: 'post',
data
});
}
export async function updatePosition(
request: ApiRequestFunction,
instanceId: string,
positionId: string,
data: Partial<TrusteePosition>
): Promise<TrusteePosition> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/positions/${positionId}`,
method: 'put',
data
});
}
export async function deletePosition(
request: ApiRequestFunction,
instanceId: string,
positionId: string
): Promise<void> {
await request({
url: `${_getTrusteeBaseUrl(instanceId)}/positions/${positionId}`,
method: 'delete'
});
}
// ============================================================================
// POSITION-DOCUMENT LINK API
// ============================================================================
export interface TrusteePositionDocument {
id: string;
positionId: string;
documentId: string;
mandateId?: string;
featureInstanceId?: string;
_createdAt?: number;
_modifiedAt?: number;
[key: string]: any;
}
export async function fetchPositionDocuments(
request: ApiRequestFunction,
instanceId: string,
params?: PaginationParams
): Promise<PaginatedResponse<TrusteePositionDocument> | TrusteePositionDocument[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/position-documents`,
method: 'get',
params: _buildPaginationParams(params)
});
}
export async function fetchPositionDocumentById(
request: ApiRequestFunction,
instanceId: string,
linkId: string
): Promise<TrusteePositionDocument | null> {
try {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/position-documents/${linkId}`,
method: 'get'
});
} catch {
return null;
}
}
export async function createPositionDocument(
request: ApiRequestFunction,
instanceId: string,
data: Partial<TrusteePositionDocument>
): Promise<TrusteePositionDocument> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/position-documents`,
method: 'post',
data
});
}
export async function deletePositionDocument(
request: ApiRequestFunction,
instanceId: string,
linkId: string
): Promise<void> {
await request({
url: `${_getTrusteeBaseUrl(instanceId)}/position-documents/${linkId}`,
method: 'delete'
});
}
// ============================================================================
// ACCOUNTING API
// ============================================================================
export async function fetchAccountingConnectors(
request: ApiRequestFunction,
instanceId: string
): Promise<AccountingConnectorInfo[]> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/connectors`,
method: 'get'
});
}
export async function fetchAccountingConfig(
request: ApiRequestFunction,
instanceId: string
): Promise<AccountingConfig> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/config`,
method: 'get'
});
}
export async function saveAccountingConfig(
request: ApiRequestFunction,
instanceId: string,
data: { connectorType: string; displayLabel: string; config: Record<string, string> }
): Promise<any> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/config`,
method: 'post',
data
});
}
export async function deleteAccountingConfig(
request: ApiRequestFunction,
instanceId: string
): Promise<void> {
await request({
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/config`,
method: 'delete'
});
}
export async function testAccountingConnection(
request: ApiRequestFunction,
instanceId: string
): Promise<{ success: boolean; errorMessage?: string }> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/test-connection`,
method: 'post'
});
}
export async function fetchChartOfAccounts(
request: ApiRequestFunction,
instanceId: string
): Promise<Array<{ accountNumber: string; label: string; accountType?: string }>> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/chart-of-accounts`,
method: 'get'
});
}
export async function syncPositionsToAccounting(
request: ApiRequestFunction,
instanceId: string,
positionIds: string[]
): Promise<{ total: number; success: number; errors: number; results: any[] }> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/sync`,
method: 'post',
data: { positionIds }
});
}
export async function fetchSyncStatus(
request: ApiRequestFunction,
instanceId: string
): Promise<{ items: AccountingSyncStatus[] }> {
return await request({
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/sync-status`,
method: 'get'
});
}