# -*- 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[^"]*"[^>]*>(.*?)', html, re.S)) def row_html(html, key): """取出包含指定关键字的那个 ...。""" for m in re.finditer(r"]*>(.*?)", 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))) if __name__ == "__main__": main()