feat: 生产订单新增导出 Excel 与打印功能
- 订单列表页「导出 Excel」(/orders/export): 导出全部生产订单(订单号/BOM/接单量/工厂/状态/经手人/下单时间/备注) - 订单详情页「导出 Excel」(/order/<id>/export): 导出派工单, 含「订单信息」+「领料明细」双 sheet - 订单详情页「打印」按钮: window.print() + @media print 样式(隐藏导航/按钮, 输入框转纯文本, 隐藏提示), 输出干净派工单
This commit is contained in:
@@ -1468,6 +1468,23 @@ def orders():
|
||||
return render_template("orders.html", data=data)
|
||||
|
||||
|
||||
@app.route("/orders/export")
|
||||
@login_required
|
||||
@role_required("admin", "manager")
|
||||
def orders_export():
|
||||
"""导出全部生产订单为 Excel。"""
|
||||
os_ = db.session.scalars(db.select(ProdOrder).order_by(ProdOrder.order_no.desc())).all()
|
||||
data = []
|
||||
for o in os_:
|
||||
bom = db.session.get(Bom, o.bom_id)
|
||||
fac = db.session.get(Factory, o.factory_id) if o.factory_id else None
|
||||
data.append({"o": o, "bom": bom, "factory": fac})
|
||||
from excel_io import export_orders
|
||||
path = os.path.join(EXE_DIR, f"生产订单_{date.today().isoformat()}.xlsx")
|
||||
export_orders(path, data)
|
||||
return send_file(path, as_attachment=True, download_name=os.path.basename(path))
|
||||
|
||||
|
||||
@app.route("/order/new", methods=["GET", "POST"])
|
||||
@login_required
|
||||
@role_required("admin", "manager")
|
||||
@@ -1540,6 +1557,44 @@ def order_detail(oid):
|
||||
posted_count=posted_count)
|
||||
|
||||
|
||||
@app.route("/order/<int:oid>/export")
|
||||
@login_required
|
||||
@role_required("admin", "manager")
|
||||
def order_export(oid):
|
||||
"""导出单个生产订单详情(派工单)为 Excel。"""
|
||||
o = db.session.get(ProdOrder, oid)
|
||||
if not o:
|
||||
return redirect(url_for("orders"))
|
||||
bom = db.session.get(Bom, o.bom_id)
|
||||
items = db.session.scalars(db.select(BomItem).where(BomItem.bom_id == o.bom_id)).all()
|
||||
sm = stock_map_as_of(o.factory_id, o.created_at)
|
||||
fac = db.session.get(Factory, o.factory_id) if o.factory_id else None
|
||||
allocs = db.session.scalars(
|
||||
db.select(ProdOrderAlloc).where(ProdOrderAlloc.order_id == oid)).all()
|
||||
alloc_map = {a.material_id: a for a in allocs}
|
||||
reqs = []
|
||||
for it in items:
|
||||
m = db.session.get(Material, it.material_id)
|
||||
need = it.qty_per_unit * o.qty
|
||||
have = sm.get(m.id, 0)
|
||||
a = alloc_map.get(m.id)
|
||||
subs = [{"pn": s["sub"].part_number, "mf": s["sub"].manufacturer or "-",
|
||||
"stock": round(s["stock"], 3), "available": s["available"]}
|
||||
for s in substitute_rows(m.id, o.factory_id, None)]
|
||||
reqs.append({"m": m, "need": need, "have": have,
|
||||
"gap": have - need, "short": need > have, "subs": subs,
|
||||
"alloc": a.alloc_qty if a else 0,
|
||||
"posted": a.posted if a else False})
|
||||
reqs.sort(key=lambda x: x["gap"])
|
||||
posted_total = sum(a.alloc_qty for a in allocs if a.posted)
|
||||
planned_total = sum(a.alloc_qty for a in allocs)
|
||||
posted_count = sum(1 for a in allocs if a.posted)
|
||||
from excel_io import export_order_detail
|
||||
path = os.path.join(EXE_DIR, f"生产订单_{o.order_no}.xlsx")
|
||||
export_order_detail(path, o, bom, reqs, fac, posted_total, planned_total, posted_count)
|
||||
return send_file(path, as_attachment=True, download_name=os.path.basename(path))
|
||||
|
||||
|
||||
@app.route("/order/<int:oid>/pick", methods=["POST"])
|
||||
@login_required
|
||||
@role_required("admin", "manager")
|
||||
|
||||
Reference in New Issue
Block a user