文件
hyb-oa/client/src/api/assets.ts
T

362 行
9.1 KiB
TypeScript

import { apiRequestData } from "./http";
export type AssetStatus = "in_stock" | "in_use" | "under_repair" | "retired" | "archived";
export type AssetType = "fixed_asset" | "electronic_document" | "electronic_system" | "code_repository" | "backup_media";
export type AssetSensitivityLevel = "public_candidate" | "internal" | "confidential" | "strictly_confidential";
export type AssetCategoryItem = {
id: string;
code: string;
name: string;
documentCategoryId: string | null;
enabled: boolean;
archivedAt: string | null;
createdAt: string | null;
updatedAt: string | null;
documentCategory: {
id: string;
code: string;
name: string;
entityType: string;
} | null;
};
export type AssetAssigneeOption = {
id: string;
employeeNo: string;
name: string;
department: {
id: string;
name: string;
} | null;
};
export type AssetItem = {
id: string;
assetNo: string;
name: string;
assetType: AssetType;
sensitivityLevel: AssetSensitivityLevel;
categoryId: string;
legalEntityId: string;
costCenterId: string;
purchaseRequestId: string | null;
serialNo: string | null;
location: string | null;
status: AssetStatus;
assigneeEmployeeId: string | null;
ownerEmployeeId: string | null;
keeperEmployeeId: string | null;
archiveLocation: string | null;
externalRef: string | null;
sourceHash: string | null;
verificationNo: string | null;
confidentialityNote: string | null;
metadata: Record<string, unknown> | null;
sensitiveFieldsRedacted?: boolean;
lastVerifiedAt: string | null;
expiresAt: string | null;
activatedAt: string | null;
retiredAt: string | null;
createdAt: string | null;
updatedAt: string | null;
category: {
id: string;
code: string;
name: string;
documentCategoryId: string | null;
documentCategory: {
id: string;
code: string;
name: string;
} | null;
} | null;
legalEntity: {
id: string;
code: string;
name: string;
} | null;
costCenter: {
id: string;
code: string;
name: string;
legalEntityId: string;
} | null;
purchaseRequest: {
id: string;
requestNo: string | null;
title: string;
status: string;
} | null;
assignee: {
id: string;
employeeNo: string;
name: string;
department: {
id: string;
name: string;
} | null;
} | null;
owner: AssetAssigneeOption | null;
keeper: AssetAssigneeOption | null;
permissions: {
canEdit: boolean;
};
};
export type AssetCategoryListResponse = {
includeArchived: boolean;
items: AssetCategoryItem[];
};
export type AssetListResponse = {
mine: boolean;
items: AssetItem[];
};
export type AssetListQuery = {
status?: AssetStatus;
assetType?: AssetType;
sensitivityLevel?: AssetSensitivityLevel;
categoryId?: string;
assigneeId?: string;
ownerId?: string;
keeperId?: string;
legalEntityId?: string;
costCenterId?: string;
q?: string;
mine?: boolean;
};
export type CreateAssetPayload = {
name: string;
assetType?: AssetType;
sensitivityLevel?: AssetSensitivityLevel;
categoryId: string;
legalEntityId: string;
costCenterId: string;
purchaseRequestId?: string | null;
serialNo?: string | null;
location?: string | null;
status?: AssetStatus;
assigneeEmployeeId?: string | null;
ownerEmployeeId?: string | null;
keeperEmployeeId?: string | null;
archiveLocation?: string | null;
externalRef?: string | null;
sourceHash?: string | null;
verificationNo?: string | null;
confidentialityNote?: string | null;
metadata?: Record<string, unknown> | null;
lastVerifiedAt?: string | null;
expiresAt?: string | null;
activatedAt?: string | null;
retiredAt?: string | null;
};
export type PatchAssetPayload = Partial<
Omit<CreateAssetPayload, "purchaseRequestId" | "assigneeEmployeeId">
>;
export type AssetMovementResponse = {
assetId: string;
assetNo: string;
status: AssetStatus;
assigneeEmployeeId: string | null;
location: string | null;
assignmentId?: string | null;
transferId?: string | null;
};
export type AssetErpTrackStatus =
| "not_triggered"
| "pending"
| "processing"
| "succeeded"
| "failed"
| "dead_letter"
| "skipped";
export type AssetErpBinding = {
id: string;
provider: string;
entityType: string;
localId: string;
externalId: string | null;
externalCode: string | null;
lastSyncedAt: string | null;
};
export type AssetErpOutbox = {
id: string;
eventType: string;
status: string;
attempts: number;
lastError: string | null;
processedAt: string | null;
updatedAt: string | null;
};
export type AssetErpStage = {
eligible: boolean;
reason: string | null;
deliveryStatus: AssetErpTrackStatus | string;
actionHint: "none" | "backfill" | "retry" | "resync";
preview: {
changeType: string | null;
sourceEventName: string | null;
categoryCode: string | null;
legalEntityCode: string | null;
costCenterCode: string | null;
status: string | null;
};
outbox: AssetErpOutbox | null;
binding: AssetErpBinding | null;
};
export type AssetErpTrack = {
asset: {
id: string;
assetNo: string | null;
name: string | null;
status: string | null;
legalEntity: {
id: string;
code: string | null;
name: string | null;
} | null;
costCenter: {
id: string;
code: string | null;
name: string | null;
} | null;
purchaseRequest: {
id: string;
requestNo: string | null;
title: string | null;
} | null;
};
stage: AssetErpStage;
permissions: {
canRetry: boolean;
canSeeExternalRefs: boolean;
};
};
function toQueryString(query: Record<string, string | boolean | undefined>) {
const params = new URLSearchParams();
for (const [key, value] of Object.entries(query)) {
if (value == null || value === "") {
continue;
}
params.set(key, typeof value === "boolean" ? (value ? "1" : "0") : value);
}
const encoded = params.toString();
return encoded ? `?${encoded}` : "";
}
export async function fetchAssetCategories(params: { includeArchived?: boolean; enabled?: boolean } = {}) {
return apiRequestData<AssetCategoryListResponse>(
`/api/asset-categories${toQueryString(params as Record<string, string | boolean | undefined>)}`,
);
}
export async function createAssetCategory(payload: {
code: string;
name: string;
documentCategoryId?: string | null;
enabled?: boolean;
}) {
return apiRequestData<{ assetCategory: AssetCategoryItem }>("/api/asset-categories", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function patchAssetCategory(
assetCategoryId: string,
payload: Partial<{
code: string;
name: string;
documentCategoryId: string | null;
enabled: boolean;
}>,
) {
return apiRequestData<{ assetCategory: AssetCategoryItem }>(`/api/asset-categories/${assetCategoryId}`, {
method: "PATCH",
body: JSON.stringify(payload),
});
}
export async function fetchAssetAssignees(params: { q?: string } = {}) {
return apiRequestData<{ items: AssetAssigneeOption[] }>(
`/api/assets/assignees${toQueryString(params as Record<string, string | boolean | undefined>)}`,
);
}
export async function fetchAssets(params: AssetListQuery = {}) {
return apiRequestData<AssetListResponse>(
`/api/assets${toQueryString(params as Record<string, string | boolean | undefined>)}`,
);
}
export async function fetchAssetDetail(assetId: string) {
return apiRequestData<{ asset: AssetItem }>(`/api/assets/${assetId}`);
}
export async function createAsset(payload: CreateAssetPayload) {
return apiRequestData<{ asset: AssetItem }>("/api/assets", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function patchAsset(assetId: string, payload: PatchAssetPayload) {
return apiRequestData<{ asset: AssetItem }>(`/api/assets/${assetId}`, {
method: "PATCH",
body: JSON.stringify(payload),
});
}
export async function assignAsset(assetId: string, payload: { employeeId: string; note?: string | null }) {
return apiRequestData<AssetMovementResponse>(`/api/assets/${assetId}/assign`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function returnAsset(assetId: string, payload: { note?: string | null } = {}) {
return apiRequestData<AssetMovementResponse>(`/api/assets/${assetId}/return`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function transferAsset(
assetId: string,
payload: { toEmployeeId?: string | null; toLocation?: string | null; note?: string | null },
) {
return apiRequestData<AssetMovementResponse>(`/api/assets/${assetId}/transfer`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function fetchAssetErpTrack(assetId: string) {
return apiRequestData<AssetErpTrack>(`/api/integrations/erp/assets/${assetId}/track`);
}
export async function requeueAssetErpSync(assetId: string, runNow = true) {
const query = runNow ? '?runNow=1' : '?runNow=0';
return apiRequestData<{
outboxId: string;
status: string;
duplicated: boolean;
requeued: boolean;
eventType: string;
}>(`/api/integrations/erp/assets/${assetId}/requeue${query}`, {
method: 'POST',
body: JSON.stringify({}),
});
}