ERP-node/frontend/lib/api/approval.ts

498 lines
14 KiB
TypeScript

/**
* 결재 시스템 API 클라이언트
* 엔드포인트: /api/approval/*
*/
import apiClient from "@/lib/api/client";
// ============================================================
// 공통 타입 정의
// ============================================================
export interface ApiResponse<T = any> {
success: boolean;
data?: T;
message?: string;
error?: string;
total?: number;
page?: number;
limit?: number;
}
export interface ApprovalDefinition {
definition_id: number;
definition_name: string;
definition_name_eng?: string;
description?: string;
default_template_id?: number;
max_steps: number;
allow_self_approval: boolean;
allow_cancel: boolean;
is_active: string;
company_code: string;
created_by?: string;
created_at: string;
updated_by?: string;
updated_at: string;
}
export interface ApprovalLineTemplate {
template_id: number;
template_name: string;
description?: string;
definition_id?: number;
definition_name?: string;
is_active: string;
company_code: string;
created_by?: string;
created_at: string;
updated_by?: string;
updated_at: string;
steps?: ApprovalLineTemplateStep[];
}
export interface ApprovalLineTemplateStep {
step_id: number;
template_id: number;
step_order: number;
step_type?: "approval" | "consensus" | "notification";
approver_type: "user" | "position" | "dept";
approver_user_id?: string;
approver_position?: string;
approver_dept_code?: string;
approver_label?: string;
company_code: string;
}
export interface ApprovalProxySetting {
id: number;
original_user_id: string;
original_user_name?: string;
original_dept_name?: string;
proxy_user_id: string;
proxy_user_name?: string;
proxy_dept_name?: string;
start_date: string;
end_date: string;
reason?: string;
is_active: string;
company_code: string;
created_at: string;
updated_at: string;
}
export interface ApprovalRequest {
request_id: number;
title: string;
description?: string;
definition_id?: number;
definition_name?: string;
target_table: string;
target_record_id: string;
target_record_data?: Record<string, any>;
status: "requested" | "in_progress" | "approved" | "rejected" | "cancelled";
current_step: number;
total_steps: number;
requester_id: string;
requester_name?: string;
requester_dept?: string;
completed_at?: string;
final_approver_id?: string;
final_comment?: string;
screen_id?: number;
button_component_id?: string;
company_code: string;
created_at: string;
updated_at: string;
lines?: ApprovalLine[];
}
export interface ApprovalLine {
line_id: number;
request_id: number;
step_order: number;
approver_id: string;
approver_name?: string;
approver_position?: string;
approver_dept?: string;
approver_label?: string;
status: "waiting" | "pending" | "approved" | "rejected" | "skipped";
comment?: string;
processed_at?: string;
company_code: string;
created_at: string;
// 요청 정보 (my-pending 조회 시 포함)
title?: string;
target_table?: string;
target_record_id?: string;
requester_name?: string;
requester_dept?: string;
request_created_at?: string;
}
export interface CreateApprovalRequestInput {
title: string;
description?: string;
definition_id?: number;
target_table: string;
target_record_id?: string;
target_record_data?: Record<string, any>;
screen_id?: number;
button_component_id?: string;
approval_mode?: "sequential" | "parallel";
approval_type?: "self" | "escalation" | "consensus" | "post";
approvers: {
approver_id: string;
approver_name?: string;
approver_position?: string;
approver_dept?: string;
approver_label?: string;
step_type?: "approval" | "consensus" | "notification";
step_order?: number;
}[];
}
// ============================================================
// 결재 유형 (Definitions) API
// ============================================================
export async function getApprovalDefinitions(params?: {
is_active?: string;
search?: string;
}): Promise<ApiResponse<ApprovalDefinition[]>> {
try {
const response = await apiClient.get("/approval/definitions", { params });
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function getApprovalDefinition(id: number): Promise<ApiResponse<ApprovalDefinition>> {
try {
const response = await apiClient.get(`/approval/definitions/${id}`);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function createApprovalDefinition(data: {
definition_name: string;
definition_name_eng?: string;
description?: string;
default_template_id?: number;
max_steps?: number;
allow_self_approval?: boolean;
allow_cancel?: boolean;
is_active?: string;
}): Promise<ApiResponse<ApprovalDefinition>> {
try {
const response = await apiClient.post("/approval/definitions", data);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function updateApprovalDefinition(
id: number,
data: Partial<ApprovalDefinition>
): Promise<ApiResponse<ApprovalDefinition>> {
try {
const response = await apiClient.put(`/approval/definitions/${id}`, data);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function deleteApprovalDefinition(id: number): Promise<ApiResponse<void>> {
try {
const response = await apiClient.delete(`/approval/definitions/${id}`);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
// ============================================================
// 결재선 템플릿 (Templates) API
// ============================================================
export async function getApprovalTemplates(params?: {
definition_id?: number;
is_active?: string;
}): Promise<ApiResponse<ApprovalLineTemplate[]>> {
try {
const response = await apiClient.get("/approval/templates", { params });
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function getApprovalTemplate(id: number): Promise<ApiResponse<ApprovalLineTemplate>> {
try {
const response = await apiClient.get(`/approval/templates/${id}`);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function createApprovalTemplate(data: {
template_name: string;
description?: string;
definition_id?: number;
is_active?: string;
steps?: Omit<ApprovalLineTemplateStep, "step_id" | "template_id" | "company_code">[];
}): Promise<ApiResponse<ApprovalLineTemplate>> {
try {
const response = await apiClient.post("/approval/templates", data);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function updateApprovalTemplate(
id: number,
data: {
template_name?: string;
description?: string;
definition_id?: number;
is_active?: string;
steps?: Omit<ApprovalLineTemplateStep, "step_id" | "template_id" | "company_code">[];
}
): Promise<ApiResponse<ApprovalLineTemplate>> {
try {
const response = await apiClient.put(`/approval/templates/${id}`, data);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function deleteApprovalTemplate(id: number): Promise<ApiResponse<void>> {
try {
const response = await apiClient.delete(`/approval/templates/${id}`);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
// ============================================================
// 결재 요청 (Requests) API
// ============================================================
export async function getApprovalRequests(params?: {
status?: string;
target_table?: string;
target_record_id?: string;
requester_id?: string;
my_approvals?: boolean;
page?: number;
limit?: number;
}): Promise<ApiResponse<ApprovalRequest[]>> {
try {
const response = await apiClient.get("/approval/requests", { params });
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function getApprovalRequest(id: number): Promise<ApiResponse<ApprovalRequest>> {
try {
const response = await apiClient.get(`/approval/requests/${id}`);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function createApprovalRequest(
data: CreateApprovalRequestInput
): Promise<ApiResponse<ApprovalRequest>> {
try {
const response = await apiClient.post("/approval/requests", data);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function cancelApprovalRequest(id: number): Promise<ApiResponse<void>> {
try {
const response = await apiClient.post(`/approval/requests/${id}/cancel`);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
// ============================================================
// 결재 라인 처리 (Lines) API
// ============================================================
export async function getMyPendingApprovals(): Promise<ApiResponse<ApprovalLine[]>> {
try {
const response = await apiClient.get("/approval/my-pending");
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function processApprovalLine(
lineId: number,
data: { action: "approved" | "rejected"; comment?: string }
): Promise<ApiResponse<void>> {
try {
const response = await apiClient.post(`/approval/lines/${lineId}/process`, data);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
// ============================================================
// 대결 위임 설정 (Proxy Settings) API
// ============================================================
export async function getProxySettings(): Promise<ApiResponse<ApprovalProxySetting[]>> {
try {
const response = await apiClient.get("/approval/proxy-settings");
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function createProxySetting(data: {
original_user_id: string;
proxy_user_id: string;
start_date: string;
end_date: string;
reason?: string;
}): Promise<ApiResponse<ApprovalProxySetting>> {
try {
const response = await apiClient.post("/approval/proxy-settings", data);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function updateProxySetting(
id: number,
data: {
proxy_user_id?: string;
start_date?: string;
end_date?: string;
reason?: string;
is_active?: string;
}
): Promise<ApiResponse<ApprovalProxySetting>> {
try {
const response = await apiClient.put(`/approval/proxy-settings/${id}`, data);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function deleteProxySetting(id: number): Promise<ApiResponse<void>> {
try {
const response = await apiClient.delete(`/approval/proxy-settings/${id}`);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function checkActiveProxy(
userId: string
): Promise<ApiResponse<{ proxy_user_id: string; proxy_user_name?: string } | null>> {
try {
const response = await apiClient.get(
`/approval/proxy-settings/check/${encodeURIComponent(userId)}`
);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
// ============================================================
// 후결 승인 API
// ============================================================
export async function postApproveRequest(requestId: number): Promise<ApiResponse<void>> {
try {
const response = await apiClient.post(`/approval/requests/${requestId}/post-approve`);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
// ============================================================
// 결재선 템플릿 단계 (Template Steps) API
// ============================================================
export async function getTemplateSteps(
templateId: number
): Promise<ApiResponse<ApprovalLineTemplateStep[]>> {
try {
const response = await apiClient.get(`/approval/templates/${templateId}/steps`);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function createTemplateStep(
templateId: number,
data: Omit<ApprovalLineTemplateStep, "step_id" | "template_id" | "company_code">
): Promise<ApiResponse<ApprovalLineTemplateStep>> {
try {
const response = await apiClient.post(`/approval/templates/${templateId}/steps`, data);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function updateTemplateStep(
templateId: number,
stepId: number,
data: Partial<Omit<ApprovalLineTemplateStep, "step_id" | "template_id" | "company_code">>
): Promise<ApiResponse<ApprovalLineTemplateStep>> {
try {
const response = await apiClient.put(
`/approval/templates/${templateId}/steps/${stepId}`,
data
);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}
export async function deleteTemplateStep(
templateId: number,
stepId: number
): Promise<ApiResponse<void>> {
try {
const response = await apiClient.delete(
`/approval/templates/${templateId}/steps/${stepId}`
);
return response.data;
} catch (error: any) {
return { success: false, error: error.message };
}
}