01 / 核查结论:目前不含公式
现有实现将每个单元格转换为字符串,并明确设置为文本类型。导出的收入、成本和毛利贡献是结果快照,没有可重算公式,也没有完整的行列字典和操作说明。
| 核查对象 | 已存在的行为 | 与目标的差距 |
|---|---|---|
finance/views.py · export() | 一张“证据明细”;前四行含版本 SHA、筛选上下文、ROI 口径、导出时间;所有值写为文本。 | 没有公式计算层、汇总报表或说明页。 |
tests/test_finance.py · test_excel_export_precision_and_formula_safety | 明确断言所有单元格都不是公式,验证高精度金额及注入保护。 | 只能证明证据快照行为正确,不能证明公式导出正确。 |
frontend/src/dialogs.tsx · EvidenceDialog | 选择 XLSX 下载证据明细。 | 没有公式版选择、兼容性说明、精度提示或异步状态。 |
| 规模与参考附件 | 现有单次导出上限 100,000 行;附件共有 332,830 行。 | 不能通过现有接口一次导出原附件全部明细。 |
已运行的两项针对性测试:test_excel_export_precision_and_formula_safety、test_xlsx_double_header_and_lookup,结果 2 passed(1.59 秒)。后者验证导入双表头与毛利率匹配,不是 Excel 公式重算测试。
保留金额文本并非无意义限制:系统使用高精度 Decimal,而 Excel 普通数值只有约 15 位有效数字。新方案必须保留证据精度,不能直接把所有字符串改成浮点数。
02 / 设计选择与推荐
| 决策 | 选项与代价 | 推荐 |
|---|---|---|
| 导出模式 | A. 替换现有证据导出,破坏旧语义。 B. 保留证据快照,新增公式工作簿。 | B。界面清楚区分“证据快照”和“公式分析工作簿”;CSV 始终是快照,不承诺公式。 |
| 精度 | A. 全部按 Excel 浮点数,丢失高精度证据。 B. 精确文本证据 + 数值计算层 + Decimal 对账。 C. 宏或自定义高精度插件,兼容、部署及安全成本高。 | B。明确公式值遵守批准后的精度政策,不声称原生公式保持 24 位小数精确运算。 |
| 公式兼容性 | A. Microsoft 365,支持动态数组去重。 B. 旧版 Excel / WPS / LibreOffice,需另做兼容实现及验证。 | 先以 Microsoft 365 桌面 Windows / Mac 为明确验收目标;网页版另测。其他引擎通过验证后再声明支持,不能以应用跨平台替代工作簿兼容性。 |
| 人数计算 | A. UNIQUE/FILTER 真正按范围去重。 B. 服务端预制去重辅助表,修改客户或分组后可能失效。 C. 每行 COUNTIFS 扫全表,规模大时开销很高。 | 公式版选 A,限定报表分组数量并压测;B 仅作明确只读的兼容快照,不能冒充完全可重算。避免 C。 |
| 生成与重算 | A. 现有 openpyxl 写公式,打开 Excel 时重算。 B. 导出后由经验证的受控引擎重算并保存缓存。 C. 添加写缓存库,但缓存仍是服务器结果。 | 第一阶段 A + 真实 Excel 验收;首次打开前预览可能空白,必须告知。若业务要求下载即带可信缓存,则 B 是上线前置条件;不把 C 当作重算证明。 |
| 编辑能力 | A. 任意插行、改维度和期间并自动重建全部报表。 B. 固定导出范围,允许指定输入修改,结构性变化重新导出。 | 首版 B,边界容易验证;完整可变结构作为后续独立需求,不暗示已经支持。 |
| 大文件 | A. 同步放宽现有上限。 B. 数据库任务 + 独立 worker + 私有文件下载。 | 全量附件采用 B;复用项目已有任务处理模式,不预先引入新的消息队列。 |
03 / 工作簿结构与行列说明
输出放在前面,输入和证据放在后面。仅创建实际需要的页,不按每个指标拆页。所有名称均为规划,尚未实现。
| 工作表 | 行与列的含义 | 内容与用途 |
|---|---|---|
| 分析汇总 | 每行一个指标或已选维度分组;列为本期、基期、差额、变化率、单位、可用状态。 | 汇总金额、去重人数、比率由明细或计算结果引用产生;非加法指标不合计子组值。页首注明范围、期间、版本及模拟状态。 |
| 使用说明 | 按主题分行:范围、粒度、字段、公式、操作、限制。 | 字典列包括名称、业务含义、数据类型、单位、来源字段、可否修改、空值含义、公式与示例;另附版本、时区和支持的 Excel 版本。 |
| 参数与口径 | 每行一个参数或产品毛利率;列为当前值、含义、来源、是否可改。 | 收入映射、ROI 分支、自营产品集合、毛利率、精度政策;首版期间及筛选锁定。允许的模拟参数必须明确标识。 |
| 计算明细 | 一行对应一个导入后的 Fact,保留来源定位键;不是一位客户或一次就诊。 | 期间、维度、去标识客户 token、基础数值、原价、毛利来源、适用毛利率、毛利公式、缺失标志等;Excel Table 管理引用范围。 |
| 原始证据 | 与计算明细一一对应;金额和标识保留精确文本。 | 授权范围内的来源行、字段映射及原值;不可把完整患者原始信息无差别复制出去。工作表保护只防误操作,不是加密或权限控制。 |
| 对账检查 | 每行一个指标及范围;列为服务器精确文本、批准精度的参考数值、公式结果、差异、阈值和检查状态。 | 包含行数、缺失数、总分一致性、公式覆盖与精度警告;此页仅观察结果,不反向驱动业务公式。 |
说明页必须回答的问题
- 本文件覆盖哪个数据版本、期间、组织及筛选?这是授权范围快照,不代表整院所有数据。
- 金额单位是什么?百分比以小数储存;升单率变化“百分点”与相对变化率分列,不混用。
- 收入、实收、原价、毛利贡献分别指什么?毛利贡献不是净利润,ROI 成本的定义必须写明。
- 哪些单元格可改?颜色之外同时提供文字标签、批注和数据验证;公式格保护防止误覆盖。
- 如何启用自动计算、重新计算和查看公式?不需要启用宏,不连接外部数据,不回写业务系统。
- 空值、0、不可用、缺期和超精度分别是什么意思?遇到不支持函数时不要把错误当成 0。
- 修改后如何核对?本地修改是模拟结果,服务器原始快照及其 SHA 不因此变成修改后内容的认证。
04 / 公式契约:每个衍生结果可追溯
基础事实可以是输入常量;新增衍生金额、计数、比率和差异必须来自真正的公式依赖。禁止用 =12345 或引用隐藏的静态答案来伪装计算。建立“指标 → 输入 → 公式 → 单位 → 缺失策略 → 测试”的显式清单。
| 指标 | 计算定义 | 边界与验收重点 |
|---|---|---|
| 收入 / 成本 / 原价 | 在指定范围汇总对应基础字段。 | 有数据但全为 0 与无数据不同;成本或原价部分缺失时依赖指标不可用,不能只合计非空项。 |
| 毛利贡献 | 原始毛利有值时使用该输入;否则收入 × 已匹配产品毛利率;汇总逐行结果。 | 必须恢复并记录 direct / lookup / missing 来源。Fact.gross 已是结果,不能直接把它当作原始毛利来伪造推导。必要时从保留的 raw 与映射提取,先做一致性测试。 |
| ROI | profit_over_cost:(收入 − 成本) / 成本;gross_less_cost_over_cost:(毛利贡献 − 成本) / 成本。 | 遵从数据版本映射;成本 ≤ 0 或任何必要字段缺失时不可用。 |
| 消费人数 / 客单价 | 范围内客户 token 去重计数;收入 / 消费人数。 | 跨月、跨产品、跨科室重复客户只计一次;有任一缺失客户时与现有后端口径一致地不可用。 |
| 毛利率 / 产品扣率 | 毛利贡献 / 收入;收入 / 原价金额。 | 先汇总再相除,不能平均行级比率;分母必须大于 0;不把扣率解释为“1 − 比值”。 |
| 自营收入 / 升单率 | 配置自营产品范围内收入;该范围客户去重数 / 全部客户去重数。 | 产品集合未配置时不可用;不能以自营收入占比替代升单率。 |
| 原价客单价 | 原价金额 / 去重人数。 | 原价或客户缺失时不可用。 |
| 差额 / 变化率 | 本期 − 基期;差额 / ABS(基期)。 | 基期 0 不计算变化率;缺期不比较;比率指标同时注明差额单位。 |
| 贡献率 | 子组金额差额 / 父组金额差额。 | 仅收入、成本、毛利、自营收入等可加指标;父级差额 0 不计算,不为人数或比率伪造加法贡献。 |
公式示例与生成规则
下列为设计样例。Data 表名、英文列名和命名范围须由模板定义,不能让用户字符串直接拼入公式;状态判断在拥有该指标的计算层生成。公式使用英文函数名和 OOXML 语法,实际写入动态数组需要验证序列化及兼容前缀。
收入(已确认该期间有记录):
=SUMIFS(Data[Revenue],Data[Period],CurrentPeriod)
成本完整性检查后计算 ROI:
=IF(CostStatus<>"OK",NA(),IF(Cost<=0,NA(),(Revenue-Cost)/Cost))
变化率(先确认本期与基期可比较):
=IF(Comparable=0,NA(),IF(BaselineValue=0,NA(),
(CurrentValue-BaselineValue)/ABS(BaselineValue)))
365 去重人数(先确认范围有记录,且该范围客户字段完整):
=IF(CustomerStatus<>"OK",NA(),
ROWS(UNIQUE(FILTER(Data[CustomerToken],Data[Period]=CurrentPeriod))))
毛利计算分支:
=IF([@GrossSource]="direct",[@GrossInput],
IF([@RateStatus]="OK",[@Revenue]*[@MarginRate],NA()))多月、多维度条件需生成对应掩码;上述单月例子不能直接替代完整上下文。全量、大量分组不允许每个明细行扫描全表。公式构建须限制报告维度及单元格数量。
缺失表达推荐:计算层用预期的 NA() 阻止错误结果传播;输出页用配套状态显示“不可用:缺成本”等原因。只对已知状态做展示转换,不用 IFERROR(...,0) 吞掉真实公式错误。
05 / 精度与财务对账
“显示两位小数”不是“计算只用两位小数”。原附件有 11,990 行收入超过四位小数,不能在导出时静默按行截断。
- 证据层:保留 Decimal 原始字符串及来源映射;不经 JavaScript Number 中转。完整金额不可因导出而发生舍入。
- 计算层:先检测有效数字、数量级和累计误差风险,再转换 Excel 数值。把转换策略、舍入位数、舍入模式和发生时点写入文件。
- 推荐默认:分析公式不逐行强制 ROUND;展示金额两位,最终财务比较按批准的规则舍入。若业务要求“每行先舍入再汇总”,另设明确版本口径,不能混用。
- 两套参照:Decimal 对原始业务口径的精确结果用于证据核验;按相同批准数值政策得到的参考结果用于 Excel 计算对账。区别“政策导致的差异”与“实现错误”。
- 误差门槛:逐项规定金额绝对误差、比率误差及人数严格相等。建议金额以最终批准币种最小单位一致为目标;具体阈值必须经真实样本和财务确认,不能先放宽到让测试通过。
- 边界处理:超过可接受数值范围、舍入临界点或差异超阈值时阻止宣称“精确一致”,给出可定位的警告或拒绝公式版,证据版仍保留。
不推荐启用 Excel“以显示精度为准”,因为它会改变存储值。原生数值公式不能承诺任意 24 位小数精确运算;若确有此硬要求,应保留服务端 Decimal 为权威计算引擎,并另行评估高精度插件,不在首版隐式引入宏。
06 / 修改后究竟会重算什么
| 操作 | 首版承诺 | 限制 |
|---|---|---|
| 修改允许编辑的收入、成本、原价、直接毛利 | 行级毛利、汇总、比率、差额及对账随公式重算。 | 原始证据不变;明确标记为本地模拟,不回写服务器。 |
| 修改已有产品的毛利率 | 仅 lookup 来源行重算;direct 来源行不受影响。 | 不自动新增产品,不静默替换原始毛利。 |
| 筛选或隐藏明细行 | 默认仅改变可见行,不改变汇总范围。 | 明确 SUMIFS 不随 AutoFilter 改变;若未来要“仅可见行汇总”,作为独立模式实现及测试。 |
| 改变期间、维度、客户、产品集合,追加或删除行 | 首版不承诺;从系统重新选择范围并导出。 | Table 能扩展不等于分组报表、去重及状态范围全部正确扩展;锁定结构以防误解。 |
| 修改公式 | 默认保护防误操作;允许授权副本解除保护后自行分析。 | 解除保护后的结果不属于系统验证范围;工作表保护不是安全边界。 |
源事实 ID 或稳定行键只用于追溯;本地模拟状态可通过可编辑输入与导出初值比较生成。任何数据版本 SHA 都只标识服务器来源,不能认证已被本地修改的文件。
07 / 安全、权限与 33 万行性能
可信公式与不可信内容严格分离
- 公式只由受控模板生成;原始文本、列名、维度标签保持文本类型。保留并扩展当前 =、+、-、@、制表符及换行注入测试。
- 无 VBA、DDE、外部工作簿链接或未经允许的 HYPERLINK;扫描 OOXML 关系和公式,不只检查文件扩展名。
- 客户去重使用工作簿内稳定的去标识 token。推荐每次导出独立密钥 HMAC,在所有页统一使用,密钥不写入文件;仍按敏感数据管理,不能称为不可逆匿名化。
- 申请、执行、下载三个阶段复核组织和科室权限;执行快照只包含授权行,下载前权限被撤销必须拒绝。原始证据页也不能绕过字段权限。
- 下载文件私有存储、短期保留、自动清理;审计记录版本、范围、模式、公式版本、结果及文件哈希,不记录患者原值。
任务化导出
保留旧同步证据入口的行为;新增公式版任务状态:queued → running → succeeded / failed / expired。请求校验后冻结数据版本、映射、筛选、权限范围、参数和公式版本。worker 用分块迭代处理,临时文件原子完成后才发布;支持超时、失败重试、去重请求、崩溃恢复和过期清理。
真实附件 332,830 行未超过 Excel 单表 1,048,576 行的限制,但当前接口的 100,000 行限制仍然存在。完整公式版必须另做容量评估,超过支持范围应显式拒绝或提示缩小范围,不能悄悄截断。
性能基准至少覆盖 1,000 / 100,000 / 332,830 行,测导出耗时、峰值内存、文件大小、首次打开、改值重算、并发排队。记录设备、Excel 版本和数据分组基数;本轮不虚构 SLA。高基数分组达到预算时提示缩小报表范围,不降级为静态结果却仍标“公式版”。
08 / 文件级实施步骤
| 阶段 | 工作与目标文件 | 完成条件 / 依赖 |
|---|---|---|
| P0 · 口径冻结 估计 1–2 人日 | 复核 finance/analysis.py、finance/importing.py 与原附件;定义精度政策、公式清单、编辑边界及兼容矩阵;确认毛利来源恢复。 | 财务确认收入 N / 实收 I、原价、退款、自营产品、成本与 ROI;否则不可冻结黄金结果。 |
| P1 · 最小公式工作簿 估计 2–4 人日 | 新增 finance/exporting.py 集中生成模板、状态和公式;复用现有分析口径,不引入通用公式 DSL。先实现小样本汇总、明细、参数、说明和对账。 | 每个衍生单元格可追溯;输入/公式/文本写入类型分离;小样本真实 Excel 重算通过。 |
| P2 · 精度与隐私 估计 1–2 人日 | 同模块实现精确文本、数值转换预检、毛利来源、客户 token、来源定位和注入防护;增加针对性单元测试。 | Decimal 对账、去重、缺失、恶意文本及越权用例通过;不破坏证据版。 |
| P3 · 任务与 API 估计 2–3 人日 | 在 finance/models.py 增加必要的导出任务与迁移;在 finance/views.py 及现有 URL 配置增加提交/查询/下载入口;新增导出 worker 命令,复用导入 worker 的部署模式。 | 完整附件能异步生成;崩溃恢复、重试、权限撤销、留存清理可验证。schema_version、mode、context、compatibility 等字段由服务端白名单校验。 |
| P4 · 网页交互 估计 1–2 人日 | frontend/src/dialogs.tsx、types.ts、api.ts 按需调整:模式选择、兼容性与精度说明、任务状态、错误反馈、下载和重试。 | 桌面/手机可用;不显示无依据百分比;错误不丢失筛选上下文;CSV 与旧 XLSX 行为清晰保留。 |
| P5 · 引擎与全量验收 估计 3–5 人日 | 新增 tests/test_exporting.py、扩展 tests/e2e/workspace.spec.ts;编写受控重算与差异报告脚本;更新 docs/acceptance.md。 | 下节所有适用门禁有可复现记录;33 万行性能验证及财务签字完成。 |
合计粗估 10–18 人日,用于排期,不是承诺。受控 Excel 测试环境、财务确认和超预算性能优化可能增加日历时间。P1 小样本原型通过后再投入大文件任务流程;各阶段保持可单独审查和回滚。
兼容 API:旧 format=xlsx 默认仍为证据快照;新公式模式显式申请任务并返回任务 ID。服务端返回实际导出模式与版本,前端不凭文件后缀推断。
09 / 严格测试与上线门禁
openpyxl 不执行计算;设置自动重算或 fullCalcOnLoad 也不是测试结果。必须在目标 Excel 引擎执行、保存,再同时读取公式和结果缓存验证。
| 测试层 | 必须覆盖的场景 | 通过标准 |
|---|---|---|
| 结构与公式覆盖 | 每页、命名范围、Table、单元格类型、公式依赖、说明及数据验证;空数据导出。 | 衍生区域全覆盖真实公式,基础输入无意外公式;无循环引用、损坏修复提示或外部链接。 |
| 财务黄金样例 | 两种 ROI、direct/lookup 毛利、退款、负数、0、缺成本、部分缺字段、缺期、基期0、新增/消失分组。 | 与独立 Decimal 预期一致到批准精度;人数完全相等;缺失不能变0。 |
| 客户去重 | 同人跨科室/产品/月,重复明细、自营与非自营交集、空客户字段。 | 总体不相加子组人数;升单率分子去重正确;缺客户状态与系统一致。 |
| 真实引擎重算 | Excel Windows / Mac;打开重算保存;分别读取 formula 与 data_only;修改收入、成本、原价及毛利率后再次计算。 | 受影响链路变化符合独立预期,非依赖指标不误变。扫描 #REF!、#DIV/0!、#VALUE!、#NAME?、#SPILL!;仅允许明确缺失状态对应的 #N/A。 |
| 精度极限 | 15位边界、24位小数、极大金额、正负抵消、舍入临界值、33万行累计差异。 | 精确文本不变;超出政策明确报警或拒绝;不通过放宽误差掩盖错误。 |
| 注入与越权 | 恶意标签/原始公式、工作表名特殊字符、跨组织/科室、任务 ID 猜测、下载前撤权。 | 无执行不可信公式、外链或敏感原值泄露;未授权下载拒绝并审计。 |
| 任务可靠性 | 重复提交、worker中断、磁盘不足、超时、并发、到期清理。 | 无半成品下载、孤儿文件和静默截断;失败可解释,恢复无重复发布。 |
| 前端与兼容回归 | 两模式选择、状态、错误重试、下载、移动端;现有 CSV/XLSX。 | 浏览器端到端通过;旧证据版仍保持精度与公式注入防护。新公式版测试只允许白名单公式,不删除旧安全断言。 |
| 真实附件全量 | 332,830行;2025-08/2026-08及原映射;全量与分组对账。 | 行数不缺失,金额满足政策,人数为33,147 / 38,361;缺成本 ROI 不可用,未配置自营范围不擅自补值。 |
发布清单(全部待实施验证)
- □ 口径、精度、编辑范围、支持引擎由财务及产品负责人确认。
- □ 所有指标有公式覆盖与独立数值断言,修改输入后的重算链通过。
- □ 真实 Excel 重算证据包含引擎版本、脚本或步骤、输入哈希、结果与误差报告;LibreOffice 只能证明其自身兼容性。
- □ 原附件全量导出、权限、安全和资源预算通过;大文件首开及改值重算满足商定目标。
- □ 使用说明、列字典、异常状态与原始证据齐全,无患者原始标识泄露。
- □ 灰度开关、失败回退、审计、清理、任务运行监控与运维说明就绪。
上线先小范围授权用户试用公式模式,旧证据导出保留作为回退。只有 Excel 导出门禁通过,不意味着整个财务系统所有商业上线门禁自动满足。
10 / 需确认的业务决策
可直接采用的工程默认
- 双模式并存,公式版 XLSX 不含宏和外链。
- 精确证据 + 数值计算 + 对账,不牺牲原始精度。
- Microsoft 365 为首版公式验收目标。
- 固定范围、指定输入可改,结构变化重新导出。
- 大文件异步、授权下载、客户去标识。
上线前必须由财务确认
- 收入继续使用 N 列,还是另需 I 列实收口径?
- 舍入在每行还是最终汇总发生?使用哪种舍入规则与容差?
- 毛利率允许本地模拟吗?直接毛利是否允许修改?
- 自营产品集合、退款计人、成本归属及 ROI 口径是什么?
- 是否必须支持旧版 Excel/WPS,以及首次打开前就有结果缓存?
建议实施顺序:先确认口径与 Excel 版本 → 小样本真正公式与重算验证 → 33 万行任务化及性能测试 → 前端完整交互与财务签字。不要先把导出值改成数值、加几条 SUM,就标记需求完成。