Repository: horstoeko/zugferd (php)

Issue:
[FEATURE] Allow adding empty ShipTo nodes to the document without enforcing a TradeParty name
**Describe the feature**

This Issue is a follow-up to #101 

I want to create an invoice with a tax exemption for intra-community supply.
The business rule BR-IC-12 states that, therefore, the country code of the ship to address (BT-80) must be set in `/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:PostalTradeAddress/ram:CountryID`

The method `setDocumentShipTo` forces me to provide a name of the `ShipToTradeParty`. 
However, according to the ZUGFeRD and X-Rechnung specifications, these fields shall be used if the name is not equal to the buyer's name.

> Das Informationselement ist zu verwenden, wenn der Empfänger vom Erwerber abweicht.
> _X-Rechnung Spec_

> Shall be used if the Deliver to party is different from the Buyer.
> _Factur-X Spec_

**Expected behavior**

Provide a method like `setDocumentShipToAddress` that uses an empty TradeParty if `getShipToTradeParty` returns `null`.

See `src/ZugferdDocumentBuilder.php:1016`

**Additional context**
We could work around this by providing the same name as the buyer.
It might be possible that we get a validation error then.


Pull request description:
Issue 189
# Description

Allow empty value for name and ID for participants

Fixes #189 

## Type of change

- [X] New feature (non-breaking change which adds functionality)

# Checklist:

- [X] My code follows the style guidelines of this project
- [X] I have performed a self-review of my own code
- [X] I have commented my code, particularly in hard-to-understand areas
- [X] I have made corresponding changes to the documentation
- [X] My changes generate no new warnings
- [X] I have added tests that prove my fix is effective or that my feature works
- [X] New and existing unit tests pass locally with my changes
- [X] Any dependent changes have been merged and published in downstream modules

Patch:
diff --git a/src/ZugferdDocumentBuilder.php b/src/ZugferdDocumentBuilder.php
index eddcf7c..a9b2127 100644
--- a/src/ZugferdDocumentBuilder.php
+++ b/src/ZugferdDocumentBuilder.php
@@ -860,14 +860,14 @@ class ZugferdDocumentBuilder extends ZugferdDocument
     /**
      * Ship-To
      *
-     * @param  string      $name        __BT-70, From BASIC WL__ The name of the party to whom the goods are being delivered or for whom the services are being performed. Must be used if the recipient of the goods or services is not the same as the buyer.
+     * @param  string|null $name        __BT-70, From BASIC WL__ The name of the party to whom the goods are being delivered or for whom the services are being performed. Must be used if the recipient of the goods or services is not the same as the buyer.
      * @param  string|null $id          __BT-71, From BASIC WL__ An identifier for the place where the goods are delivered or where the services are provided. Multiple IDs can be assigned or specified. They can be differentiated by using different identification schemes. If no scheme is given, it should be known to the buyer and seller, e.g. a previously exchanged identifier assigned by the buyer or seller.
      * @param  string|null $description __BT-, From __ Further legal information that is relevant for the party
      * @return ZugferdDocumentBuilder
      */
-    public function setDocumentShipTo(?string $name, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
+    public function setDocumentShipTo(?string $name = null, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
     {
-        $shipToTradeParty = $this->getObjectHelper()->getTradeParty($name, $id, $description);
+        $shipToTradeParty = $this->getObjectHelper()->getTradePartyAllowEmpty($name, $id, $description);
         $this->getObjectHelper()->tryCall($this->headerTradeDelivery, "setShipToTradeParty", $shipToTradeParty);
         return $this;
     }
@@ -989,14 +989,14 @@ class ZugferdDocumentBuilder extends ZugferdDocument
     /**
      * Detailed information on the different end recipient
      *
-     * @param  string      $name        __BT-X-164, From EXTENDED__ Name or company name of the different end recipient
+     * @param  string|null $name        __BT-X-164, From EXTENDED__ Name or company name of the different end recipient
      * @param  string|null $id          __BT-X-162, From EXTENDED__ Identification of the different end recipient. Multiple IDs can be assigned or specified. They can be differentiated by using different identification schemes.
      * @param  string|null $description __BT-, From __ Further legal information that is relevant for the different end recipient
      * @return ZugferdDocumentBuilder
      */
-    public function setDocumentUltimateShipTo(string $name, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
+    public function setDocumentUltimateShipTo(?string $name = null, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
     {
-        $shipToTradeParty = $this->getObjectHelper()->getTradeParty($name, $id, $description);
+        $shipToTradeParty = $this->getObjectHelper()->getTradePartyAllowEmpty($name, $id, $description);
         $this->getObjectHelper()->tryCall($this->headerTradeDelivery, "setUltimateShipToTradeParty", $shipToTradeParty);
         return $this;
     }
@@ -1118,14 +1118,14 @@ class ZugferdDocumentBuilder extends ZugferdDocument
     /**
      * Set detailed information of the deviating consignor party
      *
-     * @param  string      $name        __BT-X-183, From EXTENDED__ The name of the party
+     * @param  string|null $name        __BT-X-183, From EXTENDED__ The name of the party
      * @param  string|null $id          __BT-X-181, From EXTENDED__ An identifier for the party. Multiple IDs can be assigned or specified. They can be differentiated by using different identification schemes. If no scheme is given, it should  be known to the buyer and seller, e.g. a previously exchanged identifier assigned by the buyer or seller.
      * @param  string|null $description __BT-, From __ Further legal information that is relevant for the party
      * @return ZugferdDocumentBuilder
      */
-    public function setDocumentShipFrom(string $name, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
+    public function setDocumentShipFrom(?string $name = null, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
     {
-        $shipToTradeParty = $this->getObjectHelper()->getTradeParty($name, $id, $description);
+        $shipToTradeParty = $this->getObjectHelper()->getTradePartyAllowEmpty($name, $id, $description);
         $this->getObjectHelper()->tryCall($this->headerTradeDelivery, "setShipFromTradeParty", $shipToTradeParty);
         return $this;
     }
@@ -2667,15 +2667,15 @@ class ZugferdDocumentBuilder extends ZugferdDocument
     /**
      * Set detailed information on the different ship-to party at position level
      *
-     * @param  string      $name         __BT-X-50, From EXTENDED__ The name of the party to whom the goods are being delivered or for whom the services are being performed. Must be used if the recipient of the goods or services is not the same as the buyer.
+     * @param  string|null $name         __BT-X-50, From EXTENDED__ The name of the party to whom the goods are being delivered or for whom the services are being performed. Must be used if the recipient of the goods or services is not the same as the buyer.
      * @param  string|null $id           __BT-X-48, From EXTENDED__ An identifier for the place where the goods are delivered or where the services are provided. Multiple IDs can be assigned or specified. They can be differentiated by using different identification schemes. If no scheme is given, it should be known to the buyer and seller, e.g. a previously exchanged identifier assigned by the buyer or seller.
      * @param  string|null $description  __BT-, From __ Further legal information that is relevant for the party (Obsolete)
      * @return ZugferdDocumentBuilder
      */
-    public function setDocumentPositionShipTo(string $name, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
+    public function setDocumentPositionShipTo(?string $name = null, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
     {
         $positiondelivery = $this->getObjectHelper()->tryCallAndReturn($this->currentPosition, "getSpecifiedLineTradeDelivery");
-        $shipToTradeParty = $this->getObjectHelper()->getTradeParty($name, $id, $description);
+        $shipToTradeParty = $this->getObjectHelper()->getTradePartyAllowEmpty($name, $id, $description);
         $this->getObjectHelper()->tryCall($positiondelivery, "setShipToTradeParty", $shipToTradeParty);
         return $this;
     }
@@ -2790,15 +2790,15 @@ class ZugferdDocumentBuilder extends ZugferdDocument
     /**
      * Detailed information on the different end recipient on position level
      *
-     * @param  string      $name         __BT-X-69, From EXTENDED__ The name of the party to whom the goods are being delivered or for whom the services are being performed. Must be used if the recipient of the goods or services is not the same as the buyer.
+     * @param  string|null $name         __BT-X-69, From EXTENDED__ The name of the party to whom the goods are being delivered or for whom the services are being performed. Must be used if the recipient of the goods or services is not the same as the buyer.
      * @param  string|null $id           __BT-X-67, From EXTENDED__ An identifier for the party Multiple IDs can be assigned or specified. They can be differentiated by using different identification schemes. If no scheme is given, it should be known to the buyer and seller, e.g. a previously exchanged identifier assigned by the buyer or seller.
      * @param  string|null $description  __BT-, From __ Further legal information that is relevant for the party (Obsolete)
      * @return ZugferdDocumentBuilder
      */
-    public function setDocumentPositionUltimateShipTo(string $name, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
+    public function setDocumentPositionUltimateShipTo(?string $name = null, ?string $id = null, ?string $description = null): ZugferdDocumentBuilder
     {
         $positiondelivery = $this->getObjectHelper()->tryCallAndReturn($this->currentPosition, "getSpecifiedLineTradeDelivery");
-        $shipToTradeParty = $this->getObjectHelper()->getTradeParty($name, $id, $description);
+        $shipToTradeParty = $this->getObjectHelper()->getTradePartyAllowEmpty($name, $id, $description);
         $this->getObjectHelper()->tryCall($positiondelivery, "setUltimateShipToTradeParty", $shipToTradeParty);
         return $this;
     }
diff --git a/src/ZugferdObjectHelper.php b/src/ZugferdObjectHelper.php
index e26da64..8ea7b94 100644
--- a/src/ZugferdObjectHelper.php
+++ b/src/ZugferdObjectHelper.php
@@ -598,7 +598,7 @@ class ZugferdObjectHelper
     }
 
     /**
-     * Tradeparty type^^
+     * Tradeparty type
      *
      * @param  string|null $name
      * @param  string|null $ID
@@ -611,6 +611,19 @@ class ZugferdObjectHelper
             return null;
         }
 
+        return $this->getTradePartyAllowEmpty($name, $ID, $description);
+    }
+
+    /**
+     * Tradeparty type (allow all nulls)
+     *
+     * @param  string|null $name
+     * @param  string|null $ID
+     * @param  string|null $description
+     * @return object|null
+     */
+    public function getTradePartyAllowEmpty(?string $name = null, ?string $ID = null, ?string $description = null): ?object
+    {
         $tradeParty = $this->createClassInstance('ram\TradePartyType');
 
         $this->tryCall($tradeParty, "addToID", $this->getIdType($ID));


Test patch:
diff --git a/tests/testcases/BuilderEn16931Test.php b/tests/testcases/BuilderEn16931Test.php
index ec412b6..668e059 100644
--- a/tests/testcases/BuilderEn16931Test.php
+++ b/tests/testcases/BuilderEn16931Test.php
@@ -587,6 +587,29 @@ class BuilderEn16931Test extends TestCase
         $this->assertXPathNotExistsWithIndex('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:ProductEndUserTradeParty/ram:DefinedTradeContact/ram:EmailURIUniversalCommunication/ram:URIID', 1);
     }
 
+    public function testSetDocumentShipToAllEmpty(): void
+    {
+        (self::$document)->setDocumentShipTo();
+
+        $this->disableRenderXmlContent();
+        $this->assertXPathExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:Name');
+    }
+
+    public function testAddDocumentShipTolAllEmptyId(): void
+    {
+        $this->assertXPathExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:Name');
+
+        (self::$document)->addDocumentShipTolId('549911');
+
+        $this->disableRenderXmlContent();
+        $this->assertXPathValueWithIndex('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID', 0, "549911");
+        $this->assertXPathNotExistsWithIndex('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID', 1);
+    }
+
     public function testSetDocumentShipTo(): void
     {
         (self::$document)->setDocumentShipTo("Kunden AG Mitte", "549910");
diff --git a/tests/testcases/BuilderExtendedTest.php b/tests/testcases/BuilderExtendedTest.php
index 37a424a..a462648 100644
--- a/tests/testcases/BuilderExtendedTest.php
+++ b/tests/testcases/BuilderExtendedTest.php
@@ -596,6 +596,29 @@ class BuilderExtendedTest extends TestCase
         $this->assertXPathNotExistsWithIndex('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:ProductEndUserTradeParty/ram:DefinedTradeContact/ram:EmailURIUniversalCommunication/ram:URIID', 2);
     }
 
+    public function testSetDocumentShipToAllEmpty(): void
+    {
+        (self::$document)->setDocumentShipTo();
+
+        $this->disableRenderXmlContent();
+        $this->assertXPathExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:Name');
+    }
+
+    public function testAddDocumentShipTolAllEmptyId(): void
+    {
+        $this->assertXPathExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:Name');
+
+        (self::$document)->addDocumentShipTolId('549911');
+
+        $this->disableRenderXmlContent();
+        $this->assertXPathValueWithIndex('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID', 0, "549911");
+        $this->assertXPathNotExistsWithIndex('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID', 1);
+    }
+
     public function testSetDocumentShipTo(): void
     {
         (self::$document)->setDocumentShipTo("Kunden AG Mitte", "549910");
diff --git a/tests/testcases/BuilderMinimumTest.php b/tests/testcases/BuilderMinimumTest.php
index 44d22a6..f59703d 100644
--- a/tests/testcases/BuilderMinimumTest.php
+++ b/tests/testcases/BuilderMinimumTest.php
@@ -589,6 +589,29 @@ class BuilderMinimumTest extends TestCase
         $this->assertXPathNotExistsWithIndex('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:ProductEndUserTradeParty/ram:DefinedTradeContact/ram:EmailURIUniversalCommunication/ram:URIID', 1);
     }
 
+    public function testSetDocumentShipToAllEmpty(): void
+    {
+        (self::$document)->setDocumentShipTo();
+
+        $this->disableRenderXmlContent();
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:Name');
+    }
+
+    public function testAddDocumentShipTolAllEmptyId(): void
+    {
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:Name');
+
+        (self::$document)->addDocumentShipTolId('549911');
+
+        $this->disableRenderXmlContent();
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:ID');
+        $this->assertXPathNotExists('/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:Name');
+    }
+
     public function testSetDocumentShipTo(): void
     {
         (self::$document)->setDocumentShipTo("Kunden AG Mitte", "549910");
diff --git a/tests/testcases/ObjectHelperEn16931Test.php b/tests/testcases/ObjectHelperEn16931Test.php
index 597dc77..398bebb 100644
--- a/tests/testcases/ObjectHelperEn16931Test.php
+++ b/tests/testcases/ObjectHelperEn16931Test.php
@@ -652,6 +652,34 @@ class ObjectHelperEn16931Test extends TestCase
         $this->assertNull($tradeparty);
     }
 
+    public function testGetTradePartyAllValuesWithAllowEmpty(): void
+    {
+        /**
+         * @var \horstoeko\zugferd\entities\en16931\ram\TradePartyType
+         */
+        $tradeparty = self::$objectHelper->getTradePartyAllowEmpty("name", "id", "description");
+        $this->assertEquals("name", $tradeparty->getName());
+        $this->assertIsArray($tradeparty->getID());
+        $this->assertArrayHasKey(0, $tradeparty->getID());
+        $this->assertEquals("id", $tradeparty->getID()[0]);
+        $this->assertEquals("description", $tradeparty->getDescription());
+    }
+
+    public function testGetTradePartyNullValuesWithAllowEmpty(): void
+    {
+        /**
+         * @var \horstoeko\zugferd\entities\en16931\ram\TradePartyType
+         */
+        $tradeparty = self::$objectHelper->getTradePartyAllowEmpty(null, null, null);
+        $this->assertNotNull($tradeparty);
+        $this->assertNull($tradeparty->getName());
+        $this->assertEquals("", $tradeparty->getName());
+        $this->assertIsArray($tradeparty->getID());
+        $this->assertArrayNotHasKey(0, $tradeparty->getID());
+        $this->assertNull($tradeparty->getDescription());
+        $this->assertEquals("", $tradeparty->getDescription());
+    }
+
     public function testGetTradeAddressAllValues(): void
     {
         /**
diff --git a/tests/testcases/ObjectHelperExtendedTest.php b/tests/testcases/ObjectHelperExtendedTest.php
index c8649a1..be6fc73 100644
--- a/tests/testcases/ObjectHelperExtendedTest.php
+++ b/tests/testcases/ObjectHelperExtendedTest.php
@@ -654,6 +654,34 @@ class ObjectHelperExtendedTest extends TestCase
         $this->assertNull($tradeparty);
     }
 
+    public function testGetTradePartyAllValuesWithAllowEmpty(): void
+    {
+        /**
+         * @var \horstoeko\zugferd\entities\extended\ram\TradePartyType
+         */
+        $tradeparty = self::$objectHelper->getTradePartyAllowEmpty("name", "id", "description");
+        $this->assertEquals("name", $tradeparty->getName());
+        $this->assertIsArray($tradeparty->getID());
+        $this->assertArrayHasKey(0, $tradeparty->getID());
+        $this->assertEquals("id", $tradeparty->getID()[0]);
+        $this->assertEquals("description", $tradeparty->getDescription());
+    }
+
+    public function testGetTradePartyNullValuesWithAllowEmpty(): void
+    {
+        /**
+         * @var \horstoeko\zugferd\entities\extended\ram\TradePartyType
+         */
+        $tradeparty = self::$objectHelper->getTradePartyAllowEmpty(null, null, null);
+        $this->assertNotNull($tradeparty);
+        $this->assertNull($tradeparty->getName());
+        $this->assertEquals("", $tradeparty->getName());
+        $this->assertIsArray($tradeparty->getID());
+        $this->assertArrayNotHasKey(0, $tradeparty->getID());
+        $this->assertNull($tradeparty->getDescription());
+        $this->assertEquals("", $tradeparty->getDescription());
+    }
+
     public function testGetTradeAddressAllValues(): void
     {
         /**
diff --git a/tests/testcases/PdfReaderEn16931AllowanceChargeTest.php b/tests/testcases/PdfReaderEn16931AllowanceChargeTest.php
index 31f4b04..92634df 100644
--- a/tests/testcases/PdfReaderEn16931AllowanceChargeTest.php
+++ b/tests/testcases/PdfReaderEn16931AllowanceChargeTest.php
@@ -317,9 +317,13 @@ class PdfReaderEn16931AllowanceChargeTest extends TestCase
     public function testDocumentShipToGeneral(): void
     {
         self::$document->getDocumentShipTo($shiptoname, $shiptoids, $shiptodescription);
+        $this->assertNotNull($shiptoname);
+        $this->assertIsString($shiptoname);
         $this->assertEquals("", $shiptoname);
         $this->assertIsArray($shiptoids);
         $this->assertEmpty($shiptoids);
+        $this->assertNotNull($shiptodescription);
+        $this->assertIsString($shiptodescription);
         $this->assertEquals("", $shiptodescription);
     }
 
diff --git a/tests/testcases/PdfReaderEn16931Test.php b/tests/testcases/PdfReaderEn16931Test.php
index 65a75f8..490903c 100644
--- a/tests/testcases/PdfReaderEn16931Test.php
+++ b/tests/testcases/PdfReaderEn16931Test.php
@@ -309,9 +309,13 @@ class PdfReaderEn16931Test extends TestCase
     public function testDocumentShipToGeneral(): void
     {
         self::$document->getDocumentShipTo($shiptoname, $shiptoids, $shiptodescription);
+        $this->assertNotNull($shiptoname);
+        $this->assertIsString($shiptoname);
         $this->assertEquals("", $shiptoname);
         $this->assertIsArray($shiptoids);
         $this->assertEmpty($shiptoids);
+        $this->assertNotNull($shiptodescription);
+        $this->assertIsString($shiptodescription);
         $this->assertEquals("", $shiptodescription);
     }
 
diff --git a/tests/testcases/PdfReaderMinimumTest.php b/tests/testcases/PdfReaderMinimumTest.php
index f146619..945d11a 100644
--- a/tests/testcases/PdfReaderMinimumTest.php
+++ b/tests/testcases/PdfReaderMinimumTest.php
@@ -282,9 +282,13 @@ class PdfReaderMinimumTest extends TestCase
     public function testDocumentShipToGeneral(): void
     {
         self::$document->getDocumentShipTo($shiptoname, $shiptoids, $shiptodescription);
+        $this->assertNotNull($shiptoname);
+        $this->assertIsString($shiptoname);
         $this->assertEquals("", $shiptoname);
         $this->assertIsArray($shiptoids);
         $this->assertEmpty($shiptoids);
+        $this->assertNotNull($shiptodescription);
+        $this->assertIsString($shiptodescription);
         $this->assertEquals("", $shiptodescription);
     }
 
diff --git a/tests/testcases/PdfReaderXRechnungTest.php b/tests/testcases/PdfReaderXRechnungTest.php
index a1cd285..756c135 100644
--- a/tests/testcases/PdfReaderXRechnungTest.php
+++ b/tests/testcases/PdfReaderXRechnungTest.php
@@ -309,9 +309,13 @@ class PdfReaderXRechnungTest extends TestCase
     public function testDocumentShipToGeneral(): void
     {
         self::$document->getDocumentShipTo($shiptoname, $shiptoids, $shiptodescription);
+        $this->assertNotNull($shiptoname);
+        $this->assertIsString($shiptoname);
         $this->assertEquals("", $shiptoname);
         $this->assertIsArray($shiptoids);
         $this->assertEmpty($shiptoids);
+        $this->assertNotNull($shiptodescription);
+        $this->assertIsString($shiptodescription);
         $this->assertEquals("", $shiptodescription);
     }
 
diff --git a/tests/testcases/ReaderBasicTest.php b/tests/testcases/ReaderBasicTest.php
index ec86801..8e74745 100644
--- a/tests/testcases/ReaderBasicTest.php
+++ b/tests/testcases/ReaderBasicTest.php
@@ -321,9 +321,13 @@ class ReaderBasicTest extends TestCase
     public function testDocumentShipToGeneral(): void
     {
         self::$document->getDocumentShipTo($shiptoname, $shiptoids, $shiptodescription);
+        $this->assertNotNull($shiptoname);
+        $this->assertIsString($shiptoname);
         $this->assertEquals("", $shiptoname);
         $this->assertIsArray($shiptoids);
         $this->assertEmpty($shiptoids);
+        $this->assertNotNull($shiptodescription);
+        $this->assertIsString($shiptodescription);
         $this->assertEquals("", $shiptodescription);
     }
 
diff --git a/tests/testcases/ReaderEn16931AllowanceChargeTest.php b/tests/testcases/ReaderEn16931AllowanceChargeTest.php
index 1469814..9269705 100644
--- a/tests/testcases/ReaderEn16931AllowanceChargeTest.php
+++ b/tests/testcases/ReaderEn16931AllowanceChargeTest.php
@@ -332,9 +332,13 @@ class ReaderEn16931AllowanceChargeTest extends TestCase
     public function testDocumentShipToGeneral(): void
     {
         self::$document->getDocumentShipTo($shiptoname, $shiptoids, $shiptodescription);
+        $this->assertNotNull($shiptoname);
+        $this->assertIsString($shiptoname);
         $this->assertEquals("", $shiptoname);
         $this->assertIsArray($shiptoids);
         $this->assertEmpty($shiptoids);
+        $this->assertNotNull($shiptodescription);
+        $this->assertIsString($shiptodescription);
         $this->assertEquals("", $shiptodescription);
     }
 
diff --git a/tests/testcases/ReaderEn16931Test.php b/tests/testcases/ReaderEn16931Test.php
index 2c8618b..32561ff 100644
--- a/tests/testcases/ReaderEn16931Test.php
+++ b/tests/testcases/ReaderEn16931Test.php
@@ -324,9 +324,13 @@ class ReaderEn16931Test extends TestCase
     public function testDocumentShipToGeneral(): void
     {
         self::$document->getDocumentShipTo($shiptoname, $shiptoids, $shiptodescription);
+        $this->assertNotNull($shiptoname);
+        $this->assertIsString($shiptoname);
         $this->assertEquals("", $shiptoname);
         $this->assertIsArray($shiptoids);
         $this->assertEmpty($shiptoids);
+        $this->assertNotNull($shiptodescription);
+        $this->assertIsString($shiptodescription);
         $this->assertEquals("", $shiptodescription);
     }
 
diff --git a/tests/testcases/ReaderXRechnungTest.php b/tests/testcases/ReaderXRechnungTest.php
index 0a6b963..d33f4c4 100644
--- a/tests/testcases/ReaderXRechnungTest.php
+++ b/tests/testcases/ReaderXRechnungTest.php
@@ -325,9 +325,13 @@ class ReaderXRechnungTest extends TestCase
     public function testDocumentShipToGeneral(): void
     {
         self::$document->getDocumentShipTo($shiptoname, $shiptoids, $shiptodescription);
+        $this->assertNotNull($shiptoname);
+        $this->assertIsString($shiptoname);
         $this->assertEquals("", $shiptoname);
         $this->assertIsArray($shiptoids);
         $this->assertEmpty($shiptoids);
+        $this->assertNotNull($shiptodescription);
+        $this->assertIsString($shiptodescription);
         $this->assertEquals("", $shiptodescription);
     }