Files
dbx-main/app/modules/dispatch/templates/dispatch/new.html
T
king 8d7fe01c2d feat(dispatch): 메뉴얼 오더 플랫폼 추가(엑셀 단독)
- 플랫폼 Manual 추가. 엑셀 첫 시트(Receiver Name/Phone/Address/Product Name/
  Item Code/Quantity)를 전용 파서로 읽어 1행=1박스 생성
  · 받는 사람 정보가 엑셀에 직접 있어 PDF 불필요(라벨 슬롯 없음)
  · 묶음키 없음 → 행마다 별도 박스
- 업로드 화면: Manual 선택 시 라벨 PDF 칸 숨김 + 안내문
- 출고 카드: Order ID/Tracking 은 값 있을 때만 표시(Manual 은 숨김),
  Manual 은 상품명 표기(받는사람/전화/주소/상품명/수량)
- 재고 차감/사방넷 출고는 기존 집계 로직 그대로(콤보 _N 분해 포함)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 12:16:19 +09:00

110 lines
6.1 KiB
HTML

{% extends "erp_base.html" %}
{% block content %}
<section class="dsp">
{% include "dispatch/_nav.html" %}
<div class="erp-card" style="max-width:640px;">
<div class="cpg-card-head"><h2 data-ko="출고 파일 업로드" data-en="Upload Dispatch Files">출고 파일 업로드</h2></div>
<p class="erp-muted" id="dsp-intro" style="margin:4px 0 16px;"></p>
<form method="post" action="/dispatch/batches" enctype="multipart/form-data" style="display:flex;flex-direction:column;gap:14px;">
<label style="display:flex;flex-direction:column;gap:4px;">
<span><span data-ko="출고 날짜" data-en="Dispatch Date">출고 날짜</span> <span style="color:#dc2626;">*</span></span>
<input class="erp-input" type="date" name="dispatch_date" value="{{ today }}" required />
</label>
<label style="display:flex;flex-direction:column;gap:4px;">
<span data-ko="플랫폼" data-en="Platform">플랫폼</span>
<select class="erp-select" name="platform" id="dsp-platform">
{% for pf in platforms %}
<option value="{{ pf }}">{{ pf }}</option>
{% endfor %}
</select>
</label>
<label style="display:flex;flex-direction:column;gap:4px;">
<span><span data-ko="배치명" data-en="Batch name">배치명</span>
<span class="erp-muted" data-ko="(예: 2026-06-19 오전 출고)" data-en="(e.g. 2026-06-19 AM)">(예: 2026-06-19 오전 출고)</span></span>
<input class="erp-input" type="text" name="batch_name"
data-ko-ph="오전 출고 / 오후 출고 등으로 구분" data-en-ph="e.g. AM dispatch / PM dispatch"
placeholder="오전 출고 / 오후 출고 등으로 구분" />
</label>
<label id="dsp-label-row" style="display:flex;flex-direction:column;gap:4px;">
<span id="dsp-label-lbl"></span>
<input class="erp-input" type="file" name="label_pdf" id="dsp-label" accept="application/pdf" />
</label>
<label style="display:flex;flex-direction:column;gap:4px;">
<span id="dsp-data-lbl"></span>
<input class="erp-input" type="file" name="data_xlsx" id="dsp-data"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" required />
</label>
<div style="display:flex;gap:8px;margin-top:8px;">
<button class="erp-btn erp-btn-primary" type="submit" data-ko="업로드 후 배치 생성" data-en="Upload &amp; Create">업로드 후 배치 생성</button>
<a class="erp-btn erp-btn-outline" href="/dispatch/" data-ko="취소" data-en="Cancel">취소</a>
</div>
</form>
</div>
</section>
{% endblock %}
{% block scripts %}
<script>
(function () {
// 플랫폼별 안내/파일 라벨(한/영). 데이터 엑셀 필수, 라벨 PDF 선택(보관·PII 추출용).
var CFG = {
ko: {
"TikTok": {
intro: "TikTok: Order Export.xlsx 로 출고 리스트가 생성됩니다. 받는 사람 이름/주소는 라벨 PDF 에서 가져오니 PDF 도 함께 올리세요.",
label: "📄 Shipping label + Packing slip.pdf <span class='erp-muted'>(받는 사람 이름/주소 추출 · 권장)</span>",
data: "📊 TikTok Order Export.xlsx <span style='color:#dc2626;'>*</span> <span class='erp-muted'>(자동 출고 리스트 기준)</span>"
},
"Shopee": {
intro: "Shopee: Packing List.Doorstep Delivery.xlsx 로 출고 리스트가 생성됩니다. 받는 사람 이름/주소는 Shopee Seller Centre.pdf 에서 가져오니 PDF 도 함께 올리세요.",
label: "📄 Shopee Seller Centre.pdf <span class='erp-muted'>(받는 사람 이름/주소 추출 · 권장)</span>",
data: "📊 Packing List.Doorstep Delivery.xlsx <span style='color:#dc2626;'>*</span> <span class='erp-muted'>(자동 출고 리스트 기준)</span>"
},
"Manual": {
intro: "메뉴얼 오더: 엑셀 파일만 올리세요. 첫 시트의 받는 사람/전화/주소/상품/수량을 읽어 출고 리스트를 만듭니다(PDF 불필요).",
label: "",
data: "📊 Manual Order.xlsx <span style='color:#dc2626;'>*</span> <span class='erp-muted'>(받는사람·상품·수량 포함)</span>"
}
},
en: {
"TikTok": {
intro: "TikTok: the dispatch list is built from Order Export.xlsx. Recipient name/address come from the label PDF, so please upload the PDF too.",
label: "📄 Shipping label + Packing slip.pdf <span class='erp-muted'>(recipient name/address · recommended)</span>",
data: "📊 TikTok Order Export.xlsx <span style='color:#dc2626;'>*</span> <span class='erp-muted'>(dispatch list source)</span>"
},
"Shopee": {
intro: "Shopee: the dispatch list is built from Packing List.Doorstep Delivery.xlsx. Recipient name/address come from Shopee Seller Centre.pdf, so please upload the PDF too.",
label: "📄 Shopee Seller Centre.pdf <span class='erp-muted'>(recipient name/address · recommended)</span>",
data: "📊 Packing List.Doorstep Delivery.xlsx <span style='color:#dc2626;'>*</span> <span class='erp-muted'>(dispatch list source)</span>"
},
"Manual": {
intro: "Manual order: upload the Excel file only. Recipient/phone/address/product/qty are read from the first sheet (no PDF needed).",
label: "",
data: "📊 Manual Order.xlsx <span style='color:#dc2626;'>*</span> <span class='erp-muted'>(includes recipient, product, qty)</span>"
}
}
};
var sel = document.getElementById('dsp-platform');
function apply() {
var lang = (window.dspLang && window.dspLang() === 'en') ? 'en' : 'ko';
var c = (CFG[lang] && CFG[lang][sel.value]) || CFG[lang]["TikTok"];
document.getElementById('dsp-intro').textContent = c.intro;
document.getElementById('dsp-label-lbl').innerHTML = c.label;
document.getElementById('dsp-data-lbl').innerHTML = c.data;
// 라벨(PDF) 슬롯이 없는 플랫폼(Manual)은 라벨 업로드 칸을 숨긴다.
document.getElementById('dsp-label-row').style.display = c.label ? '' : 'none';
}
sel.addEventListener('change', apply);
document.addEventListener('dsp:lang', apply); // 언어 토글 시 재적용
apply();
})();
</script>
{% endblock %}