完善采购审批流程、企业微信通知和采购专用章
This commit is contained in:
+3
-154
@@ -1,156 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""模拟完整流程:停用/启用/删除 + 主管审核加章,并导出带章 PDF 渲染成 PNG。
|
||||
|
||||
用法:先启动服务(python app.py 8099),再 python test_stamp_toggle.py 8099
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import sqlite3
|
||||
import sys
|
||||
|
||||
import requests
|
||||
|
||||
PORT = sys.argv[1] if len(sys.argv) > 1 else "8099"
|
||||
BASE = "http://127.0.0.1:%s" % PORT
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
OUT = os.path.join(HERE, "out")
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
DB = os.path.join(os.path.dirname(HERE), "po_app", "instance", "po.db")
|
||||
|
||||
FAILS = []
|
||||
|
||||
|
||||
def check(label, cond, extra=""):
|
||||
print((" OK " if cond else " FAIL ") + label + (" " + str(extra) if extra else ""))
|
||||
if not cond:
|
||||
FAILS.append(label)
|
||||
|
||||
|
||||
def new_sess(u, p):
|
||||
s = requests.Session()
|
||||
r = s.post(BASE + "/login", data={"username": u, "password": p})
|
||||
assert r.status_code == 200, r.status_code
|
||||
return s
|
||||
|
||||
|
||||
def flash_of(html):
|
||||
return " | ".join(re.sub(r"<[^>]+>", "", m.group(1)).strip()
|
||||
for m in re.finditer(r'class="flash[^"]*"[^>]*>(.*?)</div>',
|
||||
html, re.S))
|
||||
|
||||
|
||||
def row_html(html, key):
|
||||
"""取出包含指定关键字的那个 <tr>...</tr>。"""
|
||||
for m in re.finditer(r"<tr[^>]*>(.*?)</tr>", html, re.S):
|
||||
if key in m.group(1):
|
||||
return m.group(0)
|
||||
return ""
|
||||
|
||||
|
||||
def dbq(sql, args=()):
|
||||
con = sqlite3.connect(DB)
|
||||
cur = con.cursor()
|
||||
cur.execute(sql, args)
|
||||
r = cur.fetchone()
|
||||
con.close()
|
||||
return r
|
||||
|
||||
|
||||
def main():
|
||||
admin = new_sess("admin", "admin123")
|
||||
|
||||
print("\n[1] 供应商:停用 → 整行置灰 → 启用 → 彻底删除")
|
||||
admin.post(BASE + "/suppliers",
|
||||
data={"code": "S-T1", "name": u"测试供应商T1", "contact": u"测试联系人"})
|
||||
sid = dbq("SELECT id FROM suppliers WHERE code='S-T1'")[0]
|
||||
h = admin.get(BASE + "/suppliers").text
|
||||
check("S-T1 已创建", "S-T1" in h)
|
||||
check("初始为启用态(未置灰)", "row-off" not in row_html(h, "S-T1"))
|
||||
admin.post(BASE + "/suppliers/%d/toggle" % sid)
|
||||
h = admin.get(BASE + "/suppliers").text
|
||||
check("停用后整行置灰", "row-off" in row_html(h, "S-T1"))
|
||||
check("停用后按钮变为『启用』", u"启用" in row_html(h, "S-T1"))
|
||||
check("停用后仍可编辑(保留入口)", "openEdit" in row_html(h, "S-T1"))
|
||||
admin.post(BASE + "/suppliers/%d/toggle" % sid)
|
||||
h = admin.get(BASE + "/suppliers").text
|
||||
check("启用后恢复(不再置灰)", "row-off" not in row_html(h, "S-T1"))
|
||||
admin.post(BASE + "/suppliers/%d/delete" % sid)
|
||||
h = admin.get(BASE + "/suppliers").text
|
||||
check("删除后从列表消失", "S-T1" not in h)
|
||||
|
||||
print("\n[2] 物料:停用 → 整行置灰 → 启用 → 彻底删除")
|
||||
admin.post(BASE + "/materials",
|
||||
data={"code": "M-T1", "spec": u"测试物料T1", "unit": u"件", "price": "9.9"})
|
||||
mid = dbq("SELECT id FROM materials WHERE code='M-T1'")[0]
|
||||
h = admin.get(BASE + "/materials").text
|
||||
check("M-T1 已创建", "M-T1" in h)
|
||||
check("初始为启用态(未置灰)", "row-off" not in row_html(h, "M-T1"))
|
||||
admin.post(BASE + "/materials/%d/toggle" % mid)
|
||||
h = admin.get(BASE + "/materials").text
|
||||
check("停用后整行置灰", "row-off" in row_html(h, "M-T1"))
|
||||
admin.post(BASE + "/materials/%d/toggle" % mid)
|
||||
h = admin.get(BASE + "/materials").text
|
||||
check("启用后恢复", "row-off" not in row_html(h, "M-T1"))
|
||||
admin.post(BASE + "/materials/%d/delete" % mid)
|
||||
h = admin.get(BASE + "/materials").text
|
||||
check("删除后从列表消失", "M-T1" not in h)
|
||||
|
||||
print("\n[3] 主管审核:确认前必须先加章")
|
||||
r = admin.post(BASE + "/orders/new", data={"doc_type": "purchase"})
|
||||
m = re.search(r"/orders/(\d+)/edit", r.url)
|
||||
oid = int(m.group(1))
|
||||
admin.post(BASE + "/orders/%d" % oid, data={
|
||||
"supplier_name": u"测试供应商",
|
||||
"item_code": ["M-1001"], "item_spec": [u"测试物料"],
|
||||
"item_unit": [u"件"], "item_qty": ["10"], "item_price": ["12.5"],
|
||||
"item_date": [""], "item_remark": [""],
|
||||
})
|
||||
admin.post(BASE + "/orders/%d/submit" % oid, data={"comment": u"模拟提交"})
|
||||
st = dbq("SELECT status FROM orders WHERE id=?", (oid,))[0]
|
||||
check("订单已提交,状态待审核", st == "pending_review", st)
|
||||
|
||||
rv = new_sess("reviewer", "123456")
|
||||
r = rv.post(BASE + "/orders/%d/review" % oid,
|
||||
data={"comment": u"直接点确认试试", "stamped": "0"})
|
||||
check("未加章 → 被拒绝并提示", u"请先加盖审核章" in flash_of(r.text),
|
||||
flash_of(r.text))
|
||||
st = dbq("SELECT status FROM orders WHERE id=?", (oid,))[0]
|
||||
check("未加章时状态不变", st == "pending_review", st)
|
||||
|
||||
r = rv.post(BASE + "/orders/%d/review" % oid,
|
||||
data={"comment": u"已核对无误", "stamped": "1"})
|
||||
row = dbq("SELECT status, reviewed_by FROM orders WHERE id=?", (oid,))
|
||||
check("加章后审核通过", row[0] == "pending_approval", row)
|
||||
check("记录了审核人", bool(row[1]), row[1])
|
||||
|
||||
print("\n[4] 导出带章 PDF 并渲染预览")
|
||||
pdf_bytes = admin.get(BASE + "/orders/%d/pdf" % oid).content
|
||||
pdf_path = os.path.join(OUT, "seal_review.pdf")
|
||||
with open(pdf_path, "wb") as f:
|
||||
f.write(pdf_bytes)
|
||||
check("PDF 已生成", len(pdf_bytes) > 10000, "%d bytes" % len(pdf_bytes))
|
||||
try:
|
||||
import fitz
|
||||
doc = fitz.open(pdf_path)
|
||||
pix = doc[-1].get_pixmap(dpi=130)
|
||||
png_path = os.path.join(OUT, "seal_review.png")
|
||||
pix.save(png_path)
|
||||
print(" 渲染预览:", png_path, "共 %d 页" % doc.page_count)
|
||||
doc.close()
|
||||
except Exception as e:
|
||||
print(" 渲染预览失败:", e)
|
||||
|
||||
print("\n[5] 清理测试订单")
|
||||
con = sqlite3.connect(DB)
|
||||
cur = con.cursor()
|
||||
cur.execute("DELETE FROM order_items WHERE order_id=?", (oid,))
|
||||
cur.execute("DELETE FROM orders WHERE id=?", (oid,))
|
||||
con.commit()
|
||||
con.close()
|
||||
print(" 已删除订单 %d" % oid)
|
||||
|
||||
print("\n" + ("模拟全部通过" if not FAILS else "失败: " + "; ".join(FAILS)))
|
||||
|
||||
"""Compatibility entry point; tests only use temporary databases."""
|
||||
from run_tests import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
raise SystemExit(main(('-k', 'full_flow')))
|
||||
|
||||
Reference in New Issue
Block a user