feat(cafe24): 옵션값+품목 통합 목록, 드래그 순서, 옵션값 불러오기

- 옵션 1개 상품은 한 행에 썸네일·옵션값 이름·품목코드(복사)·자체코드·
  추가금액·진열·판매를 두고 「저장」 한 번으로 옵션 PUT → 품목 PUT.
- 옵션 없는 상품: 행 추가/삭제 후 저장 → 옵션 생성 → 카페24가 부여한
  품목코드를 재시도 조회(products.wait_for_variants)로 받아 자체코드·
  추가금액·썸네일까지 이어서 반영.
- 순서 드래그는 품목 display_order 로 저장(옵션값 재배열 PUT 은 위치 짝맞춤
  때문에 품목코드↔이름이 뒤바뀔 수 있어 사용하지 않음).
- 「옵션값 불러오기」: 탭/공백 구분 텍스트(이름·판매가·추가금액·자체코드)
  붙여넣기 → 행 자동 채움. 기존 옵션은 이름으로 짝지어 코드/금액만.
- 옵션 2개 이상(조합) 상품은 기존 2열 화면 유지.
- 모달 JS 를 app/static/cafe24-options.js 로 분리. 유닛테스트 90 통과,
  통합 하네스 통과, 헤드리스 크롬 렌더 확인.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-18 23:25:52 +09:00
parent be0d44ded6
commit 8125a59366
8 changed files with 1002 additions and 360 deletions
+6 -6
View File
@@ -327,11 +327,11 @@ def options_create(
st.log_audit(actor=actor, action="create_options", product_no=product_no, result="SUCCESS",
detail=f"옵션 '{body['options'][0]['option_name']}' 생성: {', '.join(values)}")
logger.info("카페24 상품 %s 옵션 생성 (%s)", product_no, actor)
try:
variants = products.list_variants(api.client, product_no)
except Cafe24Error as exc: # 옵션은 만들어졌다 — 품목 목록만 비워서 돌려준다.
logger.warning("카페24 상품 %s 옵션 생성 후 품목 조회 실패: %s", product_no, exc)
variants = []
# 카페24가 자동 생성한 품목(코드 부여)을 바로 돌려준다 — 읽기 지연이 있어 짧게 재시도.
# 화면은 이 코드로 자체코드·추가금액을 이어서 PUT 한다.
variants = products.wait_for_variants(api.client, product_no, len(values))
if len(variants) < len(values):
logger.warning("카페24 상품 %s 옵션 생성 후 품목 %s/%s 건만 조회됨", product_no, len(variants), len(values))
return {"ok": True, "option": _options_view(created), "variants": [_variant_view(v) for v in variants]}
@@ -484,7 +484,7 @@ def variants_update(
for r in results:
code = str(r.get("variant_code") or "")
if code in by_code:
for key in ("custom_variant_code", "additional_amount", "display", "selling"):
for key in ("custom_variant_code", "additional_amount", "display", "selling", "display_order"):
if key in r and r[key] is not None:
by_code[code][key] = r[key]
st.save_write_snapshot(product_no, "variants", by_code)