Skip to main content
Glama
mpq-quote

mpq-quote

by datu0108

原料报价系统

原料价格管理与原料核价的黑盒服务 —— 采购在后台改价,业务员填参数拿报价; 所有核价口径、原料单价、计算过程锁在服务端,AI 只能传参数进来、拿一个价格出去。

这份代码里没有任何公司的真实数据(先看这段)

这是一个通用模板:结构、机制、工程约定全部保留, 但任何公司的真实数字都不在里面 —— 这既是公开发布的前提, 也正好让它可以安全地被改造成你自己的系统。

你需要自己填的

在哪填

加工费、损耗率、关键词上浮、利润率

app/pricing/rules.py(模板已备好,见第七节)

原料价格表源表 xlsx

放自己的表进 price-tables/,再 python -m app.seed

域名、服务器、部署路径

换成你自己的

填口径之前服务起不来:rules.py 里 IS_DEMO = True 时,服务拒绝启动 (fail-closed),必须显式设 MPQ_ALLOW_DEMO_RULES=true 才放行。 理由:「示例值能算出一个报价」和「示例值是对的」之间差着一个真实的商业决策 —— 宁可启动失败,也不要拿示例数字当真报价发出去。


Related MCP server: Electronics RFQ Agent

一、为什么要做这个系统

把核价放在 AI 对话里完成的旧做法有两个结构性问题:

  1. 价格表是 Excel——采购改价必须靠人肉上传,AI 每次现读现查,改价无留痕、无版本。

  2. 核价在 AI 对话里完成——排版脚本只负责排版,公式是 AI 现场算的: 同一个面料两次算可能不一样,算错了没人查得出来,而且 AI 会把加工费、损耗率、原料单价全说出来。

这个系统把核价变成确定性黑盒服务:

层

谁能访问

能看到什么

MCP / AI 接口

任意 AI 客户端

只有最终报价 元/kg + MOQ 状态 + 需人工核实的提示。无任何原料单价,无任何计算步骤,无任何内部系数。

业务员 Web

内部业务员

最终价 + 原料 AA 单价/等级/匹配情况(沿用现有报价单口径),仍不含加工费、损耗率、利润率、成本。

审计明细

管理员本地

完整逐步计算过程(view=audit),不通过 MCP 暴露。

黑盒的实现方式(app/pricing/public.py):

  • MCP 的工具清单里不存在任何能返回价格表/规则的工具(没有 get_material_price、没有 list_materials);

  • 所有对外返回体走字段白名单序列化,assert_no_internal() 递归拦截内部字段,命中即抛错;

  • 错误信息同样过滤,不带内部数字;

  • MCP 令牌不对返回 403 而不是 401——401 会被部分 AI 客户端误判成"需要 OAuth 授权"而卡死。


二、快速开始

cd material-price-quote-system
./run.sh                      # 首次会自动建 venv、装依赖、导入价格表、建账号
# 打开 http://<服务器IP>:8000

或手动:

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python -m app.seed   # 导入 price-tables/ 里的价格表 + 建账号
.venv/bin/python -m uvicorn app.main:app --host 0.0.0.0 --port 8000

⚠️ 第一次启动会被拒绝,这是故意的

app/pricing/rules.py 里还是示例核价口径(IS_DEMO = True),服务会直接抛错退出:

app/pricing/rules.py 里仍是示例核价口径(IS_DEMO=True),已拒绝启动。

两条出路,选一条:

  1. (推荐)填自己的口径 —— 把 rules.py 里的 LOSS_RATE / BASE_FEE / 关键词上浮金额 / PROFIT_RATE / MOQ_UPLIFT 换成你的数字, 再把 IS_DEMO 改成 False。见第七节。

  2. (仅本地试玩)显式放行 —— export MPQ_ALLOW_DEMO_RULES=true。

为什么要这么较真:「示例值能算出一个报价」和「示例值是对的」之间, 差着一个真实的商业决策。宁可启动失败,也不要拿示例数字当真报价发出去。

想先空跑一遍看看?python ops/make_demo_price_table.py 会生成一份演示价格表 (编出来的假价格)放到 price-tables/,再 python -m app.seed 就能起一个有数据的实例。 但别拿它当真报价 —— 里面的加工费/损耗率/利润率也还是示例值。

初始账号

账号

角色

能做什么

admin

管理员

全部 + 审计明细(view=audit)

purchaser

采购

改价格、导入价格表、处理补价清单

sales

业务员

报价;看不到原料单价、看不到审计口径、不能改价

口令不写死在代码里,用环境变量给:

# .env
MPQ_ADMIN_PASSWORD=...
MPQ_PURCHASER_PASSWORD=...
MPQ_SALES_PASSWORD=...

# 生效(会重置已有账号的口令)
docker compose exec mpq python -m app.seed --users-only --reset-passwords

线上已用随机强口令,不再是 admin123 / sales123 这类默认值。 同时记得改 MPQ_SECRET_KEY 与两个 MCP 令牌。


三、数据从哪来

Excel 原料价格表是公司机密,不随包分发,也不放在 AI 工作目录里 (AI 随手就能读源表 = 黑盒失效)。它应该只待在核价机能碰到的目录里, 线上服务器 <部署目录>/price-tables/ 放一份。

安装到新机器时:把表拷进 material-price-quote-system/price-tables/,或用 MPQ_PRICE_TABLE_DIR 指向任意目录,然后 python -m app.seed。 导入器会扫目录里所有 .xlsx —— 不写死文件名(各家厂的表名都不一样, 写死就等于把供应商名单写进代码)。

已处理的三个数据坑:

  • 单位不一致:有的表是元/吨,有的是元/kg。导入器按价格列表头自动判断 (价格(元/吨) → ÷1000);表头没写单位时,按文件名里的「吨」字兜底。

  • 同键重复行:同一张表里可能有重复行(纤维+规格+说明+类别+工艺+等级 全同, 通常是旧表没删干净、新价追加在后面)。导入时保留最后一行, 所有变动写进 price_history,导入报告会明确列出,可人工复核。

  • 空价格:留空的行 = 待补价,会直接出现在"补价清单"里。

想先空跑一遍:python ops/make_demo_price_table.py 会生成一份演示价格表 (编出来的假价格)。


四、闭环:采购更新价格 → 业务员拿到报价

采购改价/导入Excel  →  materials 表(带 price_history 留痕)
                            ↓
业务员填成分/规格/织机/数量  →  匹配器找价格行
                            ↓
                  匹配到  →  核价引擎算  →  返回元/kg
                  匹配不到 →  自动登记到补价清单(price_requests)
                            ↓
采购在"补价清单"里填价  →  写回 materials  →  业务员立刻能用

匹配规则(app/pricing/matcher.py,对应原 pricing-rules.md 第 7 节):

  1. 纤维与类别必须相同——纤维不同(棉 vs 涤)直接判不匹配,必须人工问价;

  2. 工艺尽量相同(带同义词:精梳紧赛↔紧赛↔紧密赛络纺);

  3. 支数/D 数最接近;

  4. 距离相同时取价高的一档,避免低报;

  5. 裸纤维查询(如业务员只说"涤纶")会锁定主流品种——数据驱动:同核心纤维下行数 ≥ 第二名 2 倍即认定为主流 (涤纶半光 80 行 vs 涤纶消光 30 行 → 半光)。这条规则避免"涤纶 75D DTY"被匹配到 涤纶H400(30.0 元/kg)而不是 涤纶半光(10.0 元/kg)——差 3 倍,会直接亏钱;

  6. 同一规格有多个版本(国产/兰精LF、兰精/博拉、原棉/高配)且业务没指定 → 标记为近似匹配并写明取了哪一档。

规格缺失 / 规格表里没有 时的兜底(2026-10-22 线上事故后加的,见下):

第 4 条「距离相同时取价高」的前提是有距离可比。下面两种情况没有距离可言, 硬套第 4 条会直接落到该纤维最贵的一行,系统性高报:

场景

旧行为

现在

没给支数(AI 只传了 process)

棉 → 60S 30.0 → 40.0(正确 32.0,高报 25%)

锁该纤维最常用规格(棉 40S)核价,标注"未指定规格,此价须人工核实"

给了支数但价格表里没有(99S)

棉 → 60S 30.0 → 42.0(高报 31%)

同样锁主流规格,标注"价格表里没有 99S 这一档支数/D数"

兜底时不再叠「取价高」(估算值再放大一次高报),而是取最接近该组中位价的那一行。 兜底单子不进补价清单(缺的是规格信息不是价格,采购也不知道该补哪一档), 改为在 MCP 返回的「提示」里明确写出按哪一档估的,必须由采购/核价员核对后才能对外报价。

另外两条防坑:

  • 规格回填:AI 常把支数写在面料名里("32S全棉精梳汗布")却没填 spec 字段。 系统会从面料名/需求原话里把支数捞回来再匹配(只有一种原料时才回填,避免把棉的 40S 套到氨纶 40D 上)。 实测:回填后那张单从 40.0 变回 32.0。

  • 参数不完整 ≠ 价格缺失:没给纤维、类别填反这类错误会明确报「参数不完整」, 不会登记进补价清单、不会编一个价格。类别填反时系统会自动纠正并告知(棉被当长丝类 → 纠正为短纤类)。


五、管理后台(采购 / 老板)

https://quote.example.com/admin.html —— 只有采购和管理员能进, 业务员访问会被挡下(接口层同样 403,不是只在前端藏)。

标签页

给谁

干什么

概览

老板

原料总数/有价/待补价/待处理补价单/报价单数/近 7 天改价数/价格表更新至 + 分类别待补价占比 + 最近一次改价

原料更新

采购

改价(改过的行标黄,可一次批量提交)、清空价格转待补价、改价格日期、导入 Excel

补价流程

采购

待补价 → 填价生效 / 忽略 / 重新打开;价格表空价行也一并列出

变更记录

采购 / 老板

价格变更流水:谁、何时、哪个原料、旧价 → 新价、涨跌幅、来源文件。这就是"流程更新"的留痕

报价记录

老板

所有经系统核价的报价留档(单号/客户/布名/织机/数量/报价/是否低于 MOQ/业务员/时间)

核价口径

仅管理员

等级系数、损耗率、各织机加工费、关键词上浮、工艺别名、MOQ 与上浮规则 —— 机密,仅老板可见

新增接口(都在 app/api/admin.py):

方法

路径

权限

GET

/api/admin/stats

采购 / 管理员

GET

/api/price-history

采购 / 管理员

POST

/api/materials/batch-update

采购 / 管理员

PATCH

/api/price-requests/{id}/status

采购 / 管理员

GET

/api/admin/rules

仅管理员

批量改价与单条改价一样,每一行都写 price_history 留痕。 「核价口径」里的加工费/损耗率/利润系数只在这个页出现,绝不进任何对外返回体。


六、接给 AI 用(MCP)

端点

https://quote.example.com/mcp
Authorization: Bearer <令牌>

支持 Streamable HTTP(Accio Work 等填 URL 的客户端)与 stdio(Claude Desktop 等本地客户端)。

两种令牌:管理员 / 业务员

令牌与角色一一对应,可以单独吊销,互不影响。

令牌

环境变量

角色

能拿到什么

管理员

MPQ_MCP_TOKEN

admin

默认黑盒;可显式传 view=business 拿含 AA 单价的业务口径(内部核对用),list_material_options 给 400 条

业务员

MPQ_MCP_TOKEN_SALES

sales

只有最终报价。传 view=business 会被降级并明确告知;词表只给 200 条

业务员令牌永远拿不到原料单价,无论怎么构造参数。 令牌不对一律返回 403(不是 401 —— 401 会让部分 AI 客户端误判为"需要 OAuth 授权"而卡死)。

换令牌只要改服务器 .env 再 docker compose restart:

# 重新生成业务员令牌
python3 -c "import secrets;print(secrets.token_urlsafe(32))"
# 写进 .env 后
docker compose up -d

工具清单

工具

作用

返回

quote_material_price

核价

只有最终报价 + 提示

list_machines

可选织机与常用布种

织机名、常用布种(无费用)

list_material_options

原料规格词表

纤维/规格/工艺(无价格)

list_material_options 返回的条目字段名与 quote_material_price 的 materials 入参完全一致 (fiber / spec / process / desc / alias),AI 可以原样照抄进 materials 数组。 早期版本返回中文键(纤维 / 支数或D数 / …),而工具入参是英文键, Pydantic 默认 extra="ignore" 会静默丢弃中文键 → materials 项全空 → 核价直接失败 (线上真实事故:AI 照抄词表后报错,业务被误导去"采购补价",而价格表里明明有)。 现在词表输出英文键,同时 MaterialInput 也接受中文键别名,两边怎么写都能用。

list_material_options 可以在环境变量里关掉(MPQ_MCP_EXPOSE_SPEC_VOCABULARY=false), 关掉后 AI 只能凭业务员的说法尝试匹配,命中率会下降。

调用示例

{
  "jsonrpc": "2.0", "id": 1, "method": "tools/call",
  "params": {
    "name": "quote_material_price",
    "arguments": {
      "raw_requirement": "32S全棉精梳汗布,3000公斤",
      "materials": [
        {"fiber": "全棉", "category": "短纤类", "spec": "32S", "desc": "精梳", "grade": "AA", "ratio": 1.0}
      ],
      "machine": "单面圆纬机",
      "quantity_value": 3000, "quantity_unit": "kg",
      "fabric_name": "全棉汗布", "customer": "XX客户"
    }
  }
}

raw_requirement 务必原样传入业务员的原话 —— 系统据此判断品质等级/工艺这些参数 是业务员明确说的,还是 AI 自己补的(补的会在"提示"里要求人工确认)。

返回:

{
  "报价单号": "MQ20261022-0001",
  "初步报价_元每kg": 30.0,
  "报价口径": "人民币元/kg,含税;不含运费、包装费;面料价(不含染色印花等后整理)",
  "报价基准": "按 MOQ 报价",
  "提示": [],
  "折算重量_kg": 3000.0,
  "原料价格更新至": "2026-10-17"
}

匹配不到价格时返回 {"成功": false, "错误": "...已登记到补价清单..."},不会编一个价格出来。 参数不全(例如没给支数/D数)时返回"请补充规格后再报价",不会登记进补价清单 —— 参数没给全是业务员的事,不是采购的补价待办。

客户端配置

Accio Work(填 URL + 请求头):

URL:    https://quote.example.com/mcp
Header: Authorization: Bearer <MPQ_MCP_TOKEN_SALES>

Claude Desktop(claude_desktop_config.json):

{
  "mcpServers": {
    "mpq-quote": {
      "command": "/绝对路径/material-price-quote-system/.venv/bin/python",
      "args": ["-m", "app.mcp_server"],
      "cwd": "/绝对路径/material-price-quote-system",
      "env": { "MPQ_MCP_TRANSPORT": "stdio" }
    }
  }
}

七、核价口径(内部,勿外传)

以下内容属于公司内部定价机密,不通过任何对外接口返回。本文档仅供系统维护者查阅。

⚠️ 下面给的是示例值(对应 app/pricing/rules.py 里的 IS_DEMO = True)。 必须换成你自己的数字 —— 加工费、损耗率、上浮金额、利润率都是商业机密, 开源版只能给结构和占位数字。

公式(每 kg,人民币,含税):

等级调整后单价 P = AA单价 × 等级系数        A=0.95  AA=1.00  AAA=1.05  AAAA=1.10
原料成本   = Σ(占比 × P)
织造损耗   = Σ(占比 × P × 损耗率)           短纤类 5%   长丝类 3%        ← 示例值
加工费     = 基础加工费(织机, 场景) + Σ关键词上浮                        ← 示例值
报价成本   = 原料成本 + 织造损耗 + 加工费
MOQ 报价   = 报价成本 × 1.10,向上进位到 1 位小数                      ← 示例值
低于 MOQ   = MOQ 报价 × 1.02,再向上进位     (MOQ = 2000kg)            ← 示例值
  • 场景:含任意短纤类原料 → "带短纤"加工费表与关键词表;全部长丝 → "全长丝"表。

  • 加工费、损耗率、关键词上浮金额、利润率:禁止出现在任何对外返回体。

  • 数量为米/码时必须给全幅(cm)与 GSM;1 码 = 0.9144 米;每kg米数 = 1000 ÷ (GSM × 全幅米)。

  • 数量不明按 MOQ 报价。

  • 对外统一说法必须和算法一致:示例是「MOQ 2000kg,低于 2000kg 在 MOQ 报价基础上上调 2%」—— 业务员嘴上说的和系统算出来的如果不是一回事,扯皮的就是你。

改口径的四处(都在 app/pricing/rules.py): LOSS_RATE / BASE_FEE / SPUN_KW·FIL_KW 里的金额 / PROFIT_RATE·MOQ_UPLIFT。 改完把 IS_DEMO 改成 False,服务才会正常启动。

这套口径有两套独立实现互相对照:tests/test_engine.py 里另写了一份按公式重推的参考实现, 逐项和 engine.compute_quote() 比对(覆盖短纤/长丝/低于MOQ/米码换算/关键词叠加/等级调整/数量未知/面料名命中), 两边不一致就红。


八、REST API

方法

路径

说明

权限

POST

/api/auth/login /logout,GET /api/auth/me

登录态

—

GET

/api/materials

价格表(分页/筛选)

登录

PATCH

/api/materials/{id}

改价格(留痕)

采购/管理员

GET

/api/materials

原料价格表

登录(业务员看不到 price 值)

POST

/api/materials/import

导入 Excel

采购/管理员

GET

/api/materials/vocabulary

规格词表(无价格)

登录

GET

/api/price-requests

补价清单(业务员看不到 price 值)

登录

POST

/api/price-requests/{id}/fill

补价

采购/管理员

POST

/api/quotes/price

试算(view = business/ai/audit)

登录

POST

/api/quotes

报价并存档

登录

GET

/api/quotes

报价历史

登录

view=ai 的返回与 MCP 完全一致;view=audit 含完整计算过程,仅管理员可见 (业务员伪造 view=audit 直接 403)。

业务员默认看不到任何单价(MPQ_SALES_CAN_SEE_PRICE=true 可打开)。 价格表里凡是自由文本(匹配说明、补价备注、错误信息)在返回给业务员前都会过一遍 scrub_prices() 清洗,防止价格数字混在说明文字里漏出去。

交互式文档:http://<服务器IP>:8000/api/docs


九、部署

示例部署:Docker Compose + Nginx 反代 + Let's Encrypt 证书。下面是一套可直接照抄的骨架, 路径和域名请换成你自己的。

服务器上的目录结构

/opt/material-price-quote-system/          应用目录
├── app/  web/  tests/  price-tables/
├── .env                            权限 600,密钥在服务器本地生成
├── data/mpq.db                    SQLite(volume 挂载到容器 /app/data)
├── Dockerfile  docker-compose.yml
/etc/letsencrypt/live/<你的域名>/        证书(certbot 自动续期)
/etc/nginx/conf.d/<你的域名>.conf         nginx vhost
/var/www/<你的域名>/.well-known/acme-challenge/   证书签发 webroot(权限必须 755,否则 403)

price-tables/ 里的源表不进镜像(.dockerignore 已排除),运行时只读 bind mount 挂进容器。 验证方法见 AGENTS.md「机密源表怎么验证它真的没进镜像」。

常用操作

cd /opt/material-price-quote-system

docker compose ps                      # 状态
docker compose logs -f --tail 100      # 日志
docker compose restart                 # 重启
docker compose up -d --build           # 改完代码后重新部署
docker compose exec mpq python -m app.seed --users-only   # 只建账号
docker compose exec mpq python -m app.seed               # 重导价格表 + 建账号

为什么用 Docker

本项目需要 Python 3.10+(X | None 注解 + pydantic 2 + MCP SDK 2),很多机器的系统 Python 还停在 3.8, 所以用 python:3.12-slim 容器。国内拉不动 Docker Hub 时把基础镜像换成国内加速前缀, pip 也换成国内源(见 Dockerfile,那里已写成标准源 + 注释说明怎么换)。

容器内存限制 400MB(mem_limit + memswap_limit):这台机器上往往还跑着别的东西 (比如数据库常驻几百 MB),不给容器设上限,它被挤爆时会连坐把整台机的内存吃光。 超了只杀自己,不拖累邻居。

实测过的一个坑:宿主机 1.9G 内存 + mysqld 常驻 470M,容器不限内存时跑着跑着 整机被 OOM killer 干掉,MySQL 先死。容器一定要设内存上限。

换到其他服务器

# 1. 上传代码
cd /opt/material-price-quote-system
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt

# 2. 配 .env(密钥自己生成,别用示例值)
cat > .env <<'EOF'
MPQ_DB_URL=sqlite:////app/data/mpq.db
MPQ_SECRET_KEY=<随机长串>
MPQ_MCP_TOKEN=<随机长串>
MPQ_MCP_ENABLED=true
MPQ_MCP_EXPOSE_SPEC_VOCABULARY=true
MPQ_PRICE_TABLE_DIR=/opt/material-price-quote-system/price-tables
EOF
chmod 600 .env

# 3. 初始化并启动
.venv/bin/python -m app.seed
docker compose up -d --build

# 4. nginx + 证书
mkdir -p /var/www/<你的域名>/.well-known/acme-challenge
chmod 755 /var/www/<你的域名> /var/www/<你的域名>/.well-known
chown -R www-data:www-data /var/www/<你的域名>
# 先写一个只监听 80 的 vhost,certbot --webroot 签完再换成 HTTPS
certbot certonly --webroot -w /var/www/<你的域名> -d <你的域名> \
  --register-unsafely-without-email --agree-tos --non-interactive

nginx vhost 见 deploy/quote.example.com.conf(本仓库内),要点:

  • / 反代到 127.0.0.1:8010;

  • /mcp 必须单独一个 location:proxy_buffering off + proxy_read_timeout 3600s, 否则 SSE 响应会被缓冲,AI 客户端会卡住;

  • 容器只绑 127.0.0.1,对外只暴露 443,避免绕过 TLS。

换成 MySQL

.venv/bin/pip install pymysql
# .env 里改成
MPQ_DB_URL=mysql+pymysql://mpq:密码@127.0.0.1:3306/mpq?charset=utf8mb4

宿主机上已有 mysqld(3306)时,不要给本系统单独起一个 MySQL 容器 —— 两个 MySQL 抢内存是最容易把自己搞挂的方式。

已做的安全收口

项

做法

OpenAPI 文档

默认关闭(MPQ_ENABLE_API_DOCS=true 才开),避免暴露接口结构

登录爆破

同 IP 10 分钟内失败 8 次即 429

账号枚举

用户不存在与密码错误返回同一个提示

MCP 令牌不对

返回 403(不是 401),避免 AI 客户端误判为需要 OAuth

令牌分级

管理员 / 业务员两个独立令牌,业务员令牌永远拿不到单价,可单独吊销

REST 审计口径

view=audit 仅管理员,非管理员伪造即 403

价格表读取

业务员拉全量价格表拿不到 price 值,只拿 has_price 布尔

自由文本

说明/备注/错误信息返回给业务员前过 scrub_prices() 清洗价格数字

管理后台

/admin.html 与 /api/admin/* 只对采购/管理员开放,业务员一律 403

核价口径

加工费/损耗率/利润系数只在 /api/admin/rules(仅管理员)出现,不进任何对外返回体

静态文件

/.env、/app/*.py、未知路径全部 404

业务接口

未登录一律 401

证书

Let's Encrypt,certbot 自动续期,续期后自动 reload nginx(见 deploy/renewal-hook.sh)

容器

mem_limit 400m、restart: unless-stopped

十、测试

测试分两层:零依赖的(全新克隆就能跑)和需要自建环境的。

第一层:零依赖,开箱即跑

.venv/bin/python -m tests.test_engine     # 引擎口径 vs 测试内的独立参考实现,逐项比对 + 黑盒泄露检测
.venv/bin/python -m tests.test_matcher    # 匹配器回归:合成价格表 + 业务问法钉死命中行

第二层:需要先起服务 / 需要凭据

.venv/bin/python -m uvicorn app.main:app --host 127.0.0.1 --port 8077 &
.venv/bin/python -m tests.test_e2e         # REST + MCP 端到端(含泄露检测、权限边界)

这一层会连真实服务、可能改数据,口令和令牌必须用环境变量传 (MPQ_ADMIN_PASSWORD / MPQ_MCP_TOKEN / E2E_BASE_URL …), 完整清单见 AGENTS.md 的「测试」一节。


十一、目录结构

material-price-quote-system/
├── app/
│   ├── main.py              # 单进程:REST + Web + MCP(含示例口径 fail-closed 护栏)
│   ├── mcp_server.py        # MCP 工具定义(对外唯一出口)
│   ├── config.py  db.py  models.py  security.py
│   ├── pricing/
│   │   ├── rules.py         # ★机密:加工费/损耗/上浮/利润率(模板,默认是示例值)
│   │   ├── engine.py        # 核价引擎
│   │   ├── matcher.py       # 原料价格匹配器
│   │   └── public.py        # ★黑盒网关:三种可见级别的白名单输出
│   ├── services/
│   │   ├── importer.py      # Excel 导入(单位换算 + 去重 + 留痕)
│   │   └── quote_service.py # 报价编排 + 补价登记
│   └── api/                 # auth / materials / quotes / admin(管理后台)
├── web/                     # 零依赖原生 JS,不引 CDN
│   ├── index.html           # 报价计算器
│   ├── materials.html       # 价格表管理 + 补价清单
│   ├── admin.html           # 管理后台(采购/老板):原料更新·补价流程·变更记录·报价记录·核价口径
│   ├── common.js  app.css
├── price-tables/            # 放你自己的原料价格表(不随包分发,见第三节)
├── ops/                     # 备份 / 令牌取用 / 权限收口 / 演示价格表生成器
├── deploy/                  # nginx vhost 示例 + 证书续期 hook
├── tests/                   # 见第十节
├── data/mpq.db              # SQLite(生产换 MySQL)
├── run.sh  requirements.txt  .env.example

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Intelligently generates cost estimates and lead times for manufacturing RFPs by parsing requests, matching against historical quotes, and calculating activity-based costs with confidence scoring and human approval workflows.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI clients to compute auditable vehicle export quotes with consistent decimal rules, including request normalization, funder screening, validation, comparison, and MOSS export.
    MIT