feat(cupang): 설정 화면 2열 개편 — itemcode 다중선택 등록 + 활성/삭제
- 수동 등록 카드 제거
- 왼쪽: itemcode_db 전체 목록(낱개+세트) 다중선택, 등록된 항목 진회색+흰글씨
/cupang/api/products/all + /cupang/products/bulk(JSON 일괄 upsert)
- 오른쪽: 등록 제품명 목록 — 제품명/코드/상태 + 활성·비활성 토글 + 완전삭제
/products/{id}/active (토글), /products/{id}/delete (hard delete)
- ItemcodeReader.list_all 추가
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,7 @@ import json
|
||||
from datetime import date, datetime
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, Depends, Form, HTTPException, Request
|
||||
from fastapi import APIRouter, Body, Depends, Form, HTTPException, Request
|
||||
from fastapi.responses import (
|
||||
HTMLResponse,
|
||||
JSONResponse,
|
||||
@@ -609,14 +609,54 @@ async def products_page(request: Request) -> HTMLResponse:
|
||||
"is_admin": is_admin(user),
|
||||
"nav_items": build_erp_nav(user, active="cupang"),
|
||||
"page_title": "쿠팡 밀크런 — 설정 (제품명)",
|
||||
"page_subtitle": "제품명 리스트 관리. itemcode_db 에서 검색해 등록하면 폼 드롭다운에 노출됩니다.",
|
||||
"page_subtitle": "왼쪽 itemcode_db 목록에서 선택해 등록하면 폼 드롭다운에 노출됩니다.",
|
||||
"products": store.list_products(include_inactive=True),
|
||||
"registered_codes": [p["product_code"] for p in store.list_products(include_inactive=True)],
|
||||
"search_enabled": bool(reader and reader.enabled),
|
||||
"search_reason": (reader.reason if reader else ""),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/products/all")
|
||||
async def product_all(
|
||||
request: Request, _: dict[str, Any] = Depends(_require_user)
|
||||
) -> JSONResponse:
|
||||
"""itemcode_db 전체 상품 목록(낱개+세트). 설정 화면 왼쪽 리스트 소스."""
|
||||
reader = _itemcode(request)
|
||||
return JSONResponse(
|
||||
{
|
||||
"enabled": bool(reader and reader.enabled),
|
||||
"reason": (reader.reason if reader else "itemcode 리더 미초기화"),
|
||||
"results": reader.list_all() if reader else [],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@router.post("/products/bulk")
|
||||
async def product_bulk(
|
||||
request: Request,
|
||||
items: list[dict[str, Any]] = Body(..., embed=True),
|
||||
user: dict[str, Any] = Depends(_require_user),
|
||||
) -> JSONResponse:
|
||||
"""선택한 상품들을 일괄 등록(upsert). body: {"items":[{"code","name"}, ...]}."""
|
||||
store = _store(request)
|
||||
if store is None:
|
||||
raise HTTPException(status_code=503, detail="cupang_db 미설정")
|
||||
added = 0
|
||||
for it in items:
|
||||
code = str(it.get("code") or "").strip()
|
||||
name = str(it.get("name") or "").strip()
|
||||
if not code or not name:
|
||||
continue
|
||||
try:
|
||||
store.upsert_product(product_code=code, product_name=name)
|
||||
added += 1
|
||||
except ValueError:
|
||||
continue
|
||||
return JSONResponse({"ok": True, "added": added})
|
||||
|
||||
|
||||
@router.post("/products")
|
||||
async def product_upsert(
|
||||
request: Request,
|
||||
@@ -637,17 +677,37 @@ async def product_upsert(
|
||||
return RedirectResponse(url="/cupang/products", status_code=303)
|
||||
|
||||
|
||||
@router.post("/products/{product_id:int}/delete")
|
||||
async def product_delete(
|
||||
@router.post("/products/{product_id:int}/active")
|
||||
async def product_set_active(
|
||||
request: Request,
|
||||
product_id: int,
|
||||
active: str = Form(...),
|
||||
user: dict[str, Any] = Depends(_require_user),
|
||||
) -> RedirectResponse:
|
||||
store = _store(request)
|
||||
if store is None:
|
||||
raise HTTPException(status_code=503, detail="cupang_db 미설정")
|
||||
try:
|
||||
store.deactivate_product(product_id=product_id)
|
||||
store.set_product_active(
|
||||
product_id=product_id, active=active in ("1", "true", "on", "True")
|
||||
)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="제품을 찾을 수 없습니다.")
|
||||
return RedirectResponse(url="/cupang/products", status_code=303)
|
||||
|
||||
|
||||
@router.post("/products/{product_id:int}/delete")
|
||||
async def product_delete(
|
||||
request: Request,
|
||||
product_id: int,
|
||||
user: dict[str, Any] = Depends(_require_user),
|
||||
) -> RedirectResponse:
|
||||
"""완전 삭제(hard delete)."""
|
||||
store = _store(request)
|
||||
if store is None:
|
||||
raise HTTPException(status_code=503, detail="cupang_db 미설정")
|
||||
try:
|
||||
store.delete_product(product_id=product_id)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="제품을 찾을 수 없습니다.")
|
||||
return RedirectResponse(url="/cupang/products", status_code=303)
|
||||
|
||||
Reference in New Issue
Block a user