1005 lines
27 KiB
TypeScript
1005 lines
27 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;
|
|
sysCreatedAt?: number;
|
|
sysModifiedAt?: number;
|
|
sysCreatedBy?: string;
|
|
sysModifiedBy?: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
export interface TrusteeRole {
|
|
id: string;
|
|
desc: string;
|
|
mandateId?: string;
|
|
sysCreatedAt?: number;
|
|
sysModifiedAt?: number;
|
|
sysCreatedBy?: string;
|
|
sysModifiedBy?: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
export interface TrusteeAccess {
|
|
id: string;
|
|
organisationId: string;
|
|
roleId: string;
|
|
userId: string;
|
|
contractId?: string | null;
|
|
mandateId?: string;
|
|
sysCreatedAt?: number;
|
|
sysModifiedAt?: number;
|
|
sysCreatedBy?: string;
|
|
sysModifiedBy?: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
export interface TrusteeContract {
|
|
id: string;
|
|
organisationId: string;
|
|
label: string;
|
|
enabled: boolean;
|
|
mandateId?: string;
|
|
sysCreatedAt?: number;
|
|
sysModifiedAt?: number;
|
|
sysCreatedBy?: string;
|
|
sysModifiedBy?: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
export interface TrusteeDocument {
|
|
id: string;
|
|
organisationId: string;
|
|
contractId: string;
|
|
documentName: string;
|
|
documentMimeType: string;
|
|
documentData?: any;
|
|
mandateId?: string;
|
|
sysCreatedAt?: number;
|
|
sysModifiedAt?: number;
|
|
sysCreatedBy?: string;
|
|
sysModifiedBy?: 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;
|
|
sysCreatedAt?: number;
|
|
sysModifiedAt?: number;
|
|
sysCreatedBy?: string;
|
|
sysModifiedBy?: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
export interface AccountingConnectorInfo {
|
|
connectorType: string;
|
|
label: string;
|
|
configFields: Array<{
|
|
key: string;
|
|
label: string;
|
|
fieldType: string;
|
|
secret: boolean;
|
|
required: boolean;
|
|
placeholder?: string;
|
|
suggestions?: 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;
|
|
sysCreatedAt?: number;
|
|
sysModifiedAt?: 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'
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// QUICK ACTIONS API
|
|
// ============================================================================
|
|
|
|
export interface QuickActionResponse {
|
|
actions: Array<{
|
|
id: string;
|
|
label: string;
|
|
description: string;
|
|
icon: string;
|
|
color: string;
|
|
category: string;
|
|
actionType: 'agentPrompt' | 'workflow' | 'link';
|
|
config: Record<string, any>;
|
|
sortOrder: number;
|
|
}>;
|
|
categories: Array<{
|
|
id: string;
|
|
label: string;
|
|
sortOrder: number;
|
|
}>;
|
|
}
|
|
|
|
export async function fetchQuickActions(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
language: string = 'de'
|
|
): Promise<QuickActionResponse> {
|
|
return await request({
|
|
url: `${_getTrusteeBaseUrl(instanceId)}/quick-actions`,
|
|
method: 'get',
|
|
params: { language }
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// 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'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Submits a background job that pushes positions to the accounting system and
|
|
* polls `/api/jobs/{jobId}` until the job reaches a terminal status. Returns
|
|
* the same `{ total, success, skipped, errors, results }` payload that the
|
|
* legacy synchronous endpoint used to return -- but does NOT block the user
|
|
* while the (potentially long) external accounting calls run in the worker.
|
|
*/
|
|
export async function syncPositionsToAccounting(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
positionIds: string[],
|
|
opts?: { pollMs?: number; onProgress?: (progress: number, message?: string | null) => void }
|
|
): Promise<{ total: number; success: number; skipped?: number; errors: number; results: any[] }> {
|
|
const submission = await request({
|
|
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/sync`,
|
|
method: 'post',
|
|
data: { positionIds }
|
|
});
|
|
|
|
const jobId: string | undefined = submission?.jobId;
|
|
if (!jobId) {
|
|
throw new Error('Background job could not be started (missing jobId).');
|
|
}
|
|
|
|
const pollMs = opts?.pollMs ?? 1500;
|
|
const TERMINAL = new Set(['SUCCESS', 'ERROR', 'CANCELLED']);
|
|
|
|
while (true) {
|
|
const job = await request({ url: `/api/jobs/${jobId}`, method: 'get' });
|
|
if (opts?.onProgress) {
|
|
opts.onProgress(Number(job?.progress ?? 0), job?.progressMessage ?? null);
|
|
}
|
|
if (job?.status && TERMINAL.has(job.status)) {
|
|
if (job.status === 'SUCCESS' && job.result) {
|
|
return job.result;
|
|
}
|
|
throw new Error(job?.errorMessage || 'Sync-Job fehlgeschlagen');
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
}
|
|
}
|
|
|
|
export async function fetchSyncStatus(
|
|
request: ApiRequestFunction,
|
|
instanceId: string
|
|
): Promise<{ items: AccountingSyncStatus[] }> {
|
|
return await request({
|
|
url: `${_getTrusteeBaseUrl(instanceId)}/accounting/sync-status`,
|
|
method: 'get'
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// READ-ONLY DATA TABLE API (Daten-Tabellen page)
|
|
// ============================================================================
|
|
//
|
|
// Generic read-only endpoints for the consolidated data tables view.
|
|
// All entities are paginated, sortable, filterable via the Unified Filter API
|
|
// (mode=filterValues / mode=ids); no CRUD writes are exposed by these helpers.
|
|
|
|
export interface TrusteeDataAccount { id: string; [key: string]: any; }
|
|
export interface TrusteeDataJournalEntry { id: string; [key: string]: any; }
|
|
export interface TrusteeDataJournalLine { id: string; [key: string]: any; }
|
|
export interface TrusteeDataContact { id: string; [key: string]: any; }
|
|
export interface TrusteeDataAccountBalance { id: string; [key: string]: any; }
|
|
export interface TrusteeAccountingConfigRecord { id: string; [key: string]: any; }
|
|
export interface TrusteeAccountingSyncRecord { id: string; [key: string]: any; }
|
|
|
|
async function _fetchReadOnlyTable<T = any>(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
pathSegment: string,
|
|
params?: PaginationParams
|
|
): Promise<PaginatedResponse<T> | T[]> {
|
|
return await request({
|
|
url: `${_getTrusteeBaseUrl(instanceId)}/${pathSegment}`,
|
|
method: 'get',
|
|
params: _buildPaginationParams(params),
|
|
});
|
|
}
|
|
|
|
export async function fetchDataAccounts(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
params?: PaginationParams
|
|
): Promise<PaginatedResponse<TrusteeDataAccount> | TrusteeDataAccount[]> {
|
|
return _fetchReadOnlyTable<TrusteeDataAccount>(request, instanceId, 'data/accounts', params);
|
|
}
|
|
|
|
export async function fetchDataJournalEntries(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
params?: PaginationParams
|
|
): Promise<PaginatedResponse<TrusteeDataJournalEntry> | TrusteeDataJournalEntry[]> {
|
|
return _fetchReadOnlyTable<TrusteeDataJournalEntry>(request, instanceId, 'data/journal-entries', params);
|
|
}
|
|
|
|
export async function fetchDataJournalLines(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
params?: PaginationParams
|
|
): Promise<PaginatedResponse<TrusteeDataJournalLine> | TrusteeDataJournalLine[]> {
|
|
return _fetchReadOnlyTable<TrusteeDataJournalLine>(request, instanceId, 'data/journal-lines', params);
|
|
}
|
|
|
|
export async function fetchDataContacts(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
params?: PaginationParams
|
|
): Promise<PaginatedResponse<TrusteeDataContact> | TrusteeDataContact[]> {
|
|
return _fetchReadOnlyTable<TrusteeDataContact>(request, instanceId, 'data/contacts', params);
|
|
}
|
|
|
|
export async function fetchDataAccountBalances(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
params?: PaginationParams
|
|
): Promise<PaginatedResponse<TrusteeDataAccountBalance> | TrusteeDataAccountBalance[]> {
|
|
return _fetchReadOnlyTable<TrusteeDataAccountBalance>(request, instanceId, 'data/account-balances', params);
|
|
}
|
|
|
|
export async function fetchAccountingConfigs(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
params?: PaginationParams
|
|
): Promise<PaginatedResponse<TrusteeAccountingConfigRecord> | TrusteeAccountingConfigRecord[]> {
|
|
return _fetchReadOnlyTable<TrusteeAccountingConfigRecord>(request, instanceId, 'accounting/configs', params);
|
|
}
|
|
|
|
export async function fetchAccountingSyncs(
|
|
request: ApiRequestFunction,
|
|
instanceId: string,
|
|
params?: PaginationParams
|
|
): Promise<PaginatedResponse<TrusteeAccountingSyncRecord> | TrusteeAccountingSyncRecord[]> {
|
|
return _fetchReadOnlyTable<TrusteeAccountingSyncRecord>(request, instanceId, 'accounting/syncs', params);
|
|
}
|
|
|
|
export async function exportAccountingData(
|
|
request: ApiRequestFunction,
|
|
instanceId: string
|
|
): Promise<void> {
|
|
const url = `${_getTrusteeBaseUrl(instanceId)}/accounting/export-data`;
|
|
const response = await request({ url, method: 'get' });
|
|
const blob = new Blob([JSON.stringify(response, null, 2)], { type: 'application/json' });
|
|
const link = document.createElement('a');
|
|
link.href = URL.createObjectURL(blob);
|
|
link.download = `trustee_data_${instanceId.slice(0, 8)}.json`;
|
|
link.click();
|
|
URL.revokeObjectURL(link.href);
|
|
}
|