Skip to content

line[].tradeSettlement.allowances is missing ChargeIndicator #116

Open

Description

@kilbiller

To Reproduce

  1. Create a EN16931 invoice with discounts on line items in the form of allowances
  2. Check the xml output

Current vs. Expected behavior

A Charge indicator set to false should be present at the top but nothing is set, i also tried adding chargeIndicator: false to the object but it does nothing.

Here is what is generated :

<ram:IncludedSupplyChainTradeLineItem>
      <ram:AssociatedDocumentLineDocument>
        <ram:LineID>2</ram:LineID>
      </ram:AssociatedDocumentLineDocument>
      <ram:SpecifiedTradeProduct>
        <ram:Name>Billets - Billet 2</ram:Name>
      </ram:SpecifiedTradeProduct>
      <ram:SpecifiedLineTradeAgreement>
        <ram:GrossPriceProductTradePrice>
          <ram:ChargeAmount>65</ram:ChargeAmount>
          <ram:BasisQuantity unitCode="C62">1</ram:BasisQuantity>
        </ram:GrossPriceProductTradePrice>
        <ram:NetPriceProductTradePrice>
          <ram:ChargeAmount>52.5</ram:ChargeAmount>
          <ram:BasisQuantity unitCode="C62">1</ram:BasisQuantity>
        </ram:NetPriceProductTradePrice>
      </ram:SpecifiedLineTradeAgreement>
      <ram:SpecifiedLineTradeDelivery>
        <ram:BilledQuantity unitCode="C62">1</ram:BilledQuantity>
      </ram:SpecifiedLineTradeDelivery>
      <ram:SpecifiedLineTradeSettlement>
        <ram:ApplicableTradeTax>
          <ram:TypeCode>VAT</ram:TypeCode>
          <ram:CategoryCode>S</ram:CategoryCode>
          <ram:RateApplicablePercent>20</ram:RateApplicablePercent>
        </ram:ApplicableTradeTax>
        <ram:SpecifiedTradeAllowanceCharge>
          <ram:ActualAmount>12.5</ram:ActualAmount>
          <ram:Reason>BILLETPASCHER applied on Billets - Billet 2</ram:Reason>
        </ram:SpecifiedTradeAllowanceCharge>
        <ram:SpecifiedTradeSettlementLineMonetarySummation>
          <ram:LineTotalAmount>52.5</ram:LineTotalAmount>
        </ram:SpecifiedTradeSettlementLineMonetarySummation>
      </ram:SpecifiedLineTradeSettlement>
    </ram:IncludedSupplyChainTradeLineItem>

Notice SpecifiedTradeAllowanceCharge is missing ChargeIndicator.

Here is the error report from Mustang:

schema validation fails:org.xml.sax.SAXParseException; lineNumber: 93; columnNumber: 29; cvc-complex-type.2.4.a: Invalid content was found starting with element ‘{“urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100”:ActualAmount}’. One of ‘{“urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100”:ChargeIndicator}’ is expected.

[CII-SR-463]-Each Specified Trade Allowance Charge (BG-20)(BG-21) shall contain a Charge Indicator. [ID FX-SCH-A-000348] from /xslt/ZF_240/FACTUR-X_EN16931.xslt)

[CII-SR-463]-Each Specified Trade Allowance Charge (BG-20)(BG-21) shall contain a Charge Indicator. [ID FX-SCH-A-000348] from /xslt/ZF_240/FACTUR-X_EN16931.xslt)

What version of node-zugferd are you using?

0.1.1-beta.1

Provide environment information

Node v24.14.1

Which area(s) are affected? (Select all that apply)

Package

Config (if applicable)

import { zugferd } from 'node-zugferd';
import { EN16931, type ProfileEN16931 } from 'node-zugferd/profile/en16931';

const invoicer = zugferd({
			profile: EN16931,
			strict: false,
		});

Activity

  1. linked a pull request that will close this issuefeat: v1.0.0.beta-0 #115on Jul 3, 2026
  2. kobima6813 commented on Oct 26, 2026

    @kobima6813

    Additional repro for this, on node-zugferd 0.1.1-beta.1 (Node 20.19.2, EN16931 profile).

    Any invoice line with tradeSettlement.allowances fails the library's own XSD check, so toXML() rejects it:

    invalid xml (status=WITH_ERRORS)
      [error] cvc-complex-type.2.4.a: Invalid content was found starting with element
      '{"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100":ActualAmount}'.
      One of '{"...:100":ChargeIndicator}' is expected.
    

    Inside ram:SpecifiedTradeAllowanceCharge, the CII XSD requires ram:ChargeIndicator before ram:ActualAmount.
    The schema declares chargeIndicator (BG-27-0) as additionalXml of actualAmount (BT-136), but it is not emitted
    before ActualAmount. Passing chargeIndicator: false explicitly makes no difference, as #116 also says.

    Minimal repro (node repro.mjs):

    import { zugferd } from "node-zugferd";
    import { EN16931 } from "node-zugferd/profile/en16931";
    
    const invoicer = zugferd({ profile: EN16931 });
    const addr = { postCode: "10115", line1: "Musterstr. 1", city: "Berlin", countryCode: "DE" };
    const data = {
      number: "R-1", typeCode: "380", issueDate: new Date("2026-10-26"),
      transaction: {
        line: [{
          identifier: "1", tradeProduct: { name: "Item" },
          tradeAgreement: { netTradePrice: { chargeAmount: "100.00" } },
          tradeDelivery: { billedQuantity: { amount: 1, unitMeasureCode: "H87" } },
          tradeSettlement: {
            tradeTax: { typeCode: "VAT", categoryCode: "S", rateApplicablePercent: "19" },
            allowances: [{ actualAmount: "10.00", reasonCode: "95", reason: "Discount" }], // remove this line -> OK
            monetarySummation: { lineTotalAmount: "90.00" },
          },
        }],
        tradeAgreement: {
          seller: { name: "Seller GmbH", postalAddress: addr, taxRegistration: { vatIdentifier: "DE123456788" } },
          buyer: { name: "Buyer AG", postalAddress: addr },
        },
        tradeDelivery: { information: { deliveryDate: new Date("2026-10-26") } },
        tradeSettlement: {
          currencyCode: "EUR",
          vatBreakdown: [{ calculatedAmount: "17.10", typeCode: "VAT", basisAmount: "90.00", categoryCode: "S", rateApplicablePercent: "19" }],
          paymentTerms: { dueDate: new Date("2026-11-25") },
          monetarySummation: { lineTotalAmount: "90.00", taxBasisTotalAmount: "90.00",
            taxTotal: { amount: "17.10", currencyCode: "EUR" }, grandTotalAmount: "107.10", duePayableAmount: "107.10" },
        },
      },
    };
    console.log(await invoicer.create(data).toXML());
    • With the allowances line: the call throws the error above.
    • Without it: the call succeeds.

    Expected: inside each ram:SpecifiedTradeAllowanceCharge, <ram:ChargeIndicator><udt:Indicator>false</udt:Indicator></ram:ChargeIndicator>
    is written first, followed by ram:ActualAmount, ram:ReasonCode and ram:Reason.

    Impact in a larger test: we generated 600 synthetic shop carts (EN 16931, 19 %/7 % VAT) with node-zugferd.

    • The 302 carts with a line-level discount all fail with this error.
    • The other 298 are accepted by the KoSIT validator and by phive-rules (EN 16931 1.3.16).

    #85 (closed) covered the same element-order problem for document-level allowances; the line-level path still shows it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions