2. 供应商主数据模型设计

供应商主数据模型是整个SRM平台的“地基”。如果主数据模型设计得不好,后续的准入、绩效、寻源、结算等模块都会反复打补丁。本节围绕供应商唯一标识、组织架构、联系人、银行信息、资质证照五类核心字段展开,并进一步讨论多组织、多语言、多币种场景下的模型扩展方式。

一、供应商唯一标识:主键与业务编码分离

供应商唯一标识要解决两个问题:一是系统内部如何唯一定位一条供应商记录,二是业务人员如何用可读的编码找到它。推荐做法是“代理主键 + 业务编码”双轨制。

  • 代理主键 supplier_id:由系统生成,建议使用雪花ID或UUID,永不复用、永不修改,作为所有外键关联的锚点。
  • 业务编码 supplier_code:如 SUP-2024-000871,按“前缀-年份-流水号”规则生成,便于人工识别与对账。
  • 统一社会信用代码 tax_no:作为自然键参与查重,但不做主键,因为境外供应商可能没有该代码。

查重逻辑建议采用“强匹配 + 弱匹配”两级:统一社会信用代码完全一致时判定为重复;名称相似度超过阈值(如85%)且法人代表或注册地址一致时进入人工复核队列。这样既避免误合并,也避免同一供应商被重复建档。

二、组织架构:多组织建模的核心

供应商的组织架构字段不是简单存一个“公司名称”,而要能表达集团—子公司—工厂的层级关系。核心字段包括:

  • legal_entity_name:法人实体名称,用于合同签署主体。
  • parent_supplier_id:自关联外键,指向集团母公司,形成树形结构。
  • org_type:组织类型,枚举值如 GROUP、SUBSIDIARY、BRANCH、PLANT。
  • registration_country / registration_address:注册国与注册地址。

通过 parent_supplier_id 自关联,可以在一张表内表达任意深度的集团树。查询某集团下所有子公司时,使用递归CTE即可,无需额外建表。

三、联系人、银行信息与资质证照

这三类信息都属于“一对多”关系,必须拆成子表,不能塞进主表字段。

  • 联系人表 supplier_contact:字段包括 contact_id、supplier_id、name、role(销售/财务/质量)、phone、email、is_primary。一个供应商可有多个联系人,但主联系人唯一。
  • 银行信息表 supplier_bank:字段包括 bank_id、supplier_id、bank_name、account_no、swift_code、currency、is_default。多币种场景下,同一供应商可维护多个币种账户。
  • 资质证照表 supplier_certificate:字段包括 cert_id、supplier_id、cert_type(营业执照/ISO9001/排污许可证)、cert_no、issue_date、expire_date、file_url、status。证照到期前30天触发预警。
银行账号属于敏感信息,建议在数据库中加密存储,界面默认脱敏显示为 **** **** 1234,仅授权角色可查看完整账号。

四、多组织、多语言、多币种扩展

当平台服务集团型客户时,同一供应商可能同时与多个采购组织发生业务关系。此时不能把“供应商—采购组织”关系写死在主表,而应引入关系表 supplier_org_relation,字段包括 supplier_id、purchase_org_id、supplier_status、payment_terms、currency。这样同一供应商在A组织是合格供应商,在B组织可能仍是潜在供应商。

多语言方面,供应商名称、地址、联系人职务等需要支持多语言展示。推荐使用翻译子表 supplier_i18n,字段为 supplier_id、lang_code(zh-CN/en-US/ja-JP)、field_name、field_value。主表只存默认语言值,查询时按用户语言回退到默认值。

多币种方面,银行账户、报价、合同金额都可能涉及不同币种。模型上应遵循“金额 + 币种 + 汇率”三件套,汇率单独存 exchange_rate 表,记录 from_currency、to_currency、rate、effective_date。任何金额字段都必须带 currency_code,禁止出现无币种的裸金额。

供应商主数据模型:主表 + 子表 + 扩展关系 supplier(供应商主表) supplier_id PK 代理主键 supplier_code 业务编码 tax_no 统一社会信用代码 legal_entity_name 法人实体 parent_supplier_id FK 自关联 supplier_contact contact_id PK supplier_id FK name / role / phone is_primary 主联系人 supplier_bank bank_id PK supplier_id FK account_no / swift currency / is_default supplier_certificate cert_id PK supplier_id FK cert_type / cert_no expire_date / status supplier_org_relation supplier_id FK purchase_org_id supplier_status payment_terms supplier_i18n(多语言) supplier_id + lang_code field_name / field_value zh-CN / en-US / ja-JP exchange_rate(多币种) from_currency / to_currency rate / effective_date 金额字段必带 currency_code 实线:一对多子表关联 虚线:扩展关系表关联

五、建模落地要点

第一,所有子表都必须带 supplier_id 外键并建立索引,避免全表扫描。第二,状态字段统一使用枚举编码而非中文文本,便于多语言展示。第三,任何“一对多”信息都不要在主表用逗号拼接,否则后续查询和权限控制会非常困难。第四,主数据变更要留痕,建议增加 supplier_change_log 表记录字段级变更前后值。

下面给出一份可直接参考的建表片段,展示主表与银行子表的关键字段定义:

CREATE TABLE supplier (
  supplier_id      BIGINT PRIMARY KEY,
  supplier_code    VARCHAR(32) NOT NULL UNIQUE,
  tax_no           VARCHAR(32),
  legal_entity_name VARCHAR(200) NOT NULL,
  parent_supplier_id BIGINT,
  default_lang     VARCHAR(10) DEFAULT 'zh-CN',
  status           VARCHAR(20) DEFAULT 'POTENTIAL',
  created_at       TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE supplier_bank (
  bank_id      BIGINT PRIMARY KEY,
  supplier_id  BIGINT NOT NULL,
  bank_name    VARCHAR(200),
  account_no   VARCHAR(128),
  swift_code   VARCHAR(32),
  currency     CHAR(3) NOT NULL,
  is_default   BOOLEAN DEFAULT FALSE,
  FOREIGN KEY (supplier_id) REFERENCES supplier(supplier_id)
);
CREATE INDEX idx_bank_supplier ON supplier_bank(supplier_id);

判断模型是否合格,可以用三个问题自检:能否在不改表结构的前提下新增一种证照类型?能否让同一供应商在不同采购组织下拥有不同状态?能否在界面上按用户语言显示供应商名称?如果三个答案都是“能”,说明模型具备足够的扩展性。