feat(WEB): 수주 Bulk Delete + Revert Force 프론트엔드 연동
- deleteOrders: for 루프 단건 삭제 → DELETE /api/v1/orders/bulk 단일 호출로 전환 - deleteOrders: force 옵션 추가 (개발환경 물리 삭제용) - revertProductionOrder: force/reason 파라미터 추가 - 수주 상세: 되돌리기 다이얼로그에 사유 Textarea 추가 - 수주 상세: 개발환경 전용 "완전삭제 (DEV)" 버튼 추가 - 수주 목록: 개발환경 전용 selectionActions "완전삭제 (DEV)" 버튼 추가
This commit is contained in:
@@ -959,37 +959,40 @@ export async function getOrderStats(): Promise<{
|
||||
}
|
||||
|
||||
/**
|
||||
* 수주 일괄 삭제
|
||||
* 수주 일괄 삭제 (Bulk API)
|
||||
*/
|
||||
export async function deleteOrders(ids: string[]): Promise<{
|
||||
export async function deleteOrders(
|
||||
ids: string[],
|
||||
options?: { force?: boolean }
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
deletedCount?: number;
|
||||
skippedCount?: number;
|
||||
skippedIds?: number[];
|
||||
error?: string;
|
||||
__authError?: boolean;
|
||||
}> {
|
||||
try {
|
||||
// 순차적으로 삭제 (API에 bulk delete가 없으므로)
|
||||
let deletedCount = 0;
|
||||
const errors: string[] = [];
|
||||
|
||||
for (const id of ids) {
|
||||
const result = await deleteOrder(id);
|
||||
if (result.success) {
|
||||
deletedCount++;
|
||||
} else {
|
||||
errors.push(result.error || `ID ${id} 삭제 실패`);
|
||||
}
|
||||
}
|
||||
|
||||
if (deletedCount === 0 && errors.length > 0) {
|
||||
return { success: false, error: errors[0] };
|
||||
}
|
||||
|
||||
return { success: true, deletedCount };
|
||||
} catch (error) {
|
||||
console.error('[deleteOrders] Error:', error);
|
||||
return { success: false, error: '서버 오류가 발생했습니다.' };
|
||||
interface BulkDeleteResponse {
|
||||
deleted_count: number;
|
||||
skipped_count: number;
|
||||
skipped_ids: number[];
|
||||
}
|
||||
const body: Record<string, unknown> = { ids: ids.map(Number) };
|
||||
if (options?.force) body.force = true;
|
||||
const result = await executeServerAction<BulkDeleteResponse>({
|
||||
url: buildApiUrl('/api/v1/orders/bulk'),
|
||||
method: 'DELETE',
|
||||
body,
|
||||
errorMessage: '수주 일괄 삭제에 실패했습니다.',
|
||||
});
|
||||
if (result.__authError) return { success: false, __authError: true };
|
||||
if (!result.success || !result.data) return { success: false, error: result.error };
|
||||
return {
|
||||
success: true,
|
||||
deletedCount: result.data.deleted_count,
|
||||
skippedCount: result.data.skipped_count,
|
||||
skippedIds: result.data.skipped_ids,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1071,7 +1074,10 @@ export async function createProductionOrder(
|
||||
/**
|
||||
* 생산지시 되돌리기 (작업지시 및 관련 데이터 삭제)
|
||||
*/
|
||||
export async function revertProductionOrder(orderId: string): Promise<{
|
||||
export async function revertProductionOrder(
|
||||
orderId: string,
|
||||
options?: { force?: boolean; reason?: string }
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
data?: {
|
||||
order: Order;
|
||||
@@ -1084,11 +1090,16 @@ export async function revertProductionOrder(orderId: string): Promise<{
|
||||
interface RevertResponse {
|
||||
order: ApiOrder;
|
||||
deleted_counts: { work_results: number; work_order_items: number; work_orders: number };
|
||||
cancelled_counts?: { work_orders: number; work_order_items: number };
|
||||
previous_status: string;
|
||||
}
|
||||
const body: Record<string, unknown> = {};
|
||||
if (options?.force !== undefined) body.force = options.force;
|
||||
if (options?.reason) body.reason = options.reason;
|
||||
const result = await executeServerAction<RevertResponse>({
|
||||
url: buildApiUrl(`/api/v1/orders/${orderId}/revert-production`),
|
||||
method: 'POST',
|
||||
body: Object.keys(body).length > 0 ? body : undefined,
|
||||
errorMessage: '생산지시 되돌리기에 실패했습니다.',
|
||||
});
|
||||
if (result.__authError) return { success: false, __authError: true };
|
||||
|
||||
Reference in New Issue
Block a user