You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于XSLT实现按供应商自定义ERP发票描述字段的方案问询

实现方案:基于供应商配置动态生成ERP发票Description字段

1. 定义供应商配置文件(vendors.xml)

给每个供应商定义专属的Description模板,用占位符对应Peppol发票里的XML节点,同时支持固定文本拼接。会计只需修改这个XML就能自定义内容和顺序,无需改动XSLT代码。

示例配置:

<vendors>
  <vendor>
    <vendor-id>VEND001</vendor-id>
    <!-- 模板:固定文本 + 占位符组合 -->
    <description-template>Invoice {invoice-number} from {supplier-name} (Issue Date: {invoice-date})</description-template>
  </vendor>
  <vendor>
    <vendor-id>VEND002</vendor-id>
    <description-template>#{invoice-number} | Total: {total-amount} EUR | Tax ID: {supplier-tax-id}</description-template>
  </vendor>
  <!-- 可选扩展:支持自定义占位符映射,适配更多Peppol节点 -->
  <vendor>
    <vendor-id>VEND003</vendor-id>
    <description-template>PO {po-number} - Invoice {invoice-number}</description-template>
    <placeholder-mappings>
      <mapping>
        <placeholder>{po-number}</placeholder>
        <xpath>./OrderReference/ID</xpath> <!-- 对应Peppol发票中采购订单ID的路径 -->
      </mapping>
    </placeholder-mappings>
  </vendor>
</vendors>

2. XSLT核心实现逻辑

在Peppol转ERP格式的XSLT中,引入vendors.xml配置,根据当前供应商ID匹配模板,再将占位符替换为实际发票数据。

基础版(XSLT 2.0)

适合固定占位符场景,无需频繁扩展新字段:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- 加载供应商配置文件 -->
  <xsl:variable name="vendors-config" select="document('vendors.xml')/vendors"/>

  <!-- 匹配Peppol发票根节点 -->
  <xsl:template match="/Invoice">
    <!-- 获取当前供应商ID(路径需匹配你的Peppol发票结构) -->
    <xsl:variable name="current-vendor-id" select="./AccountingSupplierParty/Party/PartyIdentification/ID"/>
    
    <!-- 匹配当前供应商的模板,无配置则用默认模板 -->
    <xsl:variable name="desc-template" select="$vendors-config/vendor[vendor-id = $current-vendor-id]/description-template"/>
    <xsl:variable name="default-template" select="'Invoice {invoice-number} - {supplier-name}'"/>
    <xsl:variable name="target-template" select="if ($desc-template) then $desc-template else $default-template"/>

    <!-- 生成ERP发票结构 -->
    <ERP-Invoice>
      <Description>
        <xsl:call-template name="replace-placeholders">
          <xsl:with-param name="template" select="$target-template"/>
          <xsl:with-param name="invoice" select="."/>
        </xsl:call-template>
      </Description>
      <!-- 其他ERP字段转换逻辑... -->
    </ERP-Invoice>
  </xsl:template>

  <!-- 占位符替换模板 -->
  <xsl:template name="replace-placeholders">
    <xsl:param name="template"/>
    <xsl:param name="invoice"/>

    <xsl:choose>
      <!-- 替换发票编号 -->
      <xsl:when test="contains($template, '{invoice-number}')">
        <xsl:call-template name="replace-placeholders">
          <xsl:with-param name="template" select="replace($template, '\{invoice-number\}', $invoice/ID)"/>
          <xsl:with-param name="invoice" select="$invoice"/>
        </xsl:call-template>
      </xsl:when>
      <!-- 替换供应商名称 -->
      <xsl:when test="contains($template, '{supplier-name}')">
        <xsl:call-template name="replace-placeholders">
          <xsl:with-param name="template" select="replace($template, '\{supplier-name\}', $invoice/AccountingSupplierParty/Party/PartyName/Name)"/>
          <xsl:with-param name="invoice" select="$invoice"/>
        </xsl:call-template>
      </xsl:when>
      <!-- 替换发票日期 -->
      <xsl:when test="contains($template, '{invoice-date}')">
        <xsl:call-template name="replace-placeholders">
          <xsl:with-param name="template" select="replace($template, '\{invoice-date\}', $invoice/IssueDate)"/>
          <xsl:with-param name="invoice" select="$invoice"/>
        </xsl:call-template>
      </xsl:when>
      <!-- 替换总金额 -->
      <xsl:when test="contains($template, '{total-amount}')">
        <xsl:call-template name="replace-placeholders">
          <xsl:with-param name="template" select="replace($template, '\{total-amount\}', $invoice/LegalMonetaryTotal/PayableAmount)"/>
          <xsl:with-param name="invoice" select="$invoice"/>
        </xsl:call-template>
      </xsl:when>
      <!-- 替换供应商税号 -->
      <xsl:when test="contains($template, '{supplier-tax-id}')">
        <xsl:call-template name="replace-placeholders">
          <xsl:with-param name="template" select="replace($template, '\{supplier-tax-id\}', $invoice/AccountingSupplierParty/Party/TaxRegistration/TaxSchemeID)"/>
          <xsl:with-param name="invoice" select="$invoice"/>
        </xsl:call-template>
      </xsl:when>
      <!-- 无占位符时输出最终文本 -->
      <xsl:otherwise>
        <xsl:value-of select="$template"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

进阶版(XSLT 3.0)

支持动态占位符映射,会计可自行添加新的Peppol节点映射,无需修改XSLT:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:variable name="vendors-config" select="document('vendors.xml')/vendors"/>

  <xsl:template match="/Invoice">
    <xsl:variable name="current-vendor-id" select="./AccountingSupplierParty/Party/PartyIdentification/ID"/>
    <xsl:variable name="vendor-config" select="$vendors-config/vendor[vendor-id = $current-vendor-id]"/>
    <xsl:variable name="desc-template" select="$vendor-config/description-template"/>
    <xsl:variable name="default-template" select="'Invoice {invoice-number} - {supplier-name}'"/>
    <xsl:variable name="target-template" select="if ($desc-template) then $desc-template else $default-template"/>

    <ERP-Invoice>
      <Description>
        <!-- 先替换预定义占位符 -->
        <xsl:variable name="pre-replaced">
          <xsl:call-template name="replace-placeholders">
            <xsl:with-param name="template" select="$target-template"/>
            <xsl:with-param name="invoice" select="."/>
          </xsl:call-template>
        </xsl:variable>
        <!-- 再替换自定义占位符 -->
        <xsl:call-template name="replace-custom-placeholders">
          <xsl:with-param name="template" select="$pre-replaced"/>
          <xsl:with-param name="invoice" select="."/>
          <xsl:with-param name="mappings" select="$vendor-config/placeholder-mappings/mapping"/>
        </xsl:call-template>
      </Description>
      <!-- 其他ERP字段... -->
    </ERP-Invoice>
  </xsl:template>

  <!-- 保留基础版的预定义占位符替换模板 -->
  <xsl:template name="replace-placeholders">
    <!-- 同基础版代码 -->
  </xsl:template>

  <!-- 自定义占位符替换模板 -->
  <xsl:template name="replace-custom-placeholders">
    <xsl:param name="template"/>
    <xsl:param name="invoice"/>
    <xsl:param name="mappings"/>

    <xsl:if test="$mappings">
      <xsl:variable name="current-mapping" select="$mappings[1]"/>
      <!-- 执行XPath获取节点值,不存在则显示[N/A] -->
      <xsl:variable name="field-value" select="xsl:evaluate($current-mapping/xpath, $invoice)"/>
      <xsl:variable name="display-value" select="if ($field-value) then $field-value else '[N/A]'"/>
      <!-- 替换占位符 -->
      <xsl:variable name="updated-template" select="replace($template, escape-html-uri($current-mapping/placeholder), $display-value)"/>
      <!-- 递归处理剩余映射 -->
      <xsl:call-template name="replace-custom-placeholders">
        <xsl:with-param name="template" select="$updated-template"/>
        <xsl:with-param name="invoice" select="$invoice"/>
        <xsl:with-param name="mappings" select="$mappings[position() > 1]"/>
      </xsl:call-template>
    </xsl:if>
    <xsl:if test="not($mappings)">
      <xsl:value-of select="$template"/>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

3. 优化与落地建议

  • 错误处理:在占位符替换时,若对应Peppol节点不存在,输出[N/A]或自定义默认值,避免空值影响ERP导入。
  • 配置简化:给会计提供Excel模板(列:供应商ID、模板文本、占位符、XPath),通过VBA或脚本自动生成vendors.xml,降低配置门槛。
  • 测试验证:针对每个供应商配置,生成测试Peppol发票,转换后检查Description字段是否符合预期,覆盖无配置、节点缺失等边界场景。

内容的提问来源于stack exchange,提问作者Kees Netelvrees

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 04:32:08