diff --git a/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx b/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx
index c44c889b..7500cc2d 100644
--- a/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx
+++ b/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx
@@ -35,6 +35,7 @@ import {
ChevronDown,
ChevronRight,
ChevronsUpDown,
+ Trash2,
} from "lucide-react";
import { toast } from "sonner";
import { IntegratedDetailTemplate } from "@/components/templates/IntegratedDetailTemplate";
@@ -64,6 +65,7 @@ import {
updateOrderStatus,
revertProductionOrder,
revertOrderConfirmation,
+ deleteOrder,
type Order,
type OrderStatus,
} from "@/components/orders";
@@ -115,6 +117,8 @@ export default function OrderDetailPage() {
const [isReverting, setIsReverting] = useState(false);
const [isRevertConfirmDialogOpen, setIsRevertConfirmDialogOpen] = useState(false);
const [isRevertingConfirm, setIsRevertingConfirm] = useState(false);
+ const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
+ const [isDeleting, setIsDeleting] = useState(false);
// 취소 폼 상태
const [cancelReason, setCancelReason] = useState("");
@@ -296,6 +300,31 @@ export default function OrderDetailPage() {
}
};
+ // 수주 삭제
+ const handleDelete = () => {
+ setIsDeleteDialogOpen(true);
+ };
+
+ const handleDeleteSubmit = async () => {
+ if (order) {
+ setIsDeleting(true);
+ try {
+ const result = await deleteOrder(order.id);
+ if (result.success) {
+ toast.success("수주가 삭제되었습니다.");
+ router.push("/sales/order-management-sales");
+ } else {
+ toast.error(result.error || "수주 삭제에 실패했습니다.");
+ }
+ } catch (error) {
+ console.error("Error deleting order:", error);
+ toast.error("수주 삭제 중 오류가 발생했습니다.");
+ } finally {
+ setIsDeleting(false);
+ }
+ }
+ };
+
// 문서 모달 열기
const openDocumentModal = (type: OrderDocumentType) => {
setDocumentType(type);
@@ -727,6 +756,8 @@ export default function OrderDetailPage() {
order.status !== "shipped" &&
order.status !== "cancelled" &&
order.status !== "production_ordered";
+ // 삭제 버튼은 수주등록 또는 취소 상태에서 표시
+ const showDeleteButton = order.status === "order_registered" || order.status === "cancelled";
return (
@@ -772,9 +803,15 @@ export default function OrderDetailPage() {
취소
)}
+ {showDeleteButton && (
+
+ )}
);
- }, [order, handleEdit, handleConfirmOrder, handleProductionOrder, handleViewProductionOrder, handleRevertProduction, handleRevertConfirmation, handleCancel]);
+ }, [order, handleEdit, handleConfirmOrder, handleProductionOrder, handleViewProductionOrder, handleRevertProduction, handleRevertConfirmation, handleCancel, handleDelete]);
return (
<>
@@ -1116,6 +1153,80 @@ export default function OrderDetailPage() {
+
+ {/* 수주 삭제 다이얼로그 */}
+
>
)}
>
diff --git a/src/components/outbound/ShipmentManagement/ShipmentList.tsx b/src/components/outbound/ShipmentManagement/ShipmentList.tsx
index e8f58907..ae2b1b74 100644
--- a/src/components/outbound/ShipmentManagement/ShipmentList.tsx
+++ b/src/components/outbound/ShipmentManagement/ShipmentList.tsx
@@ -41,7 +41,6 @@ import { getShipments, getShipmentStats, getShipmentStatsByStatus } from './acti
import {
SHIPMENT_STATUS_LABELS,
SHIPMENT_STATUS_STYLES,
- DELIVERY_METHOD_LABELS,
} from './types';
import type { ShipmentItem, ShipmentStatus, ShipmentStats, ShipmentStatusStats } from './types';
import { isNextRedirectError } from '@/lib/utils/redirect-error';
@@ -287,7 +286,7 @@ export function ShipmentList() {
)}
- {DELIVERY_METHOD_LABELS[item.deliveryMethod]}
+ {item.deliveryMethodLabel}
{item.customerName}
{item.siteName}
{item.manager || '-'}
@@ -331,7 +330,7 @@ export function ShipmentList() {
-
+
}
diff --git a/src/components/outbound/ShipmentManagement/actions.ts b/src/components/outbound/ShipmentManagement/actions.ts
index f9304d07..8e4a6ed1 100644
--- a/src/components/outbound/ShipmentManagement/actions.ts
+++ b/src/components/outbound/ShipmentManagement/actions.ts
@@ -144,8 +144,10 @@ function transformApiToListItem(data: ShipmentApiData): ShipmentItem {
status: data.status,
priority: data.priority,
deliveryMethod: data.delivery_method,
- customerName: data.customer_name || '',
- siteName: data.site_name || '',
+ deliveryMethodLabel: data.delivery_method_label || data.delivery_method,
+ // 발주처/배송 정보: order_info 우선 참조 (Order가 Single Source of Truth)
+ customerName: data.order_info?.customer_name || data.customer_name || '',
+ siteName: data.order_info?.site_name || data.site_name || '',
manager: data.loading_manager,
canShip: data.can_ship,
depositConfirmed: data.deposit_confirmed,
diff --git a/src/components/outbound/ShipmentManagement/types.ts b/src/components/outbound/ShipmentManagement/types.ts
index 7bb54935..bbe7d1a7 100644
--- a/src/components/outbound/ShipmentManagement/types.ts
+++ b/src/components/outbound/ShipmentManagement/types.ts
@@ -58,6 +58,7 @@ export interface ShipmentItem {
status: ShipmentStatus; // 상태
priority: ShipmentPriority; // 우선순위
deliveryMethod: DeliveryMethod; // 배송방식
+ deliveryMethodLabel: string; // 배송방식 라벨 (API에서 조회)
customerName: string; // 발주처
siteName: string; // 현장명
manager?: string; // 담당
diff --git a/src/lib/api/common-codes.ts b/src/lib/api/common-codes.ts
index bc3ab97e..7fc60810 100644
--- a/src/lib/api/common-codes.ts
+++ b/src/lib/api/common-codes.ts
@@ -118,4 +118,30 @@ export async function getItemTypeCodes() {
*/
export async function getItemTypeOptions() {
return getCommonCodeOptions('item_type');
+}
+
+/**
+ * 배송방식 코드 조회
+ */
+export async function getDeliveryMethodCodes() {
+ return getCommonCodes('delivery_method');
+}
+
+/**
+ * 배송방식 옵션 조회
+ */
+export async function getDeliveryMethodOptions() {
+ return getCommonCodeOptions('delivery_method');
+}
+
+/**
+ * 코드값으로 라벨 조회 (code → name 매핑)
+ */
+export async function getCodeLabel(group: string, code: string): Promise {
+ const result = await getCommonCodes(group);
+ if (result.success && result.data) {
+ const found = result.data.find((item) => item.code === code);
+ return found?.name || code;
+ }
+ return code;
}
\ No newline at end of file