完善采购审批流程、企业微信通知和采购专用章
This commit is contained in:
+37
-75
@@ -1,82 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""打包后 EXE 冒烟测试。
|
||||
|
||||
确认这些确实进了包:批量导入入口与模板、列表编辑入口、弹窗样式,
|
||||
以及「新建订单明细为空时仍能添加行」所依赖的 rowTpl 模板。
|
||||
|
||||
用法:python verify_exe.py 8080 [数据库路径]
|
||||
不传数据库路径时默认 po_app/dist/instance/po.db
|
||||
"""
|
||||
import os
|
||||
"""Read-only page/asset checks for a running packaged app; never writes order data."""
|
||||
import argparse
|
||||
import getpass
|
||||
import http.cookiejar
|
||||
import re
|
||||
import sqlite3
|
||||
import sys
|
||||
|
||||
import requests
|
||||
|
||||
BASE = "http://127.0.0.1:%s" % (sys.argv[1] if len(sys.argv) > 1 else "8080")
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
DB = sys.argv[2] if len(sys.argv) > 2 else os.path.join(
|
||||
os.path.dirname(HERE), "po_app", "dist", "instance", "po.db")
|
||||
|
||||
s = requests.Session()
|
||||
FAILS = []
|
||||
|
||||
|
||||
def check(label, cond, extra=""):
|
||||
print((" OK " if cond else " FAIL ") + label + (" " + str(extra) if extra else ""))
|
||||
if not cond:
|
||||
FAILS.append(label)
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
|
||||
def main():
|
||||
r = s.post(BASE + "/login", data={"username": "admin", "password": "admin123"})
|
||||
check("登录", r.status_code == 200, r.status_code)
|
||||
|
||||
# 注意:url_for() 会被 Jinja 渲染成实际路径,页面里不会出现函数名
|
||||
for path, marks in (
|
||||
("/materials", [u"批量导入 Excel", "matImpModal", "/materials/import_excel",
|
||||
"/materials/import_template.xlsx", "openEdit", "editModal",
|
||||
"/toggle", "/delete", u"停用", u"删除"]),
|
||||
("/suppliers", [u"批量导入 Excel", "supImpModal", "/suppliers/import_excel",
|
||||
"/suppliers/import_template.xlsx", "openEdit", "editModal",
|
||||
"/toggle", "/delete", u"停用", u"删除"]),
|
||||
):
|
||||
h = s.get(BASE + path).text
|
||||
missing = [m for m in marks if m not in h]
|
||||
check("%s 含导入/编辑/停用删除/置灰" % path, not missing, missing)
|
||||
|
||||
css = s.get(BASE + "/static/style.css").text
|
||||
check("style.css 含弹窗样式", "modal-mask" in css and "modal-box" in css)
|
||||
|
||||
for u in ("/materials/import_template.xlsx", "/suppliers/import_template.xlsx"):
|
||||
r = s.get(BASE + u)
|
||||
check("模板下载 %s" % u, r.status_code == 200 and len(r.content) > 3000,
|
||||
"%s bytes" % len(r.content))
|
||||
|
||||
# 新建订单:明细为空时必须仍能添加行(依赖 rowTpl 模板存在)
|
||||
r = s.post(BASE + "/orders/new", data={"doc_type": "purchase"})
|
||||
h = r.text
|
||||
no = ""
|
||||
m = re.search(r"PO\d{12}", h)
|
||||
if m:
|
||||
no = m.group(0)
|
||||
check("新建订单页含 rowTpl 明细行模板", 'id="rowTpl"' in h)
|
||||
tpl = re.search(r'<template id="rowTpl">(.*?)</template>', h, re.S)
|
||||
check("rowTpl 内含完整空行", bool(tpl) and 'name="item_code"' in tpl.group(1))
|
||||
|
||||
if no and os.path.exists(DB):
|
||||
con = sqlite3.connect(DB)
|
||||
cur = con.cursor()
|
||||
cur.execute("DELETE FROM order_items WHERE order_id IN "
|
||||
"(SELECT id FROM orders WHERE order_no=?)", (no,))
|
||||
cur.execute("DELETE FROM orders WHERE order_no=?", (no,))
|
||||
con.commit()
|
||||
con.close()
|
||||
print(" 已清理测试订单 %s" % no)
|
||||
|
||||
print("\n" + ("打包版冒烟全部通过" if not FAILS else "失败: " + "; ".join(FAILS)))
|
||||
parser=argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--url',default='http://127.0.0.1:8080')
|
||||
parser.add_argument('--username',required=True,help='Use an initialized admin account')
|
||||
args=parser.parse_args()
|
||||
base=args.url.rstrip('/')
|
||||
opener=urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
||||
def get(path):
|
||||
with opener.open(base+path,timeout=30) as response:
|
||||
return response.geturl(),response.read()
|
||||
_,body=get('/login')
|
||||
match=re.search(r'name="csrf_token" value="([^"]+)"',body.decode('utf-8'))
|
||||
if not match:
|
||||
raise SystemExit('Complete first-time setup before running this check.')
|
||||
fields={'username':args.username,'password':getpass.getpass('Password: '),'csrf_token':match[1]}
|
||||
with opener.open(urllib.request.Request(base+'/login',data=urllib.parse.urlencode(fields).encode()),timeout=30) as response:
|
||||
if response.geturl().rstrip('/') != base:
|
||||
raise SystemExit('Login failed or password change is required.')
|
||||
response.read()
|
||||
for path,marker in [('/orders/new',b'request_key'),('/users',b'username'),('/materials',b'matImpModal'),
|
||||
('/suppliers',b'supImpModal'),('/static/money.js',b'lineCents'),('/static/style.css',b'modal-mask')]:
|
||||
url,body=get(path)
|
||||
if url != base+path or marker not in body:
|
||||
raise SystemExit('Failed page/asset check: '+path)
|
||||
print('PASS',path)
|
||||
for path in ['/materials/import_template.xlsx','/suppliers/import_template.xlsx','/import_template.xlsx']:
|
||||
url,body=get(path)
|
||||
if url != base+path or not body.startswith(b'PK'):
|
||||
raise SystemExit('Failed workbook check: '+path)
|
||||
print('PASS',path)
|
||||
print('Packaged page/asset checks passed; order data was not modified.')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user