feat(w05): 主数据基线加料件/需求/替代/验证四域六表(P-08/P-10/P-01/P-11/P-06)与样例料号

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJcX8A6TWp4GRs41TYryEh
This commit is contained in:
xcs
2026-08-26 23:10:08 +08:00
co-authored by Claude Fable 5
parent a681ffe9f7
commit 63034f5ab2
3 changed files with 230 additions and 9 deletions
@@ -6,19 +6,36 @@
* 2026-07-31 重分:单据归各活动自己的域,这个文件只留**主数据**,按常规 CRM / ERP 分四域。
*
* 守的是三条,每条都能机检:
* · 只有这四个域,不多不少 —— 多一个就说明有人把单据塞进主数据了;
* · 八个域,多一个就说明有人把单据塞进主数据了;
* · 每张表都是 `master` 且**不带单标识** —— 带了就是单据归错类(安装静态审也会拦);
* · 主键是**业务实体**,不是单。
*/
import { describe, expect, it } from 'vitest';
import { MASTER_DOMAINS, MASTER_OBJECTS } from '../seed-mvp-data.ts';
import { MASTER_DOMAINS, MASTER_OBJECTS, MASTER_SAMPLE_ROWS } from '../seed-mvp-data.ts';
describe('主数据四域', () => {
it('只有客户 / 项目 / 供应商 / 市场四个域', () => {
expect([...MASTER_DOMAINS]).toEqual(['customer', 'project', 'supplier', 'market']);
it('八个域:客户 / 项目 / 供应商 / 市场 + 料件 / 需求 / 替代 / 验证(SS02 差异评估 2026-08-26 加后四域)', () => {
expect([...MASTER_DOMAINS]).toEqual(['customer', 'project', 'supplier', 'market', 'parts', 'demand', 'substitution', 'validation']);
expect([...new Set(MASTER_OBJECTS.map((o) => o.domain))].sort()).toEqual([...MASTER_DOMAINS].sort());
});
it('SS02 差异评估要读写的六张主数据表都在基线里,主键照《统一方案》', () => {
const pk = (domain: string, object: string) =>
MASTER_OBJECTS.find((o) => o.domain === domain && o.object === object)?.fields.filter((f) => f.primaryKey).map((f) => f.name);
expect(pk('parts', 'profile')).toEqual(['internal_pn']);
expect(pk('parts', 'document')).toEqual(['internal_pn', 'doc_seq']);
expect(pk('demand', 'request')).toEqual(['request_id']);
expect(pk('substitution', 'relation')).toEqual(['substitution_relation_id']);
expect(pk('substitution', 'difference_item')).toEqual(['substitution_relation_id', 'difference_item_id']);
expect(pk('validation', 'record')).toEqual(['validation_id']);
});
it('样例料号:原 PN 与同族可调版在库,候选 XL2596S-5.0 刻意不播(数据工单那条路要试得出来)', () => {
const parts = MASTER_SAMPLE_ROWS.filter((r) => r.address.domain === 'parts' && r.address.object === 'profile').map((r) => r.key['internal_pn']);
expect(parts).toEqual(['LM2596S-5.0', 'LM2596S-ADJ']);
expect(parts).not.toContain('XL2596S-5.0');
});
it('四个域各自都有表 —— 空占位也得立得住', () => {
for (const d of MASTER_DOMAINS) {
expect(MASTER_OBJECTS.filter((o) => o.domain === d).length, `${d} 域一张表都没有`).toBeGreaterThan(0);