Closed quotschmacher closed 4 weeks ago
good question. As far as I understand the xml generation capabilities of .net, this is not feasible. We could implement a dirty way however, inserting a custom string CUSTOMLINEBREAK and replace this value in IInvoiceDescriptorWriter by Environment.NewLine.
Quite a hack. What do you think?
It is not done with newline I think. The indentation is a thing, too. And this could be multiline given multiple Skonto-terms. And I am not a friend of such string-replacements ;-) But if it could work...
I switch to XmlWriter as a base class for generating XML. I didn't push the change yet, but if you could do this:
could you solve the problem mentioned above?
i am getting the desired result
<cac:PaymentTerms>
<cbc:Note>
#SKONTO#TAGE=14#PROZENT=0.00#BASISBETRAG=219.80#
#SKONTO#TAGE=14#PROZENT=0.00#BASISBETRAG=219.80#
</cbc:Note>
</cac:PaymentTerms
with something like this in the UBL-Writer:
// PaymentTerms (optional)
if (this.Descriptor.GetTradePaymentTerms().Where(x => !string.IsNullOrEmpty(x.Description)).ToList().Count > 0)
{
Writer.WriteStartElement("cac", "PaymentTerms");
var sbPaymentNotes = new StringBuilder();
Writer.WriteStartElement("cbc", "Note");
foreach (PaymentTerms paymentTerms in this.Descriptor.GetTradePaymentTerms().Where(x => !string.IsNullOrEmpty(x.Description)))
{
//if (paymentTerms.Description.StartsWith("#") && paymentTerms.Description.EndsWith("#"))
{
Writer.WriteRawStringWithIndentation(Environment.NewLine);
Writer.WriteRawStringWithIndentation(paymentTerms.Description, 6);
}
//sbPaymentNotes.AppendLine(paymentTerms.Description);
}
//Writer.WriteOptionalElementString("cbc", "Note", sbPaymentNotes.ToString().TrimEnd());
//Writer.WriteRawStringWithIndentation(Environment.NewLine);
//Writer.WriteRawStringWithIndentation(sbPaymentNotes.ToString(), 6);
Writer.WriteRawStringWithIndentation(Environment.NewLine);
Writer.WriteEndElement(4);
Writer.WriteEndElement();
}
One new Method in the XML-Writer:
public void WriteRawStringWithIndentation(string data, int indentation = 0)
{
for (int i = 0; i < indentation; i++)
{
this.TextWriter?.WriteWhitespace(" ");
}
this.TextWriter?.WriteString(data);
}
and extending the WriteEndElement method like this:
public void WriteEndElement(int indentation = 0)
{
StackInfo infoForCurrentXmlLevel = this.XmlStack.Pop();
if (_DoesProfileFitToCurrentProfile(infoForCurrentXmlLevel.Profile) && _IsNodeVisible())
{
for (int i = 0; i < indentation; i++)
{
this.TextWriter?.WriteWhitespace(" ");
}
this.TextWriter?.WriteEndElement();
}
}
But I am not completely happy with it (because of the fixed indentation values) - but it works.
I agree with your unhappiness :) Would it be possible to use the XmlStack for indention? And where is WriteEndElement() put if you don't add indention?
Without the manual indentation the result is the following:
<cac:PaymentTerms>
<cbc:Note>
#SKONTO#TAGE=14#PROZENT=0.00#BASISBETRAG=209.53#
</cbc:Note>
</cac:PaymentTerms>
Would it be possible to use the XmlStack for indention?
Surely. Then one could pass a bool that there should be an additional indentation which is 2 * this.XmlStack.Count()
...
I guess this is as slick as possible: https://github.com/stephanstapel/ZUGFeRD-csharp/commit/014e180fe001777851538c41808a78ecc384a35a Unfortunately it leaves open how to properly indent the closing tag:
How about modifying WriteEndElement() and take into account if the previous line was a raw line?
So when writing a raw text string setting a private boolean, that then could be evaluated in the WriteEndElement method (newline, indentation) and be reset?
So when writing a raw text string setting a private boolean, that then could be evaluated in the WriteEndElement method (newline, indentation) and be reset?
yes, like this. Will do that later.
Ignore the content that is displayed here, but is this the intended behaviour:
?
Code is committed. Does the requirement only count for UBL format or also for CII? Could you check this?
Just tested the CII-export and it is coming out like this (I did not insert it with a linebreak):
<ram:SpecifiedTradePaymentTerms>
<ram:Description>#SKONTO#TAGE=14#PROZENT=0.00#BASISBETRAG=219.80#
</ram:Description>
</ram:SpecifiedTradePaymentTerms>
But the validator did not say anything about this. So it just does not look very good...
@quotschmacher : thanks! Could you share the generation code here? I'd like to check if the library can do better.
@quotschmacher : I have checked in some code and added a test case (UBL only). Can you please check this?
@quotschmacher : thanks! Could you share the generation code here? I'd like to check if the library can do better.
no special generation code - simply adding
result.AddTradePaymentTerms(Invariant($"#SKONTO#TAGE={zahlungsziel}#PROZENT={skonto:F2}#BASISBETRAG={basisbetrag:F2}#"));
TradePaymentTerms than than outputting and CII-invoice.
@quotschmacher : I have checked in some code and added a test case (UBL only). Can you please check this?
I hope I will get it done tomorrow
Hmm, interesting. I implemented that output already here: https://github.com/stephanstapel/ZUGFeRD-csharp/blob/9279a5c66f965a77f5b017dea351f3f2d7e2d6af/ZUGFeRD/InvoiceDescriptor23CIIWriter.cs#L985-L1001
Wouldn't that work for UBL writer?
Hmm, interesting. I implemented that output already here:
Wouldn't that work for UBL writer?
basically yes. The new thing here is correct indention of the node content like here:
https://github.com/stephanstapel/ZUGFeRD-csharp/issues/388#issuecomment-2413207892
Um, OK. :-) Not that I would be bothered about indentation as it is XML, and primarily machine-read.
I get the point though, although it is not a technical constraint but optics for the eyes. Any XML viewer has a "beautify XML" feature.
I'd rather would have an option to completely avoid indentation and produces linear, minified XML output. Hence, we have visualizer or renderer to display the XML content for humans.
Cheers, JoKi
Um, OK. :-) Not that I would be bothered about indentation as it is XML, and primarily machine-read.
I get the point though, although it is not a technical constraint but optics for the eyes. Any XML viewer has a "beautify XML" feature.
I'd rather would have an option to completely avoid indentation and produces linear, minified XML output. Hence, we have visualizer or renderer to display the XML content for humans.
Cheers, JoKi
it appeared to be necessary for the validator.
Nope,
I tested CII output with 2-3 validators online and it passed. In case of an indentation-focused format like YAML I could understand. However, it's XML and could be without any indentation at all.
Cheers, JoKi
What I painfully noticed is that the sequence of elements is of importance which led to the weird way of implementation in the CII writer regarding the DueDate.
Hi,
I switch to XmlWriter as a base class for generating XML. I didn't push the change yet, but if you could do this:
could you solve the problem mentioned above?
The new line needs to be at the end only. The terminator is "#{Environment. NewLine}".
Just tested the CII-export and it is coming out like this (I did not insert it with a linebreak):
<ram:SpecifiedTradePaymentTerms> <ram:Description>#SKONTO#TAGE=14#PROZENT=0.00#BASISBETRAG=219.80# </ram:Description> </ram:SpecifiedTradePaymentTerms>
But the validator did not say anything about this. So it just does not look very good...
Exactly, that's the code I contributed. The indentation does not matter.
Something else.
If you take care of the indentation to look good, it would be part of the actual node value.
Meaning, instead of "...#{newline}"
the resulting value would include the spaces of the indentation from the next line, and read like this "...#{newline} "
which seems to be more likely problematic than an optical glitch for humans.
To my opinion, this should be wrapped inside a CDATA section in order to cater properly for all value and optical constraints. And it would be clear.
<ram:SpecifiedTradePaymentTerms>
<ram:Description><![CDATA[#SKONTO#TAGE=14#PROZENT=0.00#BASISBETRAG=219.80#
]]>
</ram:Description>
</ram:SpecifiedTradePaymentTerms>
Reference: https://developer.mozilla.org/en-US/docs/Web/API/CDATASection
Should the UBL-Writer respect Business Rules?
So it should look like
and the actual implementation produces:
If I add a verbatim string with line break at the beginning and end, the result looks like
So the line break at the end is ignored.
Do you think this is a thing? Is the Writer used able to produce this?