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

Mustangproject生成XRechnung时价格校验失败问题求助

XRechnung校验错误:Gross Price与Net Price、Allowance金额不匹配问题

错误信息

当提供Gross price时,Item net price必须等于(Gross price - Allowance amount),错误路径为/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction[1]/ram:IncludedSupplyChainTradeLineItem[1]/ram:SpecifiedLineTradeAgreement[1]/ram:GrossPriceProductTradePrice[1]

当前代码实现

for (jsonMapper.InvoiceLine invoiceLine : invoiceData.invoiceLines) {
    String description = invoiceLine.itemInformation.itemDescription.getContent();
    String name = invoiceLine.itemInformation.itemName.getContent();
    String unit = invoiceLine.invoicedQuantityUnitOfMeasureCode.getContent();
    BigDecimal vATPercent = new BigDecimal(invoiceLine.lineVatInformation.invoicedItemVatRate.getContent());

    Double netPrice = invoiceLine.priceDetails.itemNetPrice.getContent();
    Double quantity = invoiceLine.invoicedQuantity.getContent();

    invoice.addItem(new Item(new BigDecimal(netPrice), new BigDecimal(quantity), 
            new Product(description, name, unit, vATPercent))).addAllowance(new IZUGFeRDAllowanceCharge() {

        @Override
        public BigDecimal getTotalAmount(IAbsoluteValueProvider trans) {
            return new BigDecimal(
            invoiceLine.invoiceLineAllowances.invoiceLineAllowanceAmount.getContent());
        }

        @Override
        public BigDecimal getTaxPercent() {
            return new BigDecimal(invoiceLine.invoiceLineAllowances.invoiceLineAllowancePercentage.getContent());
        }

        @Override
        public boolean isCharge() {
            return false;
        }

        @Override
        public String getReason() {
            return invoiceLine.invoiceLineAllowances.invoiceLineAllowanceReason.getContent();
        }
    });
}

生成的XML片段

行项目价格部分

<ram:SpecifiedLineTradeAgreement>
        <ram:GrossPriceProductTradePrice>
          <ram:ChargeAmount>40.0000</ram:ChargeAmount>
          <ram:BasisQuantity unitCode="EA">1.0000</ram:BasisQuantity>
        </ram:GrossPriceProductTradePrice>
        <ram:NetPriceProductTradePrice>
          <ram:ChargeAmount>40.0000</ram:ChargeAmount>
          <ram:BasisQuantity unitCode="EA">1.0000</ram:BasisQuantity>
        </ram:NetPriceProductTradePrice>
      </ram:SpecifiedLineTradeAgreement>

结算汇总部分

<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
    <ram:LineTotalAmount>400.00</ram:LineTotalAmount>
    <ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
    <ram:AllowanceTotalAmount>50.00</ram:AllowanceTotalAmount>
    <ram:TaxBasisTotalAmount>350.00</ram:TaxBasisTotalAmount>
    <ram:TaxTotalAmount currencyID="EUR">71.00</ram:TaxTotalAmount>
    <ram:GrandTotalAmount>421.00</ram:GrandTotalAmount>              
    <ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
    <ram:DuePayableAmount>421.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>

问题分析与解决方案

问题根源

从XML可以看出,单条行项目的GrossPrice和NetPrice都是40.00,但结算汇总里总Allowance是50.00(对应10个单位的话,单单位Allowance是5.00),这就导致GrossPrice - AllowanceAmount != NetPrice,违反了XRechnung的强制校验规则。

核心规则说明

XRechnung要求:当同时提供行项目的GrossPrice和Allowance时,必须满足单单位NetPrice = 单单位GrossPrice - 单单位AllowanceAmount。

Mustangproject框架中,Item构造器的第一个参数是单单位GrossPrice,添加Allowance后,框架会自动计算并生成正确的NetPrice。你之前的错误是直接传入了NetPrice作为GrossPrice,导致价格逻辑不匹配。

修正代码

假设JSON中的itemNetPrice是折扣后的净价,先计算单单位的Allowance,再推导GrossPrice,代码调整如下:

for (jsonMapper.InvoiceLine invoiceLine : invoiceData.invoiceLines) {
    String description = invoiceLine.itemInformation.itemDescription.getContent();
    String name = invoiceLine.itemInformation.itemName.getContent();
    String unit = invoiceLine.invoicedQuantityUnitOfMeasureCode.getContent();
    BigDecimal vATPercent = new BigDecimal(invoiceLine.lineVatInformation.invoicedItemVatRate.getContent());

    Double netPriceDouble = invoiceLine.priceDetails.itemNetPrice.getContent();
    Double quantityDouble = invoiceLine.invoicedQuantity.getContent();
    BigDecimal quantity = new BigDecimal(quantityDouble);
    
    // 获取当前行项目的总折扣金额
    BigDecimal lineAllowanceTotal = new BigDecimal(
        invoiceLine.invoiceLineAllowances.invoiceLineAllowanceAmount.getContent());
    // 计算单单位折扣金额(保留4位小数,避免精度问题)
    BigDecimal unitAllowance = lineAllowanceTotal.divide(quantity, 4, RoundingMode.HALF_UP);
    // 推导单单位GrossPrice:净价 + 单单位折扣
    BigDecimal grossPrice = new BigDecimal(netPriceDouble).add(unitAllowance);

    // 创建Item时传入GrossPrice,框架会自动计算NetPrice
    invoice.addItem(new Item(grossPrice, quantity, 
            new Product(description, name, unit, vATPercent))).addAllowance(new IZUGFeRDAllowanceCharge() {

        @Override
        public BigDecimal getTotalAmount(IAbsoluteValueProvider trans) {
            return lineAllowanceTotal;
        }

        @Override
        public BigDecimal getTaxPercent() {
            return new BigDecimal(invoiceLine.invoiceLineAllowances.invoiceLineAllowancePercentage.getContent());
        }

        @Override
        public boolean isCharge() {
            return false;
        }

        @Override
        public String getReason() {
            return invoiceLine.invoiceLineAllowances.invoiceLineAllowanceReason.getContent();
        }
    });
}

验证结果

修正后生成的行项目XML会变为:

<ram:SpecifiedLineTradeAgreement>
    <ram:GrossPriceProductTradePrice>
        <ram:ChargeAmount>45.0000</ram:ChargeAmount>
        <ram:BasisQuantity unitCode="EA">1.0000</ram:BasisQuantity>
    </ram:GrossPriceProductTradePrice>
    <ram:NetPriceProductTradePrice>
        <ram:ChargeAmount>40.0000</ram:ChargeAmount>
        <ram:BasisQuantity unitCode="EA">1.0000</ram:BasisQuantity>
    </ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>

此时45.00 - 5.00 = 40.00,完全符合校验规则,同时结算汇总的数值也会保持逻辑一致。

内容的提问来源于stack exchange,提问作者Jonas Stengel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 07:00:55