9e707be5ac
- app/modules/cupang: router/db/store/itemcode + 템플릿 5종 - cupang_db 전용(JSON 폴백 없음). CUPANG_DB_URL 미설정 시 안내 페이지 - 월간 달력 + 출고 묶음(헤더+라인), 박스 입수량 자동계산(서버 재계산) - 입고센터 관리(사용중 soft delete), 박스규칙 upsert, 엑셀 내보내기 - 상품 검색은 itemcode_db 읽기 전용(미설정 시 수동 입력) - MODULE_KEYS/메뉴/아이콘/라벨 동기화, scripts/sql/cupang_db_init.sql(멱등) - app/data/ gitignore 추가(PII) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
123 lines
5.3 KiB
HTML
123 lines
5.3 KiB
HTML
{% extends "erp_base.html" %}
|
|
|
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css" />{% endblock %}
|
|
|
|
{% block content %}
|
|
<section class="cpg">
|
|
|
|
{% set action = '/cupang/new' if mode == 'new' else '/cupang/' ~ shipment.id ~ '/edit' %}
|
|
<form id="cpg-form" method="post" action="{{ action }}">
|
|
<input type="hidden" name="lines_json" id="cpg-lines-json" value="[]" />
|
|
|
|
<!-- ── 공통 헤더 ── -->
|
|
<div class="erp-card cpg-form-card">
|
|
<div class="cpg-card-head"><h2>공통 헤더</h2></div>
|
|
<div class="cpg-header-grid">
|
|
<label class="erp-field"><span>작성일 *</span>
|
|
<input class="erp-input" type="date" name="document_date" required
|
|
value="{{ shipment.document_date if shipment else default_date }}" /></label>
|
|
<label class="erp-field"><span>출고일 *</span>
|
|
<input class="erp-input" type="date" name="ship_date" required
|
|
value="{{ shipment.ship_date if shipment else default_date }}" /></label>
|
|
<label class="erp-field"><span>센터입고일 *</span>
|
|
<input class="erp-input" type="date" name="center_arrival_date" required
|
|
value="{{ shipment.center_arrival_date if shipment else default_date }}" /></label>
|
|
|
|
<label class="erp-field"><span>입고센터</span>
|
|
<select class="erp-select" name="center_id" id="cpg-center-select">
|
|
<option value="">— 선택 —</option>
|
|
{% for c in centers %}
|
|
<option value="{{ c.id }}" data-name="{{ c.name }}"
|
|
{% if shipment and shipment.center_id == c.id %}selected{% endif %}>{{ c.name }}</option>
|
|
{% endfor %}
|
|
</select></label>
|
|
<!-- 센터 스냅샷(자유 입력 허용: 과거 명칭 보존/센터 미등록 시) -->
|
|
<input type="hidden" name="center_name_snapshot" id="cpg-center-name"
|
|
value="{{ shipment.center_name_snapshot if shipment else '' }}" />
|
|
|
|
<label class="erp-field"><span>출고방식</span>
|
|
<select class="erp-select" name="ship_method">
|
|
{% for m in ship_methods %}
|
|
<option value="{{ m }}" {% if shipment and shipment.ship_method == m %}selected{% endif %}>{{ m }}</option>
|
|
{% endfor %}
|
|
</select></label>
|
|
|
|
<label class="erp-field"><span>작업자</span>
|
|
<input class="erp-input" type="text" name="worker"
|
|
value="{{ shipment.worker if shipment else '' }}" /></label>
|
|
|
|
{% if mode == 'new' %}
|
|
<label class="erp-field"><span>상태</span>
|
|
<select class="erp-select" name="status">
|
|
{% for s in statuses %}<option value="{{ s }}">{{ s }}</option>{% endfor %}
|
|
</select></label>
|
|
{% endif %}
|
|
|
|
<label class="erp-field"><span>문서번호(선택)</span>
|
|
<input class="erp-input" type="text" name="document_no"
|
|
value="{{ shipment.document_no if shipment else '' }}" /></label>
|
|
</div>
|
|
|
|
<label class="erp-field cpg-full"><span>출고/박스 요약 (수동 보정 메모)</span>
|
|
<input class="erp-input" type="text" name="outbound_summary"
|
|
placeholder="예: 쿠팡박스 50, 6호상자 1, (50번 박스)"
|
|
value="{{ shipment.outbound_summary if shipment else '' }}" /></label>
|
|
<label class="erp-field cpg-full"><span>메모</span>
|
|
<textarea class="erp-input" name="memo" rows="2">{{ shipment.memo if shipment else '' }}</textarea></label>
|
|
</div>
|
|
|
|
<!-- ── 품목 라인 ── -->
|
|
<div class="erp-card cpg-form-card">
|
|
<div class="cpg-card-head">
|
|
<h2>품목 라인</h2>
|
|
<span class="erp-muted">
|
|
{% if search_enabled %}제품코드 검색 → 제품명 자동 채움.{% else %}상품 검색 비활성(수동 입력).{% endif %}
|
|
수량 입력 시 박스 수 자동 계산.
|
|
</span>
|
|
</div>
|
|
|
|
<div class="erp-table-wrap">
|
|
<table class="erp-table cpg-lines">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th><th>제품코드</th><th>제품명</th><th>수량</th>
|
|
<th>입수량</th><th>박스 계산</th><th>라인메모</th><th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="cpg-lines-body"><!-- JS 렌더 --></tbody>
|
|
</table>
|
|
</div>
|
|
<button type="button" class="erp-btn erp-btn-outline" id="cpg-add-line">+ 라인 추가</button>
|
|
</div>
|
|
|
|
<div class="erp-page-actions">
|
|
<button type="submit" class="erp-btn erp-btn-primary">저장</button>
|
|
{% if mode == 'edit' %}
|
|
<a class="erp-btn erp-btn-outline" href="/cupang/{{ shipment.id }}">취소</a>
|
|
{% else %}
|
|
<a class="erp-btn erp-btn-outline" href="/cupang/">취소</a>
|
|
{% endif %}
|
|
</div>
|
|
</form>
|
|
|
|
<!-- 검색 결과 드롭다운 (JS 가 위치 이동) -->
|
|
<div id="cpg-search-pop" class="cpg-search-pop" hidden></div>
|
|
</section>
|
|
|
|
<script type="application/json" id="cpg-init-lines">
|
|
{% if shipment and shipment.lines %}{{ shipment.lines | tojson }}{% else %}[]{% endif %}
|
|
</script>
|
|
<script type="application/json" id="cpg-box-rules">
|
|
{{ box_rules | tojson }}
|
|
</script>
|
|
<script>
|
|
window.CPG = {
|
|
searchEnabled: {{ 'true' if search_enabled else 'false' }},
|
|
searchUrl: "/cupang/api/products/search",
|
|
calcUrl: "/cupang/api/box-calc"
|
|
};
|
|
</script>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}<script src="/static/cupang.js" defer></script>{% endblock %}
|