Repository: horstoeko/zugferd (php)

Issue:
[BUG] function toDateTime returns DateTime|null but DateTime::createFromFormat could return DateTime|false ...
Hello Daniel,
there is a little bug today into parsing XML with your great lib ...

```
  <ram:IssueDateTime>
    <udt:DateTimeString format="102">
      20241011
    </udt:DateTimeString>
  </ram:IssueDateTime>
```

Then in that race condition i have that error

```
Return value of horstoeko\zugferd\ZugferdObjectHelper::toDateTime() must be an instance of DateTime or null, bool returned
```

cheers
(Éric from France)

Pull request description:
#206 Fix DateTime-Handling (strings with linebreaks)
# Description

Fixes handling of datetime-values with linebreaks

Fixes #206 

## Type of change

Please delete options that are not relevant.

- [X] Bug fix (non-breaking change which fixes an issue)

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

- [X] Issue206Test


Patch:
diff --git a/build/phpunit.xml b/build/phpunit.xml
index 433f7bb..80ff106 100644
--- a/build/phpunit.xml
+++ b/build/phpunit.xml
@@ -55,6 +55,7 @@
             <file>../tests/testcases/issues/Issue43Test.php</file>
             <file>../tests/testcases/issues/Issue104Test.php</file>
             <file>../tests/testcases/issues/Issue113Test.php</file>
+            <file>../tests/testcases/issues/Issue206Test.php</file>
         </testsuite>
     </testsuites>
     <coverage processUncoveredFiles="true">
diff --git a/src/ZugferdObjectHelper.php b/src/ZugferdObjectHelper.php
index 36536f8..94688de 100644
--- a/src/ZugferdObjectHelper.php
+++ b/src/ZugferdObjectHelper.php
@@ -1437,6 +1437,9 @@ class ZugferdObjectHelper
         if (self::isNullOrEmpty($dateTimeString) || self::isNullOrEmpty($format)) {
             return null;
         }
+
+        $dateTimeString = trim($dateTimeString);
+
         if ($format == "102") {
             return DateTime::createFromFormat("Ymd", $dateTimeString);
         } elseif ($format == "101") {


Test patch:
diff --git a/tests/assets/xml_issue_206.xml b/tests/assets/xml_issue_206.xml
new file mode 100644
index 0000000..a1b3ec6
--- /dev/null
+++ b/tests/assets/xml_issue_206.xml
@@ -0,0 +1,123 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<rsm:CrossIndustryInvoice xmlns:a="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:10" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
+    <rsm:ExchangedDocumentContext>
+        <ram:GuidelineSpecifiedDocumentContextParameter>
+            <ram:ID>urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic</ram:ID>
+        </ram:GuidelineSpecifiedDocumentContextParameter>
+    </rsm:ExchangedDocumentContext>
+    <rsm:ExchangedDocument>
+        <ram:ID>471102</ram:ID>
+        <ram:TypeCode>380</ram:TypeCode>
+        <ram:IssueDateTime>
+            <udt:DateTimeString format="102">
+                20200305
+            </udt:DateTimeString>
+        </ram:IssueDateTime>
+        <ram:IncludedNote>
+            <ram:Content>Rechnung gemäß Bestellung vom 01.03.2020.</ram:Content>
+        </ram:IncludedNote>
+        <ram:IncludedNote>
+            <ram:Content>Lieferant GmbH
+                Lieferantenstraße 20
+                80333 München
+                Deutschland
+                Geschäftsführer: Hans Muster
+                Handelsregisternummer: H A 123
+            </ram:Content>
+        </ram:IncludedNote>
+        <ram:IncludedNote>
+            <ram:Content>Unsere GLN: 4000001123452
+                Ihre GLN: 4000001987658
+                Ihre Kundennummer: GE2020211
+                Zahlbar innerhalb 30 Tagen netto bis 04.04.2020, 3% Skonto innerhalb 10 Tagen bis 15.03.2020.
+            </ram:Content>
+        </ram:IncludedNote>
+    </rsm:ExchangedDocument>
+    <rsm:SupplyChainTradeTransaction>
+        <ram:IncludedSupplyChainTradeLineItem>
+            <ram:AssociatedDocumentLineDocument>
+                <ram:LineID>1</ram:LineID>
+            </ram:AssociatedDocumentLineDocument>
+            <ram:SpecifiedTradeProduct>
+                <ram:GlobalID schemeID="0160">4012345001235</ram:GlobalID>
+                <ram:Name>GTIN: 4012345001235, Unsere Art.-Nr.: TB100A4, Trennblätter A4</ram:Name>
+            </ram:SpecifiedTradeProduct>
+            <ram:SpecifiedLineTradeAgreement>
+                <ram:NetPriceProductTradePrice>
+                    <ram:ChargeAmount>9.90</ram:ChargeAmount>
+                </ram:NetPriceProductTradePrice>
+            </ram:SpecifiedLineTradeAgreement>
+            <ram:SpecifiedLineTradeDelivery>
+                <ram:BilledQuantity unitCode="H87">20.0000</ram:BilledQuantity>
+            </ram:SpecifiedLineTradeDelivery>
+            <ram:SpecifiedLineTradeSettlement>
+                <ram:ApplicableTradeTax>
+                    <ram:TypeCode>VAT</ram:TypeCode>
+                    <ram:CategoryCode>S</ram:CategoryCode>
+                    <ram:RateApplicablePercent>19</ram:RateApplicablePercent>
+                </ram:ApplicableTradeTax>
+                <ram:SpecifiedTradeSettlementLineMonetarySummation>
+                    <ram:LineTotalAmount>198.00</ram:LineTotalAmount>
+                </ram:SpecifiedTradeSettlementLineMonetarySummation>
+            </ram:SpecifiedLineTradeSettlement>
+        </ram:IncludedSupplyChainTradeLineItem>
+        <ram:ApplicableHeaderTradeAgreement>
+            <ram:SellerTradeParty>
+                <ram:Name>Lieferant GmbH</ram:Name>
+                <ram:PostalTradeAddress>
+                    <ram:PostcodeCode>80333</ram:PostcodeCode>
+                    <ram:LineOne>Lieferantenstraße 20</ram:LineOne>
+                    <ram:CityName>München</ram:CityName>
+                    <ram:CountryID>DE</ram:CountryID>
+                </ram:PostalTradeAddress>
+                <ram:SpecifiedTaxRegistration>
+                    <ram:ID schemeID="FC">201/113/40209</ram:ID>
+                </ram:SpecifiedTaxRegistration>
+                <ram:SpecifiedTaxRegistration>
+                    <ram:ID schemeID="VA">DE123456789</ram:ID>
+                </ram:SpecifiedTaxRegistration>
+            </ram:SellerTradeParty>
+            <ram:BuyerTradeParty>
+                <ram:Name>Kunden AG Mitte</ram:Name>
+                <ram:PostalTradeAddress>
+                    <ram:PostcodeCode>69876</ram:PostcodeCode>
+                    <ram:LineOne>Hans Muster</ram:LineOne>
+                    <ram:LineTwo>Kundenstraße 15</ram:LineTwo>
+                    <ram:CityName>Frankfurt</ram:CityName>
+                    <ram:CountryID>DE</ram:CountryID>
+                </ram:PostalTradeAddress>
+            </ram:BuyerTradeParty>
+        </ram:ApplicableHeaderTradeAgreement>
+        <ram:ApplicableHeaderTradeDelivery>
+            <ram:ActualDeliverySupplyChainEvent>
+                <ram:OccurrenceDateTime>
+                    <udt:DateTimeString format="102">20200305</udt:DateTimeString>
+                </ram:OccurrenceDateTime>
+            </ram:ActualDeliverySupplyChainEvent>
+        </ram:ApplicableHeaderTradeDelivery>
+        <ram:ApplicableHeaderTradeSettlement>
+            <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
+            <ram:ApplicableTradeTax>
+                <ram:CalculatedAmount>37.62</ram:CalculatedAmount>
+                <ram:TypeCode>VAT</ram:TypeCode>
+                <ram:BasisAmount>198.00</ram:BasisAmount>
+                <ram:CategoryCode>S</ram:CategoryCode>
+                <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
+            </ram:ApplicableTradeTax>
+            <ram:SpecifiedTradePaymentTerms>
+                <ram:DueDateDateTime>
+                    <udt:DateTimeString format="102">20200404</udt:DateTimeString>
+                </ram:DueDateDateTime>
+            </ram:SpecifiedTradePaymentTerms>
+            <ram:SpecifiedTradeSettlementHeaderMonetarySummation>
+                <ram:LineTotalAmount>198.00</ram:LineTotalAmount>
+                <ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
+                <ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
+                <ram:TaxBasisTotalAmount>198.00</ram:TaxBasisTotalAmount>
+                <ram:TaxTotalAmount currencyID="EUR">37.62</ram:TaxTotalAmount>
+                <ram:GrandTotalAmount>235.62</ram:GrandTotalAmount>
+                <ram:DuePayableAmount>235.62</ram:DuePayableAmount>
+            </ram:SpecifiedTradeSettlementHeaderMonetarySummation>
+        </ram:ApplicableHeaderTradeSettlement>
+    </rsm:SupplyChainTradeTransaction>
+</rsm:CrossIndustryInvoice>
\ No newline at end of file
diff --git a/tests/testcases/issues/Issue206Test.php b/tests/testcases/issues/Issue206Test.php
new file mode 100644
index 0000000..279d7b3
--- /dev/null
+++ b/tests/testcases/issues/Issue206Test.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace horstoeko\zugferd\tests\testcases\issues;
+
+use horstoeko\zugferd\tests\TestCase;
+use horstoeko\zugferd\ZugferdDocumentReader;
+
+class Issue206Test extends TestCase
+{
+    public function testDateTimeString(): void
+    {
+        $document = ZugferdDocumentReader::readAndGuessFromFile(dirname(__FILE__) . '/../../assets/xml_issue_206.xml');
+        $document->getDocumentInformation(
+            $documentNo,
+            $documentTypeCode,
+            $documentDate,
+            $invoiceCurrency,
+            $taxCurrency,
+            $documentName,
+            $documentLanguage,
+            $effectiveSpecifiedPeriod
+        );
+
+        $this->assertEquals((\DateTime::createFromFormat('Ymd', '20200305'))->format('Ymd'), $documentDate->format('Ymd'));
+    }
+}