Files
bid-doctor/server/tests/fixtures/make_bid_fixtures.py
YANG JIANKUAN db1b1f6f9f feat(check): 规则检查(报价形式、形式要件、响应表),表格按单元格分行
- check/rules.py(规则集 2026.11-r1,不调模型):大小写金额、分项合计、超最高限价、
  多个报价、别的项目名称、没填的地方、落款日期、投标有效期、附加条件、响应表里的未响应;
  每条挂投标原文,有依据的挂招标侧出处;缺限价、截止时间、有效期要求时写进覆盖范围
- 文字层的句子带上单元格框,表格按单元格上沿分行
- 按 Fable 审读意见收紧致命级:认不准的降为重要或提示
- 评测:score.py 评规则问题;P07 注入记录改为空白处前后原文,剔除注入到人员表的 D10
- 上传页的检查范围文案同步

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:44:22 +08:00

60 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""生成查标测试用的虚构投标文件(对应 tender-mini.pdf 的三条 ★ 条款)。内容全部虚构。
cd server && ../.venv/bin/python tests/fixtures/make_bid_fixtures.py # 需要 Gotenberg(:3109)
- bid-mini-v1.pdf:响应了资质证书和服务器内存,漏了交换机硬件 BFD → 1 个致命问题「未找到响应」;
- bid-mini-v2.pdf:补上了交换机硬件 BFD → 复查时这个问题「本次已解决」;
- bid-mini-forms.pdf:v2 的内容 + 格式文件里的规则问题(大写和小写金额不一致、授权书没填投标人名称、
报价附加条件、另外给了一个优惠报价),措辞故意和评测集的开发词库不同。
"""
from __future__ import annotations
from pathlib import Path
import httpx
HERE = Path(__file__).parent
GOTENBERG = "http://127.0.0.1:3109/forms/chromium/convert/html"
HEAD = """<!doctype html><html><head><meta charset="utf-8"><style>
body { font-family: "Noto Serif CJK SC", "Noto Sans CJK SC", serif; font-size: 12pt; line-height: 1.8; margin: 0; }
h1 { font-size: 16pt; text-align: center; }
table { border-collapse: collapse; width: 100%; } td, th { border: 1pt solid #333; padding: 4pt; }
</style></head><body>"""
COMMON = [
"<h1>某市智慧政务系统集成项目投标文件(测试样例,内容虚构)</h1>",
"<p>投标人:某某信息技术有限公司(虚构单位,仅用于测试)。</p>",
"<p>一、项目理解。本投标文件是测试用的虚构样例,用于验证投标文件检查流程,内容不对应任何真实的投标人或采购项目。"
"我方已认真阅读采购文件的全部内容,愿意按采购文件的要求提供货物和服务。</p>",
"<p>二、资格证明。投标人须具备有效的信息系统集成服务资质证书:我公司具备有效的信息系统集成服务资质证书,"
"证书复印件见附件1。</p>",
"<p>三、技术响应。服务器内存不低于32GB的要求:我方服务器内存配置为64GB,并提供产品彩页作为证明材料,见附件2。</p>",
]
BFD = "<p>交换机支持硬件BFD,最小报文发送间隔不大于50毫秒的要求:我方交换机支持硬件BFD,最小报文发送间隔为3.3毫秒。</p>"
TAIL = ["<p>四、售后服务。我公司提供7×24小时售后服务,接到报修后2小时内响应。</p>", "</body></html>"]
def render(name: str, parts: list[str]) -> None:
html = HEAD + "".join(parts)
r = httpx.post(GOTENBERG, files={"files": ("index.html", html.encode(), "text/html")}, timeout=60)
r.raise_for_status()
(HERE / name).write_bytes(r.content)
print(name, len(r.content))
FORMS = [
"<p>五、法定代表人授权委托书。本人王某(姓名)系(投标人名称)的法定代表人,现授权李某为我方代理人。</p>",
"<p>六、开标一览表</p>",
"<table><tr><th>项目名称</th><th>投标总报价(元)</th><th>投标总报价(大写)</th></tr>"
"<tr><td>某市智慧政务系统集成项目</td><td>1,280,000.00</td><td>壹拾贰万捌仟元整</td></tr></table>",
"<p>让利后总价:1,250,000.00元。</p>",
"<p>七、本次报价未包含设备运输费用,运输费用由采购人另行承担。</p>",
]
if __name__ == "__main__":
render("bid-mini-v1.pdf", [*COMMON, *TAIL])
render("bid-mini-v2.pdf", [*COMMON, BFD, *TAIL])
render("bid-mini-forms.pdf", [*COMMON, BFD, *FORMS, *TAIL])