ui(cupang): 박스입수량 라벨/겹침, 입고센터 컴팩트 재디자인, 출고 완전삭제
- 박스 입수량 폼: 제품명(스냅샷)→제품명, 헤더그리드로 교체해 입력란 겹침 해소
- 입고센터: 추가 폼 슬림화 + 센터 목록 2열 그리드(한 줄/센터)로 압축
- 출고 상세: 완전삭제 버튼 추가(/{id}/hard-delete, 라인 CASCADE). 취소 처리는 outline 로
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -425,6 +425,23 @@ async def delete(
|
||||
return RedirectResponse(url=f"/cupang/{shipment_id}", status_code=303)
|
||||
|
||||
|
||||
@router.post("/{shipment_id:int}/hard-delete")
|
||||
async def hard_delete(
|
||||
request: Request,
|
||||
shipment_id: int,
|
||||
user: dict[str, Any] = Depends(_require_user),
|
||||
) -> RedirectResponse:
|
||||
"""완전 삭제(헤더+라인 CASCADE). 달력으로 복귀."""
|
||||
store = _store(request)
|
||||
if store is None:
|
||||
raise HTTPException(status_code=503, detail="cupang_db 미설정")
|
||||
try:
|
||||
store.hard_delete(shipment_id=shipment_id)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="출고 묶음을 찾을 수 없습니다.")
|
||||
return RedirectResponse(url="/cupang/", status_code=303)
|
||||
|
||||
|
||||
# ════════════════════════════════════════════════════════════
|
||||
# 입고센터 관리
|
||||
# ════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -15,18 +15,22 @@
|
||||
<h2>박스 입수량 추가 / 수정</h2>
|
||||
<span class="erp-muted">같은 제품코드는 덮어씁니다. 쿠팡박스 1박스당 들어가는 수량.</span>
|
||||
</div>
|
||||
<form method="post" action="/cupang/box-rules" class="cpg-rule-grid">
|
||||
<label class="erp-field"><span>제품코드 *</span>
|
||||
<input class="erp-input" type="text" name="product_code" required placeholder="예: MS-1001" /></label>
|
||||
<label class="erp-field"><span>제품명(스냅샷)</span>
|
||||
<input class="erp-input" type="text" name="product_name_snapshot" placeholder="예: 미라네 1호세트" /></label>
|
||||
<label class="erp-field"><span>박스명</span>
|
||||
<input class="erp-input" type="text" name="box_name" value="쿠팡박스" /></label>
|
||||
<label class="erp-field"><span>박스당 입수량 *</span>
|
||||
<input class="erp-input" type="number" name="units_per_box" min="1" required /></label>
|
||||
<label class="erp-field cpg-full"><span>메모</span>
|
||||
<input class="erp-input" type="text" name="memo" /></label>
|
||||
<div><button type="submit" class="erp-btn erp-btn-primary">저장</button></div>
|
||||
<form method="post" action="/cupang/box-rules">
|
||||
<div class="cpg-header-grid">
|
||||
<label class="erp-field"><span>제품코드 *</span>
|
||||
<input class="erp-input" type="text" name="product_code" required placeholder="예: MS-1001" /></label>
|
||||
<label class="erp-field"><span>제품명</span>
|
||||
<input class="erp-input" type="text" name="product_name_snapshot" placeholder="예: 미라네 1호세트" /></label>
|
||||
<label class="erp-field"><span>박스명</span>
|
||||
<input class="erp-input" type="text" name="box_name" value="쿠팡박스" /></label>
|
||||
<label class="erp-field"><span>박스당 입수량 *</span>
|
||||
<input class="erp-input" type="number" name="units_per_box" min="1" required /></label>
|
||||
<label class="erp-field cpg-full"><span>메모</span>
|
||||
<input class="erp-input" type="text" name="memo" /></label>
|
||||
</div>
|
||||
<div class="erp-page-actions" style="margin-top:12px;">
|
||||
<button type="submit" class="erp-btn erp-btn-primary">저장</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,65 +9,56 @@
|
||||
<a class="erp-btn erp-btn-outline" href="/cupang/">← 달력</a>
|
||||
</div>
|
||||
|
||||
<!-- 추가 -->
|
||||
<div class="erp-card cpg-form-card">
|
||||
<div class="cpg-card-head"><h2>입고센터 추가</h2></div>
|
||||
<!-- 추가 (슬림) -->
|
||||
<div class="erp-card cpg-form-card cpg-center-add">
|
||||
<h2 class="cpg-center-add-title">입고센터 추가</h2>
|
||||
<form method="post" action="/cupang/centers" class="cpg-inline-form">
|
||||
<input class="erp-input" type="text" name="name" placeholder="센터명 (예: 대구3)" required />
|
||||
<input class="erp-input" type="number" name="sort_order" value="0" style="max-width:90px" title="정렬순서" />
|
||||
<input class="erp-input" type="text" name="name" placeholder="센터명 (예: 대구3)" required style="min-width:180px" />
|
||||
<input class="erp-input" type="number" name="sort_order" value="0" style="width:70px" title="정렬순서" />
|
||||
<button type="submit" class="erp-btn erp-btn-primary">추가</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 목록 -->
|
||||
<!-- 목록 (2열 그리드, 한 줄/센터) -->
|
||||
<div class="erp-card cpg-form-card">
|
||||
<div class="cpg-card-head"><h2>센터 목록 ({{ centers|length }})</h2></div>
|
||||
<div class="erp-table-wrap">
|
||||
<table class="erp-table">
|
||||
<thead>
|
||||
<tr><th>센터명</th><th>정렬</th><th>상태</th><th>사용중</th><th>동작</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in centers %}
|
||||
<tr {% if not c.active %}style="opacity:.55"{% endif %}>
|
||||
<td>
|
||||
<form method="post" action="/cupang/centers/{{ c.id }}/edit" class="cpg-inline-form">
|
||||
<input class="erp-input" type="text" name="name" value="{{ c.name }}" style="max-width:160px" />
|
||||
<input class="erp-input" type="number" name="sort_order" value="{{ c.sort_order }}" style="max-width:80px" />
|
||||
<button type="submit" class="erp-btn erp-btn-outline">수정</button>
|
||||
</form>
|
||||
</td>
|
||||
<td>{{ c.sort_order }}</td>
|
||||
<td>
|
||||
{% if c.active %}<span class="erp-badge erp-badge-success">활성</span>
|
||||
{% else %}<span class="erp-badge erp-badge-neutral">비활성</span>{% endif %}
|
||||
</td>
|
||||
<td>{% if c.in_use %}<span class="erp-badge erp-badge-inverse">사용중</span>{% else %}—{% endif %}</td>
|
||||
<td>
|
||||
<div class="cpg-row-actions">
|
||||
{% if c.active %}
|
||||
<form method="post" action="/cupang/centers/{{ c.id }}/edit" class="cpg-inline-form">
|
||||
<input type="hidden" name="active" value="0" />
|
||||
<button type="submit" class="erp-btn erp-btn-outline">비활성화</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="post" action="/cupang/centers/{{ c.id }}/edit" class="cpg-inline-form">
|
||||
<input type="hidden" name="active" value="1" />
|
||||
<button type="submit" class="erp-btn erp-btn-outline">활성화</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<form method="post" action="/cupang/centers/{{ c.id }}/delete" class="cpg-inline-form"
|
||||
onsubmit="return confirm('{% if c.in_use %}사용 중인 센터는 비활성화됩니다.{% else %}삭제합니다.{% endif %} 계속할까요?');">
|
||||
<button type="submit" class="erp-btn erp-btn-danger">삭제</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="cpg-card-head">
|
||||
<h2>센터 목록 ({{ centers|length }})</h2>
|
||||
<span class="erp-muted">사용 중 센터는 삭제 시 비활성화됩니다.</span>
|
||||
</div>
|
||||
|
||||
<div class="cpg-center-grid">
|
||||
{% for c in centers %}
|
||||
<div class="cpg-center-row {% if not c.active %}is-inactive{% endif %}">
|
||||
<form method="post" action="/cupang/centers/{{ c.id }}/edit" class="cpg-center-edit">
|
||||
<input class="erp-input cpg-center-name" type="text" name="name" value="{{ c.name }}" />
|
||||
<input class="erp-input cpg-center-sort" type="number" name="sort_order" value="{{ c.sort_order }}" title="정렬" />
|
||||
<button type="submit" class="erp-btn erp-btn-outline cpg-btn-sm" title="이름/정렬 저장">저장</button>
|
||||
</form>
|
||||
<span class="cpg-center-state">
|
||||
{% if c.in_use %}<span class="erp-badge erp-badge-inverse cpg-mini">사용중</span>{% endif %}
|
||||
{% if c.active %}<span class="erp-badge erp-badge-success cpg-mini">활성</span>
|
||||
{% else %}<span class="erp-badge erp-badge-neutral cpg-mini">비활성</span>{% endif %}
|
||||
</span>
|
||||
<span class="cpg-center-act">
|
||||
{% if c.active %}
|
||||
<form method="post" action="/cupang/centers/{{ c.id }}/edit" class="cpg-inline-form">
|
||||
<input type="hidden" name="active" value="0" />
|
||||
<button type="submit" class="erp-btn erp-btn-outline cpg-btn-sm">비활성</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="post" action="/cupang/centers/{{ c.id }}/edit" class="cpg-inline-form">
|
||||
<input type="hidden" name="active" value="1" />
|
||||
<button type="submit" class="erp-btn erp-btn-outline cpg-btn-sm">활성</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<form method="post" action="/cupang/centers/{{ c.id }}/delete" class="cpg-inline-form"
|
||||
onsubmit="return confirm('{% if c.in_use %}사용 중 → 비활성화됩니다.{% else %}삭제합니다.{% endif %} 계속?');">
|
||||
<button type="submit" class="erp-btn erp-btn-danger cpg-btn-sm">삭제</button>
|
||||
</form>
|
||||
</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="erp-muted">※ 출고 데이터에서 사용 중인 센터는 삭제 시 hard delete 되지 않고 비활성화됩니다.</p>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -20,8 +20,13 @@
|
||||
</form>
|
||||
|
||||
<form method="post" action="/cupang/{{ shipment.id }}/delete" class="cpg-inline-form"
|
||||
onsubmit="return confirm('이 출고 묶음을 취소 처리합니다. 계속할까요?');">
|
||||
<button type="submit" class="erp-btn erp-btn-danger">취소 처리</button>
|
||||
onsubmit="return confirm('이 출고 묶음을 취소 처리합니다(상태=취소). 계속할까요?');">
|
||||
<button type="submit" class="erp-btn erp-btn-outline">취소 처리</button>
|
||||
</form>
|
||||
|
||||
<form method="post" action="/cupang/{{ shipment.id }}/hard-delete" class="cpg-inline-form"
|
||||
onsubmit="return confirm('이 출고를 완전 삭제합니다(복구 불가, 품목 포함). 계속할까요?');">
|
||||
<button type="submit" class="erp-btn erp-btn-danger">삭제</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user