d128744346
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
207 lines
7.9 KiB
HTML
207 lines
7.9 KiB
HTML
{% extends "erp_base.html" %}
|
|
|
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260903n" />{% endblock %}
|
|
|
|
{% block content %}
|
|
{# 출고 묶음 보기 — 상자 계산 화면과 같은 3열 구성. 읽기 전용(수정 없음). #}
|
|
<section class="cpg">
|
|
|
|
<div class="erp-page-actions">
|
|
<a class="erp-btn erp-btn-primary" href="/cupang/?date={{ shipment.ship_date }}">◀◀ 달력</a>
|
|
<span class="erp-badge erp-badge-neutral">{{ shipment.status }}</span>
|
|
</div>
|
|
|
|
<div class="cpg-calc3">
|
|
|
|
<!-- ① 품목 -->
|
|
<div class="erp-card cpg-form-card cpg-calc-card">
|
|
<div class="cpg-card-head">
|
|
<h2>① 품목</h2>
|
|
<span class="erp-muted">{{ items|length }}종 · {{ total_qty }}개</span>
|
|
</div>
|
|
|
|
<div class="erp-table-wrap">
|
|
<table class="erp-table cpg-calc-table">
|
|
<colgroup>
|
|
<col class="cpg-col-name" />
|
|
<col class="cpg-col-qty" />
|
|
</colgroup>
|
|
<thead>
|
|
<tr><th>제품명</th><th>수량</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for it in items %}
|
|
<tr class="cpg-view-row">
|
|
<td title="{{ it.product_name }}">{{ it.product_name }}</td>
|
|
<td class="cpg-calc-num">{{ it.quantity }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% if not items %}
|
|
<tr><td colspan="2" class="erp-muted">품목이 없습니다.</td></tr>
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ② 상자 목록 -->
|
|
<div class="erp-card cpg-form-card cpg-calc-sum">
|
|
<div class="cpg-card-head">
|
|
<h2>② 상자 목록</h2>
|
|
<span class="erp-muted">상자마다 담긴 제품과 수량</span>
|
|
<span class="cpg-boxno-count" id="cpg-boxno-count">체크 0/{{ box_list|length }}</span>
|
|
<a class="erp-btn cpg-boxno-dl"
|
|
href="/cupang/{{ shipment.id }}/boxes.xlsx">엑셀 다운로드</a>
|
|
</div>
|
|
|
|
<div id="cpg-sum-body">
|
|
<div class="cpg-sum-kpis">
|
|
<div class="cpg-kpi">
|
|
<span class="cpg-kpi-label">총 상자</span>
|
|
<strong class="cpg-kpi-value">{{ box_list|length }}상자</strong>
|
|
<span class="cpg-kpi-hint">제품별 + 혼합</span>
|
|
</div>
|
|
<div class="cpg-kpi">
|
|
<span class="cpg-kpi-label">출고</span>
|
|
<strong class="cpg-kpi-value">{{ shipment.outbound_summary or '—' }}</strong>
|
|
<span class="cpg-kpi-hint">확정 시 기록</span>
|
|
</div>
|
|
<div class="cpg-kpi">
|
|
<span class="cpg-kpi-label">총 수량</span>
|
|
<strong class="cpg-kpi-value">{{ total_qty }}개</strong>
|
|
<span class="cpg-kpi-hint">{{ items|length }}종</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="cpg-sum-scroll">
|
|
<table class="erp-table cpg-boxno-table">
|
|
<colgroup>
|
|
<col class="cpg-boxno-c-no" />
|
|
<col class="cpg-boxno-c-name" />
|
|
<col class="cpg-boxno-c-code" />
|
|
<col class="cpg-boxno-c-qty" />
|
|
</colgroup>
|
|
<thead>
|
|
<tr><th>상자번호</th><th>제품명</th><th>제품코드</th><th>수량</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for b in box_list %}
|
|
{% for it in b['items'] %}
|
|
<tr data-box="{{ b.no }}" class="{% if loop.first %}is-boxtop{% endif %}">
|
|
{% if loop.first %}
|
|
<td class="cpg-boxno-cell" rowspan="{{ b['items']|length }}">{{ b.no }}</td>
|
|
{% endif %}
|
|
<td title="{{ it.product_name }}">{{ it.product_name }}</td>
|
|
<td class="cpg-boxno-code">{{ it.product_code }}</td>
|
|
<td class="cpg-calc-num">{{ it.quantity }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{% if not box_list %}
|
|
<tr><td colspan="4" class="erp-muted">상자 정보가 없습니다.</td></tr>
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ③ 센터 -->
|
|
<div class="erp-card cpg-form-card cpg-dist-card">
|
|
<div class="cpg-card-head">
|
|
<h2>③ 센터</h2>
|
|
<span class="erp-muted">출고 #{{ shipment.id }}</span>
|
|
</div>
|
|
|
|
<div class="cpg-dist-list">
|
|
<div class="cpg-dist-center has-items">
|
|
<div class="cpg-dist-head">
|
|
<strong>{{ shipment.center_name_snapshot or '센터 미지정' }}</strong>
|
|
<span class="erp-badge erp-badge-neutral">{{ shipment.ship_method }}</span>
|
|
<span class="cpg-dist-sum">
|
|
<span class="erp-badge erp-badge-neutral">{{ calc.grand_total_boxes }}상자</span>
|
|
<span class="erp-badge erp-badge-neutral">{{ total_qty }}개</span>
|
|
</span>
|
|
</div>
|
|
<ul class="cpg-dist-items">
|
|
{% if shipment.box_plan %}
|
|
{% for e in shipment.box_plan %}
|
|
<li class="cpg-dist-item{% if e.kind == 'mix' %} is-mix{% endif %}">
|
|
<div class="cpg-dist-line">
|
|
<span class="cpg-dist-name">{{ e.name }}</span>
|
|
<span class="cpg-dist-unit">{{ e.count }}상자 · {{ e.quantity }}개</span>
|
|
</div>
|
|
{% if e.kind == 'mix' and e['items'] %}
|
|
<ul class="cpg-dist-tree">
|
|
{% for it in e['items'] %}
|
|
<li><span class="cpg-tree-name">{{ it.product_name }}</span>
|
|
<span class="cpg-tree-qty">{{ it.quantity }}개</span></li>
|
|
{% endfor %}
|
|
</ul>
|
|
{% endif %}
|
|
</li>
|
|
{% endfor %}
|
|
{% else %}
|
|
{% for it in items %}
|
|
<li class="cpg-dist-item">
|
|
<div class="cpg-dist-line">
|
|
<span class="cpg-dist-name">{{ it.product_name }}</span>
|
|
<span class="cpg-dist-unit">{{ it.quantity }}개</span>
|
|
</div>
|
|
</li>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
|
|
<dl class="cpg-view-meta">
|
|
<div><dt>작성일</dt><dd>{{ shipment.document_date }}</dd></div>
|
|
<div><dt>출고일</dt><dd>{{ shipment.ship_date }}</dd></div>
|
|
<div><dt>센터입고일</dt><dd>{{ shipment.center_arrival_date }}</dd></div>
|
|
<div><dt>작업자</dt><dd>{{ shipment.worker or '—' }}</dd></div>
|
|
{% if shipment.memo %}<div><dt>메모</dt><dd>{{ shipment.memo }}</dd></div>{% endif %}
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- /cpg-calc3 -->
|
|
</section>
|
|
|
|
<script>
|
|
// 상자 목록 행 클릭 → 체크 표시 토글(상자 단위). 세는 동안 눈으로 확인하려는 용도.
|
|
(function () {
|
|
var table = document.querySelector(".cpg-boxno-table");
|
|
var counter = document.getElementById("cpg-boxno-count");
|
|
if (!table) return;
|
|
var total = table.querySelectorAll("tbody tr[data-box]").length
|
|
? new Set(Array.prototype.map.call(
|
|
table.querySelectorAll("tbody tr[data-box]"),
|
|
function (tr) { return tr.getAttribute("data-box"); }
|
|
)).size
|
|
: 0;
|
|
|
|
function refresh() {
|
|
if (!counter) return;
|
|
var done = new Set();
|
|
table.querySelectorAll("tbody tr.is-checked[data-box]").forEach(function (tr) {
|
|
done.add(tr.getAttribute("data-box"));
|
|
});
|
|
counter.textContent = "체크 " + done.size + "/" + total;
|
|
counter.classList.toggle("is-on", done.size > 0);
|
|
}
|
|
|
|
table.addEventListener("click", function (e) {
|
|
var tr = e.target.closest("tbody tr[data-box]");
|
|
if (!tr) return;
|
|
var no = tr.getAttribute("data-box");
|
|
var rows = table.querySelectorAll('tbody tr[data-box="' + no + '"]');
|
|
var on = !tr.classList.contains("is-checked");
|
|
rows.forEach(function (r) { r.classList.toggle("is-checked", on); });
|
|
refresh();
|
|
});
|
|
|
|
refresh();
|
|
})();
|
|
</script>
|
|
{% endblock %}
|