GST 发票数据模型基础:最小字段、HSN 处理与所需管理界面,帮助生成合规发票并简化对账。

大多数 GST 发票问题并不是“复杂的税务逻辑”问题,而是缺失或不一致的数据问题。当发票无法清晰地对应所售商品、交易方、供应地点以及税费计算方式时,审计就会失败。
常见的触发点是 HSN 缺失、过期或在错误层级应用。团队可能在产品上保存了 HSN,但发票行来自不同的 SKU 名称或变体,结果 HSN 没有出现在最终凭证上。另一个常见问题是税种分拆错误:因为“供给地”直接从收货地址猜测而没有保存用于决策的州编码,导致本应为 CGST+SGST 的情况被收取 IGST(或反之)。
财务团队会立刻感受到影响。对账变成了日常的清理工作:发票总额与订单不符,订单与支付网关结算不符,退款需要手动的链式记录。即便是行项目之间的微小四舍五入差异,也会造成发票 PDF、GST 报表与账本之间的不匹配。
以下是导致大多数不匹配痛点的模式:
GST 发票数据模型的目标很简单:保存一组最小但充分的订单、产品、交易方、税务、发票和贷项字段,以便每个数字都能被重现并解释。保持精简,但不要丢弃决定税种、税率和申报的法律重要字段。
如果你希望发票易于生成并且方便日后对账,从一小组对象开始,并让每个对象只做一件事。一个干净的 GST 发票数据模型与其说是多表,不如说是让事实在时间上保持稳定。
以下是大多数团队在 Day One 需要的核心记录:
发票应与订单分离。订单会变(改地址、取消商品、部分履约),而发票不应变。发票需要稳定的编号、日期和永不“漂移”的总额,以免后续有人改动订单。
税务准确的核心是行项目(Line Items)。每个订单行(以及后续的每个发票行)都应保存该项的准确数量、单价、折扣及税务分解。这是应用 HSN/SAC 与 GST 费率的真实位置。
一个能救财务团队的细节是:保存快照。在生成发票时,将产品描述、HSN/SAC、税率和定价复制到发票行。不要依赖当前的产品主数据,因为费率和名称会变更。
可选但常值得及早加入的记录有退货、退款和贷项单。例如:客户从两件商品的订单中退回一件,你需要一个引用原发票行的贷项单,同时退款记录引用网关交易。将这些作为显式对象能防止月末在 GST 登记簿上的“人工修正”。
如果你在 Koder.ai 中构建,先把每个对象做成简单界面(创建、查看、编辑),有了快照和行级字段后再添加发票生成功能。
HSN(货物)和 SAC(服务)并不是“仅在发票上”的细节。它们从产品或服务定义开始,然后在开票时复制到每个发票行。这样可以确保混合购物车的正确性,并便于审计,因为每行都能独立说明。
一个实用的最小数据模型为:
将 HSN/SAC 放在 Product 上便于管理,只是在开票时复制到 InvoiceLine 才能保证历史发票稳定。即使产品随后被修改,发票仍然显示当时的真实情况。这就是不会在对账时崩溃的 GST 发票数据模型核心。
关于 HSN 存储,保持简单:代码为必填,描述为可选,若需要变更历史可选地保存 effective_from 日期。大多数团队不需要在每个行项上都显示描述,但在财务核查异常时会有帮助。
混合购物车很常见:一张发票可以有多个行项,也因此包含多个 HSN/SAC 代码。不要强制每张发票只能有一个代码。合计在发票级别汇总,而分类应停留在行级。
变更管理是人们容易出错的地方。采用简单规则:
在管理界面上,你只需要一个地方编辑产品税务字段,并在发票行上提供只读视图以确认开票时捕获的内容。如果要快速构建这些界面,像 Koder.ai 这样的工具可以根据模型生成基本的 CRUD 页面和数据表,工作量很小。
GST 发票数据模型最常失败的地方是交易方详情。如果买卖双方身份哪怕有一点偏差,发票在纸面上可能通过,但在申报和对账时会很痛苦。
把“卖方”、“买方”和“收货方”视作独立的主体,即使它们是同一人也如此。这样可以防止客户新增不同收货地址或从多个 GST 注册点发货时的应急改动。
保持字段平实且明确。这些通常需要出现在发票和报表中:
把州既以人可读的名称也以州代码存储,因为报告与供给地规则常依赖代码。
在订单上捕获账单与发货地址,而不是只存在客户档案中。档案会变,发票不应变。
供给地应作为具体的州代码在发票上保存(在开票时从订单复制)。不要“以后再重新计算”。如果你的规则是“以收货地为准”,将该结果及用于决定的州一起存下,这使审计与争议更容易处理。
对于 B2B,买方 GSTIN 通常是必需的,应在输入时验证长度和格式。对于 B2C,GSTIN 可为空,但仍需完整地址与州来决定适用 CGST/SGST 还是 IGST。
一个简单规则:如果存在买方 GSTIN,则视为 B2B;若没有,则视为 B2C。如需例外,可存 customer_type 字段以明确区分。
若你有不同 GST 注册的分支或业务单元,将“卖方实体”建模为独立记录并包含其 GSTIN 与地址。每笔订单应引用一个卖方实体,且每张发票在开具时复制该实体信息,确保历史发票在卖方地址变更后仍保持准确。
像 Koder.ai 这样的工具可以快速生成这些记录的管理表单,但关键在于结构:独立的卖方实体、开票快照和明确的供给地州编码。
最常见的分法很简单:供给地若与供应方同州,即适用 CGST+SGST;若不同州,则适用 IGST。系统不应“以后从总额重算”,因为细小差异(四舍五入、折扣、运费)正是造成不匹配的根源。
至少要在发票行级保存税务数字,而不仅保存在发票头。这样你可以解释发票上的每一元,并将其追溯到产品、HSN 与收入。
每个发票行建议保存的最小字段如下:
折扣是系统混乱的常见来源。选择一套规则并将其清晰保存。如果折扣在税前减少价格(典型的商品折扣和优惠券),则保存原始毛额、折扣额和最终应税值。若有订单级优惠券,按行分配(通常按行的税前应税值比例分配)并保存每行的分配折扣,以便税务计算可解释。
四舍五入应保持一致并记录。选择在行级四舍五入还是仅在发票级四舍五入,然后保存你打印出的已四舍五入结果。许多团队按行计算税费、四舍五入到两位小数、求和后再用 invoice_rounding_adjustment 字段达到精确应付金额。
运费与手续费不应是隐藏的附加项。把它们作为单独的发票行处理,赋予自己的 HSN/服务代码与税率规则。例如,一个包含两个产品和一笔运费的订单应视为三行,每行都保存应税值与税额,从而大大简化对账。
税费计算完成后,发票仍需“文档”字段以保证其有效、可审计并便于日后对账。在 GST 发票数据模型中,把发票头视作法律记录:它应保持稳定,即便产品或客户数据日后变更。
从头部基础字段开始:发票编号、开具日期(发票上日期)、发票类型(税务发票、出口、B2B、B2C 等)和货币。即便大部分以 INR 开票,保存货币字段也能避免出口或多币种平台的边缘问题。
编号是团队容易踩坑的地方。保留序列或前缀(例如 "FY25-INV-")、保存财年并在数据库级别强制唯一性。同时在管理端保存按序列的“下一个编号”控制,以免两位管理员同时发号导致重复。
总额应明确保存,而非仅派生。保存小计(应税总额)、税额合计、总额和独立的四舍五入项。如果你以后从行项重算,一条规则的微调就可能让旧发票与已申报的报表不再匹配。
状态应反映真实生命周期并在需要时锁定记录:
最后,保存生成产物的元数据:PDF 模板版本、生成时间戳与文件标识符。哈希为可选项,但若需要证明 PDF 未被篡改则很有用。
例如:若客服在模板更新后重新生成 PDF,发票的总额和编号应保持一致,但存下的模板版本能解释为什么 PDF 布局不同。
要得到干净的 GST 发票,不要从发票界面开始,而应从喂入发票的管理页面开始。一个好的 GST 发票数据模型在这些输入受控且一致时会保持精简。
产品主数据是未来大多数不匹配的根源,故保持严格。每个 SKU 应有唯一默认 HSN(或服务的 SAC)、默认 GST 费率以及仅在特定日期生效的例外情况。
实用的产品界面通常需要:
避免“计算器式”的 UI。反而应保存系统能一致应用的输入:费率表、你遵循的供给地规则以及如何判定跨州与同州(通常通过比较供应方州与收货州)。
税务界面应聚焦于:按类别/HSN 分的税率、有效期,以及买方提供有效 GSTIN 与否时的处理方式。
客户界面应捕获 GSTIN 及其验证状态,以及默认账单和收货地址。不要让用户随意输入州;用受控列表避免“KA”与“Karnataka”成为两个不同的值。
公司档案界面同样重要:法定名称、GSTIN、注册地址与发票序列设置(前缀、下一个编号与财年边界)。用权限锁定这些设置,因改动会影响未来的每份文档。
你不需要复杂系统,但需要审计轨迹。记录谁修改了 HSN/SAC、GST 费率、发票序列设置或公司 GSTIN,以及旧值、新值、时间戳和变更原因。
若在像 Koder.ai 这类工具中构建,将审计日志与生效日期作为首要字段从一开始就加入,投入小且能在财务复核时节省大量时间。
合规发票关键在于在正确时间冻结正确的事实。若你按此流程设计 GST 发票数据模型,财务工作将变成简单对比,而不是每周调查。
在计算税费前,锁定订单快照:商品、数量、单价、折扣、运费/手续费、客户 GSTIN(如有)、账单与收货地址以及供给地信号。快照一旦冻结,不应随产品价格或 HSN 映射变动而更改。
基于快照计算税费并生成发票行。每个发票行都应复制 HSN/SAC、税率、应税值和当时使用的税额,而不是以后再去实时查找。
分配发票编号和开具日期,然后将发票标记为已开具。从此以后,阻止对发票记录中价格、税率、HSN 代码和地址的编辑。若需允许更改,仅限非财务注记和内部标签。
从已开具发票生成 PDF/打印视图,然后保存你将申报的最终总额:应税总额、CGST/SGST/IGST 合计、四舍五入与总计。若要额外安全,可保存文档版本或校验和以证明打印输出与存储数字一致。
开具后,变更应遵循规则而非直接编辑:
若你将该流程嵌入管理界面(可在 Koder.ai 的规划模式下先绘制步骤),团队即可在不破坏对账的前提下快速生成发票。
当把付款当成订单上的一个“已付/未付”标记时,对账会变得混乱。将付款和退款做为独立记录并指向订单与发票,财务才能在不改写历史的情况下匹配银行结算。
已开具发票应保持稳定。若客户分期付款或稍后退款,应记录为付款或退款条目,而不是更改发票总额。
通常能简化对账的最小字段有:
若客户退回一件商品,不要“缩减发票”。为被退商品开具贷项单并关联原发票。发票登记保持干净,退款与贷项单关联。
给财务一个能够回答以下问题的单一视图:已开具了什么、已收了什么、仍未结清的是什么、有哪些已冲正。包含账龄(0-7、8-30、31-60、60+ 天)并能下钻到相关的付款和退款条目。
大多数团队每月需要导出的报表:
举例:一个订单为 Rs 10,000,今天支付 Rs 6,000,下周支付 Rs 4,000。发票仍为 Rs 10,000。财务视图显示余额 Rs 4,000,直到第二笔结算到达后再标记为已付,不更改已开具的文件。
大多数 GST 发票问题不是“税务逻辑”问题,而是记录保存问题:PDF 上的数字与财务导出不匹配,或发票无法在几个月后被解释。
第一个陷阱是仅在查看时计算 GST。如果每次有人打开发票你都实时计算 CGST/SGST/IGST,率变、四舍五入规则变或修复 bug 后,结果终会不同。应保存开具时使用的已计算税额,即便同时保存输入也要保存输出。
第二个陷阱是允许编辑已开具的发票。发票一旦最终化,变更应通过贷项单或替代流程并留审计痕迹。否则会出现“为什么客户看到的 PDF 与账面不同?”的争议。
下面是 GST 发票数据模型中最常出现的不匹配模式:
一个简单例子:你向 Karnataka 的客户出售,但收货地址在 Maharashtra。如果系统误用账单州作为供给地,可能会收取 CGST+SGST 而不是 IGST。如果你又在查看时实时重算税费,该错误可能会在后续悄悄“自我修正”,留给财务一堆与已开具凭证不匹配的数字。
在构建管理界面(自定义或通过 Koder.ai)时,加一些保护:锁定已开具发票、在计算税种旁显示供给地输入并保留开具时使用的 HSN、费率与四舍五入的不可变快照。
在你将发票发送给客户或标记为“已开具”之前,做一系列快速检查。这是小错误变成大对账灾难的关口。若你在构建 GST 发票数据模型,把这些检查嵌到验证规则与管理 UI 中是很值得的。
举例:客户在付款后更新了收货地址并导致州发生变化。若你重新使用相同发票编号并修改税额,登记簿与付款记录将不再匹配。更安全的方法是保持原发票不可变并通过调整单据处理差异。
下一步:先实现这些界面和校验,再迭代。在 Koder.ai 中,从规划模式开始绘制记录与管理界面(含 HSN/SAC 映射的产品、客户/GSTIN 详情、税务规则与发票)。生成应用并用真实订单做端到端测试,然后利用快照和回滚安全地优化流程。当需要更深的定制或评审时,导出源码并用你的开发流程继续演进。