362 行
9.1 KiB
TypeScript
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({}),
|
|
});
|
|
}
|