stephanstapel / ZUGFeRD-csharp

C# assembly for creating and reading ZUGFeRD invoices
Apache License 2.0
224 stars 118 forks source link

XRechnung validation fails because of empty GrossPriceProductTradePrice-Elements #166

Closed elotto closed 1 year ago

elotto commented 3 years ago

Item gross price in XRechnung-Profile is optional. However, by omitting of GrossUnitPrice in InvoiceLineitem, InvoiceDescriptor21Writer produce a empty entry like this:

Such files will be declined by validators with following message:

[SAX] cvc-complex-type.2.4.b: The content of element 'ram:GrossPriceProductTradePrice' is not complete. One of '{"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100":TypeCode, "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100":ChargeAmount}' is expected.

A possible workaround is always to pass a grossUnitPrise param to AddTrageLineItem() function. But it may be better to fix this bug by check for assigned grossUnitPrice before write ram:GrossPriceProductTradePrice xml element.

lngr commented 1 year ago

I have the same problem

stephanstapel commented 1 year ago

Hmm. That is a bit short for a problem description. Can you share your source code and the output file? And also which validator you are using and what the output was? Thanks!

lngr commented 1 year ago

Sure:

var desc = InvoiceDescriptor.CreateInvoice(
    "123",
    DateTime.Parse("2023-01-20"),
    CurrencyCodes.EUR,
    "123");

var lineItem = desc.AddTradeLineItem(
    "1",
    "Test-Title",
    "Test-Description",
    QuantityCodes.C62,
    sellerAssignedID: "12345",
    billedQuantity: 1m,
    netUnitPrice: 998m,
    taxType: TaxTypes.VAT,
    categoryCode: TaxCategoryCodes.S,
    taxPercent: 19m);

desc.ReferenceOrderNo = "AA-BB-CC";

desc.SetSeller("Demo GmbH", "12345", "Hamburg", "Musterstr. 37", CountryCodes.DE, "1234523");
desc.AddSellerTaxRegistration("DE12345234", TaxRegistrationSchemeID.VA);
desc.SetSellerContact("Alexander Langer", emailAddress: "email@example.de", phoneno: "040-1234523");
desc.AddCreditorFinancialAccount("DE1212345234234234", "PBNKDEFF", name: "Demo GmbH");
desc.SetPaymentMeans(PaymentMeansTypeCodes.SEPACreditTransfer);

desc.SetBuyer("Test-Buyer", "12345", "Berlin", "Demostr. 81", CountryCodes.DE, "760513696");

desc.BillingPeriodStart = DateTime.Parse("2023-01-01");
desc.BillingPeriodEnd = DateTime.Parse("2023-01-31");

desc.AddApplicableTradeTax(998m, 19m, TaxTypes.VAT, TaxCategoryCodes.S);

desc.PaymentTerms = new PaymentTerms
{
    DueDate = DateTime.Parse("2023-02-14"),
};

desc.SetTotals(
    998m,
    998m,
    taxBasisAmount: 998m,
    taxTotalAmount: 189.62m,
    grandTotalAmount: 1187.62m,
    duePayableAmount: 1187.62m);

desc.Save("demo.xml", ZUGFeRDVersion.Version21, Profile.XRechnung);

Results in:


<ram:SpecifiedLineTradeAgreement>
        <ram:GrossPriceProductTradePrice />
        <ram:NetPriceProductTradePrice>
          <ram:ChargeAmount>998.0000</ram:ChargeAmount>
        </ram:NetPriceProductTradePrice>
      </ram:SpecifiedLineTradeAgreement>

with an empty GrossPriceProductTradePrice.

The resulting file demo.txt (rename to .xml) is not accepted by the Validator of Rechnungseingang für Auftragnehmer von Kommunen oder Behörden des Landes BW:

Ihre E-Rechnung konnte nicht entgegengenommen werden. Grund dafür war:

    cvc-complex-type.2.4.b: Content des Elements 'ram:GrossPriceProductTradePrice' ist nicht vollständig. '{"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100":TypeCode, "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100":ChargeAmount}' wird erwartet.

(You can try to upload the file yourself, nothing bad will happen as it's only dummy data and the "Leitfaden-ID" is not valid anyways.

(I seem to have broken the total amounts in my dummy demo data, so the demo-file is not accepted even if the GrossPriceProductTradePrice line is removed; however my actual invoices are accepted if I just remove that empty line)

Here's a direct link to the validator: https://kositvalidator.service-bw.de/

stephanstapel commented 1 year ago

ok, thanks. Just out of curiosity: is it an option to set the grossUnitPrice parameter in AddTradeLineItem()? That would lead to filling GrossPriceProductTradePrice

lngr commented 1 year ago

In this particular invoice, yes, it will be accepted by the validator (just tested that).

However, I'd rather not have to compute the gross unit price based on tax settings and the net unit price myself, since I'm a bit afraid of rounding errors. I'm writing a mere converter using our invoicing software's REST API, and here all line items on the invoice have a net unit price only, and the total tax and total gross amounts of the invoice are computed based on the net total sum of the invoice. With an additionally speciefied gross unit price per line item, the two amounts

might differ. Not sure if this will yield problems for our "buyer".

The previous converter we used (faktoora) just omitted the GrossPriceProductTradePrice tag if grossUnitPrice is null, as suggested by @elotto

(This is probably what I will do as a workaround, i.e., manually remove the line from the invoice)

stephanstapel commented 1 year ago

I see, thanks. With the information not being available (needs to be computed 'manually') and the validator not accepting the missing tag, what can the library do for you? Does it validate correctly if the element is not present at all?

lngr commented 1 year ago

I think what @elotto wrote would be the expected behaviour:

But it may be better to fix this bug by check for assigned grossUnitPrice before write ram:GrossPriceProductTradePrice xml lement.

That would also be consistent with other fields (i.e., optional fields, that are not specified and there null, are not written to the output)

Does it validate correctly if the element is not present at all?

yes