Skip to content

관리 대상 주문

작성: 0chil

주문 단위 OrderManagement는 셀러 웹사이트 상품별 SellerWebsiteOrderManagement와 독립적이다. 운영 관리자는 주문 상세 상단 별 버튼으로 참고사항을 입력해 등록·수정하고, 처리 방법을 입력해 해제한다. 참고사항은 최대 1,000자, 처리 방법은 최대 255자이며 앞뒤 공백을 정리한다.

order_management는 주문 ID와 별도의 자동 생성 ID(id)를 PK로 사용한다. uk_order_management_order_id unique index로 주문당 한 건을 유지하며, 재등록해도 기존 관리 ID를 보존한다. 엔티티는 BaseEntityKt로 생성·수정 시각을 기록한다. 해제해도 참고사항을 보존하며 최초 처리 방법과 서버 완료 시각을 기록한다. 반복 해제는 기록을 덮어쓰지 않는다. 재등록 시 완료 시각과 처리 방법을 초기화하고, 과거 수동 변경은 기존 주문 변경 이력에 보존한다. 등록자 회원 ID(registeredMemberId)는 신규 등록·재등록 시 저장한다. 수동 등록은 요청한 관리자의 회원 ID, 시스템 자동 등록은 null이다. 활성 기록의 참고사항 수정이나 반복 자동 감지는 기존 등록자를 유지한다. 이전 등록자가 없는 기록도 null로 유지한다.

배송 추적 Job에서 새로운 웹사이트 상품 관리 기록을 저장했을 때만 주문도 등록한다. 자동 등록은 참고사항 없이 생성하며, 이미 있는 참고사항은 보존한다. 새 상품 문제가 발생하면 해제된 주문도 재등록한다. 기존 상품 링크의 반복 관측은 재등록하지 않는다. 상품별 해소나 배송 완료는 주문 관리 표시를 변경하지 않는다. 상품 관리 기록·주문 관리 등록·기존 배송 처리·추적 상태 변경은 같은 트랜잭션에서 반영한다. 등록은 주문 ID unique index 기반 upsert로 동시 등록을 처리한다. 같은 트랜잭션에서 upsert로 잠근 관리 행의 최신 활성 여부·참고사항을 읽고, Kotlin에서 변경 여부를 비교해 필요한 경우에만 갱신한다. 동일 값은 수정 시각과 변경 이력을 갱신하지 않는다. 주문 잠금을 추가하지 않는다.

모든 API는 ADMIN 권한이 필요하다.

  • PUT /admin/orders/{orderId}/management: {"referenceNote":"고객 확인 필요"}, 등록·재등록·참고사항 수정, 204.
  • POST /admin/orders/{orderId}/management/resolutions: {"resolutionMethod":"고객 안내 후 환불 완료"}, 최초 해제 및 반복 해제 204.
  • 없는 주문은 exceptionv2의 ORDER_ORDER_NOT_FOUND 오류를 반환한다.
  • 주문 상세 응답의 orderManagement는 관리 ID·활성 여부·참고사항·등록자 회원 ID·처리 방법·완료 시각·생성 및 수정 시각을 제공한다. 기록이 없으면 null이다.
  • 주문 목록 응답의 managementRequired는 현재 관리 대상 여부다.
  • GET /admin/orders/managements: pageSize와 선택 lastCursor를 받아 활성 관리 대상을 관리 ID 내림차순(최초 삽입의 역순)으로 조회한다. 응답은 기존 페이지 형태(elements, hasNext, lastCursor, totalPages, totalCount)이며 lastCursor는 숫자 관리 ID다. 목록 항목의 id와 상세 링크는 실제 주문 ID를 유지한다.
  • 관리 대상 목록 항목은 저장된 registeredMemberId를 제공한다. 등록자 회원을 별도로 조회하거나 조인하지 않는다. 일반 주문 목록의 이 필드는 null이다.
  • GET /admin/orders/managements/count: 실제 주문과 연결된 활성 관리 대상의 전체 건수를 숫자로 반환한다.
  • GET /admin/orders/{orderId}/management/navigation: 현재 주문의 관리 ID 기준 이전·다음 활성 주문 ID를 반환한다. 현재 관리 기록이 해제되어도 같은 관리 ID를 기준으로 탐색한다.
  • 관리 대상 조회는 OrderManagementRepository에서 order_management와 실제 orders를 inner join한다. 주문이 없는 기록은 목록·건수·탐색에서 모두 제외한다. 필요한 고객·배송·청구 정보는 Querydsl 생성자 projection으로 함께 조회한다.
  • 일반 주문 조회·상태별 건수·이전/다음 탐색은 기존 주문일시 API를 사용하며 시작일·종료일을 필수로 받는다. OrderRepository에는 관리 대상 조회 조건을 두지 않는다.

수동 등록·수정·해제는 기존 주문 변경 이력에 담당자와 함께 저장한다. 동일 값의 반복 저장과 반복 해제는 이력을 추가하지 않는다. 아직 관리 기록이 없는 주문에 대한 해제도 변경 없이 204를 반환한다.

주문 상세 상단에 이전 주문·다음 주문·별 관리 대상 등록·새로고침을 표시한다. 활성 주문의 참고사항은 ‘관리 대상’ 카드에 상품별 웹사이트 관리 목록과 함께 표시한다. 상품별 항목이 없는 수동 등록 주문에도 카드를 표시하며, 자동 등록으로 참고사항이 없으면 ‘셀러 웹사이트 관리 항목 자동 감지’로 표시한다. 카드 안에서 ‘주문 관리 참고사항’과 ‘셀러 웹사이트 주문 이상 감지’를 제목과 구분선으로 나누며, 미해소 상품 건수는 이상 감지 영역에 표시한다. 웹사이트 이상 감지 항목은 각각 얇은 테두리와 항목 사이 여백으로 구분한다. 처리 완료 기록에도 같은 구분을 적용한다. 해제된 주문의 참고사항·처리 방법·완료 시각은 같은 카드의 접힌 관리 기록에서 확인한다. 더 오래된 처리 이력은 주문 변경 이력에서 확인한다. 상품별 해소 기능은 주문 관리 해제와 독립적으로 유지한다.

주문 목록의 ‘전체’ 왼쪽에 ‘관리 대상’ 탭을 제공한다. 선택 시 주문일시 필터 카드를 숨기고 기간·주문 상태 제한 없이 활성 관리 대상 전체를 조회한다. 다른 상태 탭을 선택하면 기존 주문일시 필터를 다시 표시한다. 탭 선택은 목록·상세·이전/다음 이동에 유지하며, 상세에서 변경하면 목록 페이지 캐시를 초기화한다. 관리 대상 탭의 건수는 전체 기간 기준이고 나머지 상태별 건수는 기존 주문일시 기준이다. 관리 대상 목록의 ‘등록자’ 열에는 등록자 회원 ID를 표시한다. 등록자 ID가 null이면 ‘시스템’으로 표시한다. 일반 주문 목록에서는 이 열을 숨긴다.

등록자 컬럼 추가 SQL을 배포 전에 적용한다. 기존 order_management 테이블에 nullable registered_member_id 컬럼만 추가하며, 기존 기록은 null로 유지한다. 목록 조회에는 ix_order_management_active_id (active, id) 인덱스를 사용한다. 기존 웹사이트 관리 테이블은 변경하지 않는다.

기존 미해소 웹사이트 기록이 있다면 등록자 컬럼 추가 후 아래 SQL로 최초 등록한다. 이미 존재하는 주문 관리 기록은 덮어쓰지 않는다.

INSERT IGNORE INTO order_management (order_id, active, reference_note, registered_member_id, created_at, updated_at)
SELECT DISTINCT order_id, TRUE, NULL, NULL, CURRENT_TIMESTAMP(6), CURRENT_TIMESTAMP(6)
FROM seller_website_order_management
WHERE resolved = FALSE;