202 lines
10 KiB
HTML
202 lines
10 KiB
HTML
{% extends "base.html" %}
|
||
{% block body %}
|
||
<h1 class="page">编辑订单 · {{ o.order_no }}({{ o.doc_type_text }})</h1>
|
||
|
||
<div class="card">
|
||
<h2>单据信息</h2>
|
||
<form method="post" id="orderForm">
|
||
<div class="form-grid">
|
||
<div><label>采购单号</label><input type="text" value="{{ o.order_no }}" disabled></div>
|
||
<div><label>采购日期</label><input type="date" name="order_date" value="{{ o.order_date or '' }}"></div>
|
||
<div><label>税点</label><input type="text" name="tax_rate" value="{{ o.tax_rate or '' }}" placeholder="如 13%"></div>
|
||
</div>
|
||
|
||
<h3>供方(供应商)</h3>
|
||
<div class="form-grid">
|
||
<div>
|
||
<label>供应商</label>
|
||
<input type="text" name="supplier_name" id="supplier_name" value="{{ o.supplier_name or '' }}">
|
||
<select id="supplierPick" style="margin-top:4px;">
|
||
<option value="">-- 从供应商库带入 --</option>
|
||
{% for s in suppliers %}<option value="{{ s.id }}">{{ s.name }}</option>{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div><label>联系人</label><input type="text" name="supplier_contact" id="supplier_contact" value="{{ o.supplier_contact or '' }}"></div>
|
||
<div><label>电话</label><input type="text" name="supplier_phone" id="supplier_phone" value="{{ o.supplier_phone or '' }}"></div>
|
||
<div><label>付款方式</label><input type="text" name="payment_terms" id="payment_terms" value="{{ o.payment_terms or '' }}"></div>
|
||
<div><label>税号</label><input type="text" name="supplier_tax_no" id="supplier_tax_no" value="{{ o.supplier_tax_no or '' }}"></div>
|
||
<div><label>银行帐号</label><input type="text" name="supplier_bank_account" id="supplier_bank_account" value="{{ o.supplier_bank_account or '' }}"></div>
|
||
<div><label>开户银行</label><input type="text" name="supplier_bank_name" id="supplier_bank_name" value="{{ o.supplier_bank_name or '' }}"></div>
|
||
</div>
|
||
|
||
<h3>需方(本公司)</h3>
|
||
<div class="form-grid">
|
||
<div><label>需方名称</label><input type="text" name="our_company" value="{{ o.our_company or '' }}"></div>
|
||
<div><label>联系人</label><input type="text" name="our_contact" value="{{ o.our_contact or '' }}"></div>
|
||
<div><label>电话</label><input type="text" name="our_phone" value="{{ o.our_phone or '' }}"></div>
|
||
<div><label>税号</label><input type="text" name="our_tax_no" value="{{ o.our_tax_no or '' }}"></div>
|
||
<div style="grid-column: span 2;">
|
||
<label>交货地点</label>
|
||
<input type="text" name="delivery_place" value="{{ o.delivery_place or '' }}">
|
||
</div>
|
||
</div>
|
||
|
||
<h3>物料明细</h3>
|
||
<table class="grid" id="itemTable">
|
||
<tr>
|
||
<th style="width:38px;">序</th>
|
||
<th style="width:150px;">物料代码</th>
|
||
<th>物料规格</th>
|
||
<th style="width:62px;">单位</th>
|
||
<th style="width:78px;">数量</th>
|
||
<th style="width:92px;">含税单价</th>
|
||
<th style="width:96px;">金额</th>
|
||
<th style="width:118px;">交期</th>
|
||
<th style="width:130px;">备注</th>
|
||
<th style="width:44px;">删</th>
|
||
</tr>
|
||
{% for it in o.items %}
|
||
<tr>
|
||
<td class="center seq">{{ loop.index }}</td>
|
||
<td><input type="text" name="item_code" value="{{ it.material_code or '' }}">
|
||
<select class="matpick" style="margin-top:3px;">
|
||
<option value="">-- 物料库 --</option>
|
||
{% for m in materials %}<option value="{{ m.id }}" data-code="{{ m.code }}" data-spec="{{ m.spec }}" data-unit="{{ m.unit }}" data-price="{{ m.price }}">{{ m.code }} {{ m.spec }}</option>{% endfor %}
|
||
</select>
|
||
</td>
|
||
<td><input type="text" name="item_spec" value="{{ it.material_spec or '' }}"></td>
|
||
<td><input type="text" name="item_unit" value="{{ it.unit or '' }}"></td>
|
||
<td><input type="number" step="0.0001" name="item_qty" class="qty" value="{{ it.qty or 0 }}"></td>
|
||
<td><input type="number" step="0.0001" name="item_price" class="price" value="{{ it.price or 0 }}"></td>
|
||
<td><input type="text" class="amt" value="{{ '%.2f'|format(it.amount or 0) }}" disabled></td>
|
||
<td><input type="date" name="item_date" value="{{ it.delivery_date or '' }}"></td>
|
||
<td><input type="text" name="item_remark" value="{{ it.remark or '' }}"></td>
|
||
<td class="center"><button type="button" class="btn sm danger" onclick="delRow(this)">×</button></td>
|
||
</tr>
|
||
{% endfor %}
|
||
</table>
|
||
|
||
<template id="rowTpl">
|
||
<tr>
|
||
<td class="center seq">1</td>
|
||
<td><input type="text" name="item_code" value="">
|
||
<select class="matpick" style="margin-top:3px;">
|
||
<option value="">-- 物料库 --</option>
|
||
{% for m in materials %}<option value="{{ m.id }}" data-code="{{ m.code }}" data-spec="{{ m.spec }}" data-unit="{{ m.unit }}" data-price="{{ m.price }}">{{ m.code }} {{ m.spec }}</option>{% endfor %}
|
||
</select>
|
||
</td>
|
||
<td><input type="text" name="item_spec" value=""></td>
|
||
<td><input type="text" name="item_unit" value=""></td>
|
||
<td><input type="number" step="0.0001" name="item_qty" class="qty" value="0"></td>
|
||
<td><input type="number" step="0.0001" name="item_price" class="price" value="0"></td>
|
||
<td><input type="text" class="amt" value="0.00" disabled></td>
|
||
<td><input type="date" name="item_date" value=""></td>
|
||
<td><input type="text" name="item_remark" value=""></td>
|
||
<td class="center"><button type="button" class="btn sm danger" onclick="delRow(this)">×</button></td>
|
||
</tr>
|
||
</template>
|
||
|
||
<div class="toolbar" style="margin-top:10px;">
|
||
<button type="button" class="btn" onclick="addRow()">+ 添加一行</button>
|
||
<span class="grow"></span>
|
||
<span class="total-bar">合计:<span class="amt" id="totalAmt">{{ '%.2f'|format(o.total_amount) }}</span> 元
|
||
<span class="muted" id="totalCn">{{ total_cn }}</span></span>
|
||
</div>
|
||
|
||
<h3>补充说明</h3>
|
||
<textarea name="note" placeholder="选填,会打印在 PDF 备注区">{{ o.note or '' }}</textarea>
|
||
|
||
<div style="margin-top:16px;">
|
||
<button class="btn primary" type="submit">保存</button>
|
||
<a class="btn" href="{{ url_for('order_view', oid=o.id) }}">查看订单</a>
|
||
<a class="btn" href="{{ url_for('order_pdf', oid=o.id) }}" target="_blank">预览 PDF</a>
|
||
</div>
|
||
</form>
|
||
|
||
<form method="post" action="{{ url_for('order_submit', oid=o.id) }}" style="margin-top:10px;">
|
||
<div class="toolbar">
|
||
<input type="text" name="comment" placeholder="提交说明(选填)" style="width:260px;">
|
||
<button class="btn ok">提交主管审核</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>从 Excel 导入明细</h2>
|
||
<div class="hint">
|
||
支持 .xlsx / .xls。系统自动识别表头(物料代码、物料规格、单位、数量、含税单价、交期、备注),
|
||
没有表头则按前 7 列顺序读取。行数超出模板也没关系,PDF 会自动分页。
|
||
<a href="{{ url_for('import_template') }}">下载导入模板</a>
|
||
</div>
|
||
<form method="post" action="{{ url_for('import_excel', oid=o.id) }}" enctype="multipart/form-data" class="toolbar">
|
||
<input type="file" name="file" accept=".xls,.xlsx" required style="width:280px;">
|
||
<select name="mode" style="width:140px;">
|
||
<option value="append">追加到现有明细</option>
|
||
<option value="replace">替换全部明细</option>
|
||
</select>
|
||
<button class="btn primary">导入</button>
|
||
</form>
|
||
</div>
|
||
|
||
<script>
|
||
const MATERIALS = {{ materials|map(attribute='id')|list|tojson }};
|
||
function bindRow(tr){
|
||
tr.querySelectorAll('.qty, .price').forEach(i => i.addEventListener('input', calc));
|
||
const pick = tr.querySelector('.matpick');
|
||
if (pick) pick.addEventListener('change', function(){
|
||
const opt = this.selectedOptions[0];
|
||
if (!opt || !opt.value) return;
|
||
tr.querySelector('[name=item_code]').value = opt.dataset.code || '';
|
||
tr.querySelector('[name=item_spec]').value = opt.dataset.spec || '';
|
||
tr.querySelector('[name=item_unit]').value = opt.dataset.unit || '';
|
||
tr.querySelector('.price').value = opt.dataset.price || 0;
|
||
calc();
|
||
});
|
||
}
|
||
function calc(){
|
||
let total = 0;
|
||
document.querySelectorAll('#itemTable tr').forEach((tr, idx) => {
|
||
const q = parseFloat(tr.querySelector('.qty')?.value || 0);
|
||
const p = parseFloat(tr.querySelector('.price')?.value || 0);
|
||
const a = (isNaN(q) ? 0 : q) * (isNaN(p) ? 0 : p);
|
||
const amt = tr.querySelector('.amt');
|
||
if (amt) amt.value = a.toFixed(2);
|
||
total += a;
|
||
const seq = tr.querySelector('.seq');
|
||
if (seq) seq.textContent = idx;
|
||
});
|
||
document.getElementById('totalAmt').textContent = total.toFixed(2);
|
||
}
|
||
function addRow(){
|
||
// 从 <template> 克隆,避免"明细为空时没有可复制的行"导致点击无反应
|
||
const t = document.getElementById('itemTable');
|
||
const tr = document.getElementById('rowTpl').content.firstElementChild.cloneNode(true);
|
||
tr.querySelectorAll('input').forEach(i => { if (i.type !== 'date') i.value = ''; });
|
||
const q = tr.querySelector('.qty'); if (q) q.value = 0;
|
||
const p = tr.querySelector('.price'); if (p) p.value = 0;
|
||
const a = tr.querySelector('.amt'); if (a) a.value = '0.00';
|
||
const sel = tr.querySelector('.matpick'); if (sel) sel.selectedIndex = 0;
|
||
t.appendChild(tr);
|
||
bindRow(tr); calc();
|
||
}
|
||
function delRow(btn){
|
||
btn.closest('tr').remove(); calc();
|
||
}
|
||
document.querySelectorAll('#itemTable tr').forEach(bindRow);
|
||
calc();
|
||
document.getElementById('supplierPick').addEventListener('change', async function(){
|
||
if (!this.value) return;
|
||
const r = await fetch('/api/suppliers').then(r => r.json());
|
||
const s = r.find(x => String(x.id) === this.value);
|
||
if (!s) return;
|
||
document.getElementById('supplier_name').value = s.name || '';
|
||
document.getElementById('supplier_contact').value = s.contact || '';
|
||
document.getElementById('supplier_phone').value = s.phone || '';
|
||
document.getElementById('supplier_tax_no').value = s.tax_no || '';
|
||
document.getElementById('supplier_bank_name').value = s.bank_name || '';
|
||
document.getElementById('supplier_bank_account').value = s.bank_account || '';
|
||
document.getElementById('payment_terms').value = s.payment_terms || '';
|
||
});
|
||
</script>
|
||
{% endblock %}
|