Repository: horstoeko/zugferd (php)

Issue:
[QUESTION] Accessing Node ReceivableSpecifiedTradeAccountingAccount
First of all I wan't to thank you from the bottom of my heart for your commitment and this awesome project. 

My question is: Can you estimate when the functionality around _TradeAccountingAccount_ will be implemented?

Specially the Field _ReceivableSpecifiedTradeAccountingAccount_:

```
...
<ram:SpecifiedLineTradeSettlement>
    ...
    <ram:ReceivableSpecifiedTradeAccountingAccount>
        <ram:ID>1337</ram:ID>
    </ram:ReceivableSpecifiedTradeAccountingAccount>
    ...
</ram:SpecifiedLineTradeSettlement>
...
```

Example: [factur-x.zip](https://github.com/user-attachments/files/19179807/factur-x.zip)

You've commented your code as a reminder:
ZugferdDocumentReader.php (Line: 3923)

Best regards

Pull request description:
[ENH] #270 Added methods to read ReceivableSpecifiedTradeAccountingAccounts on document- and position-level
# Description

Added methods to read ReceivableSpecifiedTradeAccountingAccounts on document- and position-level

Fixes #270 

## Type of change

- [X] New feature (non-breaking change which adds functionality)


Patch:
diff --git a/build/phpunit.xml b/build/phpunit.xml
index e9533a8..39767a6 100644
--- a/build/phpunit.xml
+++ b/build/phpunit.xml
@@ -61,6 +61,7 @@
             <file>../tests/testcases/issues/Issue113Test.php</file>
             <file>../tests/testcases/issues/Issue206Test.php</file>
             <file>../tests/testcases/issues/Issue268Test.php</file>
+            <file>../tests/testcases/issues/Issue270Test.php</file>
         </testsuite>
     </testsuites>
     <coverage processUncoveredFiles="true">
diff --git a/src/ZugferdDocumentReader.php b/src/ZugferdDocumentReader.php
index 83e14d7..c3d7cdd 100644
--- a/src/ZugferdDocumentReader.php
+++ b/src/ZugferdDocumentReader.php
@@ -161,6 +161,13 @@ class ZugferdDocumentReader extends ZugferdDocument
      */
     private $documentInvRefDocPointer = 0;
 
+    /**
+     * Internal pointer for documents trade accounting accounts
+     *
+     * @var integer
+     */
+    private $documentTradeAccountingAccountPointer = 0;
+
     /**
      * Internal pointer for the position
      *
@@ -2786,6 +2793,54 @@ class ZugferdDocumentReader extends ZugferdDocument
         return $this;
     }
 
+    /**
+     * Seek to the first trade accounting account of the document. Returns true if a first account is available, otherwise false
+     * You may use this together with ZugferdDocumentReader::getDocumentSellerContact
+     *
+     * @return boolean
+     */
+    public function firstDocumentTradeAccountingAccount(): bool
+    {
+        $this->documentTradeAccountingAccountPointer = 0;
+
+        $acccounts = $this->getObjectHelper()->ensureArray($this->getInvoiceValueByPath("getSupplyChainTradeTransaction.getApplicableHeaderTradeSettlement.getReceivableSpecifiedTradeAccountingAccount", []));
+
+        return isset($acccounts[$this->documentTradeAccountingAccountPointer]);
+    }
+
+    /**
+     * Seek to the next trade accounting account of the document. Returns true if another account is available, otherwise false
+     * You may use this together with ZugferdDocumentReader::getDocumentSellerContact
+     *
+     * @return boolean
+     */
+    public function nextDocumentTradeAccountingAccount(): bool
+    {
+        $this->documentTradeAccountingAccountPointer++;
+
+        $acccounts = $this->getObjectHelper()->ensureArray($this->getInvoiceValueByPath("getSupplyChainTradeTransaction.getApplicableHeaderTradeSettlement.getReceivableSpecifiedTradeAccountingAccount", []));
+
+        return isset($acccounts[$this->documentTradeAccountingAccountPointer]);
+    }
+
+    /**
+     * Get information on the booking reference (on document level)
+     *
+     * @param  null|string &$id       __BT-19, From BASIC WL__ Posting reference of the byuer. If required, this reference shall be provided by the Buyer to the Seller prior to the issuing of the Invoice.
+     * @param  null|string &$typeCode __BT-X-290, From EXTENDED__ Type of the posting reference
+     * @return ZugferdDocumentReader
+     */
+    public function getDocumentReceivableSpecifiedTradeAccountingAccount(?string &$id, ?string &$typeCode): ZugferdDocumentReader
+    {
+        $acccounts = $this->getObjectHelper()->ensureArray($this->getInvoiceValueByPath("getSupplyChainTradeTransaction.getApplicableHeaderTradeSettlement.getReceivableSpecifiedTradeAccountingAccount", []));
+        $acccounts = $acccounts[$this->documentTradeAccountingAccountPointer];
+
+        $id = $this->getInvoiceValueByPathFrom($acccounts, "getId.value", "");
+        $typeCode = $this->getInvoiceValueByPathFrom($acccounts, "getTypeCode.value", "");
+
+        return $this;
+    }
+
     /**
      * Seek to the first document position. Returns true if the first position is available, otherwise false
      * You may use it together with getDocumentPositionGenerals
@@ -3920,7 +3975,23 @@ class ZugferdDocumentReader extends ZugferdDocument
         return $this;
     }
 
-    //TODO: Seeker for documents position TradeAccountingAccount
+    /**
+     * Get information on the booking reference (on position level)
+     *
+     * @param  null|string &$id       __BT-133, From EN 16931__ Posting reference of the byuer. If required, this reference shall be provided by the Buyer to the Seller prior to the issuing of the Invoice.
+     * @param  null|string &$typeCode __BT-X-99, From EXTENDED__ Type of the posting reference
+     * @return ZugferdDocumentReader
+     */
+    public function getDocumentPositionReceivableSpecifiedTradeAccountingAccount(?string &$id, ?string &$typeCode): ZugferdDocumentReader
+    {
+        $tradeLineItem = $this->getInvoiceValueByPath("getSupplyChainTradeTransaction.getIncludedSupplyChainTradeLineItem", []);
+        $tradeLineItem = $tradeLineItem[$this->positionPointer];
+
+        $id = $this->getInvoiceValueByPathFrom($tradeLineItem, "getSpecifiedLineTradeSettlement.getReceivableSpecifiedTradeAccountingAccount.getId.value", "");
+        $typeCode = $this->getInvoiceValueByPathFrom($tradeLineItem, "getSpecifiedLineTradeSettlement.getReceivableSpecifiedTradeAccountingAccount.getTypeCode.value", "");
+
+        return $this;
+    }
 
     /**
      * Function to return a value from $invoiceObject by path


Test patch:
diff --git a/tests/assets/xml_issue_268.xml b/tests/assets/xml_issue_268.xml
index 3115b55..9d6a2fe 100644
--- a/tests/assets/xml_issue_268.xml
+++ b/tests/assets/xml_issue_268.xml
@@ -114,6 +114,7 @@
 				</ram:AdditionalReferencedDocument>
 				<ram:ReceivableSpecifiedTradeAccountingAccount>
 					<ram:ID>567</ram:ID>
+                    <ram:TypeCode>1</ram:TypeCode>
 				</ram:ReceivableSpecifiedTradeAccountingAccount>
 			</ram:SpecifiedLineTradeSettlement>
 		</ram:IncludedSupplyChainTradeLineItem>
@@ -196,6 +197,7 @@
 				</ram:AdditionalReferencedDocument>
 				<ram:ReceivableSpecifiedTradeAccountingAccount>
 					<ram:ID>567</ram:ID>
+                    <ram:TypeCode>2</ram:TypeCode>
 				</ram:ReceivableSpecifiedTradeAccountingAccount>
 			</ram:SpecifiedLineTradeSettlement>
 		</ram:IncludedSupplyChainTradeLineItem>
@@ -278,6 +280,7 @@
 				</ram:AdditionalReferencedDocument>
 				<ram:ReceivableSpecifiedTradeAccountingAccount>
 					<ram:ID>740</ram:ID>
+                    <ram:TypeCode>3</ram:TypeCode>
 				</ram:ReceivableSpecifiedTradeAccountingAccount>
 			</ram:SpecifiedLineTradeSettlement>
 		</ram:IncludedSupplyChainTradeLineItem>
@@ -1322,6 +1325,14 @@
 				<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
 				<ram:DuePayableAmount>1028.31</ram:DuePayableAmount>
 			</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
+            <ram:ReceivableSpecifiedTradeAccountingAccount>
+                <ram:ID>567</ram:ID>
+                <ram:TypeCode>1</ram:TypeCode>
+            </ram:ReceivableSpecifiedTradeAccountingAccount>
+            <ram:ReceivableSpecifiedTradeAccountingAccount>
+                <ram:ID>740</ram:ID>
+                <ram:TypeCode>2</ram:TypeCode>
+            </ram:ReceivableSpecifiedTradeAccountingAccount>
 		</ram:ApplicableHeaderTradeSettlement>
 	</rsm:SupplyChainTradeTransaction>
 </rsm:CrossIndustryInvoice>
diff --git a/tests/assets/xml_issue_268_extended.xml b/tests/assets/xml_issue_268_extended.xml
index 4af8b41..e05841a 100644
--- a/tests/assets/xml_issue_268_extended.xml
+++ b/tests/assets/xml_issue_268_extended.xml
@@ -114,6 +114,7 @@
 				</ram:AdditionalReferencedDocument>
 				<ram:ReceivableSpecifiedTradeAccountingAccount>
 					<ram:ID>567</ram:ID>
+                    <ram:TypeCode>1</ram:TypeCode>
 				</ram:ReceivableSpecifiedTradeAccountingAccount>
 			</ram:SpecifiedLineTradeSettlement>
 		</ram:IncludedSupplyChainTradeLineItem>
@@ -196,6 +197,7 @@
 				</ram:AdditionalReferencedDocument>
 				<ram:ReceivableSpecifiedTradeAccountingAccount>
 					<ram:ID>567</ram:ID>
+                    <ram:TypeCode>2</ram:TypeCode>
 				</ram:ReceivableSpecifiedTradeAccountingAccount>
 			</ram:SpecifiedLineTradeSettlement>
 		</ram:IncludedSupplyChainTradeLineItem>
@@ -278,6 +280,7 @@
 				</ram:AdditionalReferencedDocument>
 				<ram:ReceivableSpecifiedTradeAccountingAccount>
 					<ram:ID>740</ram:ID>
+                    <ram:TypeCode>3</ram:TypeCode>
 				</ram:ReceivableSpecifiedTradeAccountingAccount>
 			</ram:SpecifiedLineTradeSettlement>
 		</ram:IncludedSupplyChainTradeLineItem>
@@ -1322,6 +1325,14 @@
 				<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
 				<ram:DuePayableAmount>1028.31</ram:DuePayableAmount>
 			</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
+            <ram:ReceivableSpecifiedTradeAccountingAccount>
+                <ram:ID>567</ram:ID>
+                <ram:TypeCode>1</ram:TypeCode>
+            </ram:ReceivableSpecifiedTradeAccountingAccount>
+            <ram:ReceivableSpecifiedTradeAccountingAccount>
+                <ram:ID>740</ram:ID>
+                <ram:TypeCode>2</ram:TypeCode>
+            </ram:ReceivableSpecifiedTradeAccountingAccount>
 		</ram:ApplicableHeaderTradeSettlement>
 	</rsm:SupplyChainTradeTransaction>
 </rsm:CrossIndustryInvoice>
diff --git a/tests/testcases/BuilderEn16931Test.php b/tests/testcases/BuilderEn16931Test.php
index ef8d64f..17782d2 100644
--- a/tests/testcases/BuilderEn16931Test.php
+++ b/tests/testcases/BuilderEn16931Test.php
@@ -1773,6 +1773,7 @@ class BuilderEn16931Test extends TestCase
         (self::$document)->setDocumentPositionBillingPeriod(new DateTime(), new DateTime());
         (self::$document)->addDocumentPositionAllowanceCharge(10.0, true, 19.0, 10.0, "reasoncode", "reason");
         (self::$document)->setDocumentPositionLineSummation(100);
+        (self::$document)->addDocumentPositionReceivableSpecifiedTradeAccountingAccount("accid2", "acctypecode2");
         (self::$document)->addDocumentPositionReceivableSpecifiedTradeAccountingAccount("accid", "acctypecode");
         (self::$document)->addDocumentPositionAdditionalReferencedDocument("1", "2", "3", "4", "name", "reftypecode", new DateTime());
         (self::$document)->addDocumentPositionUltimateCustomerOrderReferencedDocument("ORDER-0001", "1.1", new DateTime());
diff --git a/tests/testcases/BuilderExtendedTest.php b/tests/testcases/BuilderExtendedTest.php
index a491763..5fce14a 100644
--- a/tests/testcases/BuilderExtendedTest.php
+++ b/tests/testcases/BuilderExtendedTest.php
@@ -1860,6 +1860,7 @@ class BuilderExtendedTest extends TestCase
         (self::$document)->setDocumentPositionBillingPeriod(new \DateTime(), new \DateTime());
         (self::$document)->addDocumentPositionAllowanceCharge(10.0, true, 19.0, 10.0, "reasoncode", "reason");
         (self::$document)->setDocumentPositionLineSummation(100);
+        (self::$document)->addDocumentPositionReceivableSpecifiedTradeAccountingAccount("accid2", "acctypecode2");
         (self::$document)->addDocumentPositionReceivableSpecifiedTradeAccountingAccount("accid", "acctypecode");
         (self::$document)->addDocumentPositionAdditionalReferencedDocument("1", "2", "3", "4", "name", "reftypecode", new \DateTime());
         (self::$document)->addDocumentPositionUltimateCustomerOrderReferencedDocument("ORDER-0001", "1.1", new \DateTime());
diff --git a/tests/testcases/BuilderMinimumTest.php b/tests/testcases/BuilderMinimumTest.php
index bc18296..fe2a827 100644
--- a/tests/testcases/BuilderMinimumTest.php
+++ b/tests/testcases/BuilderMinimumTest.php
@@ -1813,6 +1813,7 @@ class BuilderMinimumTest extends TestCase
         (self::$document)->setDocumentPositionBillingPeriod(new DateTime(), new DateTime());
         (self::$document)->addDocumentPositionAllowanceCharge(10.0, true, 19.0, 10.0, "reasoncode", "reason");
         (self::$document)->setDocumentPositionLineSummation(100);
+        (self::$document)->addDocumentPositionReceivableSpecifiedTradeAccountingAccount("accid2", "acctypecode2");
         (self::$document)->addDocumentPositionReceivableSpecifiedTradeAccountingAccount("accid", "acctypecode");
         (self::$document)->addDocumentPositionAdditionalReferencedDocument("1", "2", "3", "4", "name", "reftypecode", new DateTime());
         (self::$document)->addDocumentPositionUltimateCustomerOrderReferencedDocument("ORDER-0001", "1.1", new DateTime());
diff --git a/tests/testcases/PdfReaderEn16931AllowanceChargeTest.php b/tests/testcases/PdfReaderEn16931AllowanceChargeTest.php
index fc41ca2..329af74 100644
--- a/tests/testcases/PdfReaderEn16931AllowanceChargeTest.php
+++ b/tests/testcases/PdfReaderEn16931AllowanceChargeTest.php
@@ -970,6 +970,12 @@ class PdfReaderEn16931AllowanceChargeTest extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition());
diff --git a/tests/testcases/PdfReaderEn16931Test.php b/tests/testcases/PdfReaderEn16931Test.php
index cf17503..45b12e7 100644
--- a/tests/testcases/PdfReaderEn16931Test.php
+++ b/tests/testcases/PdfReaderEn16931Test.php
@@ -912,6 +912,12 @@ class PdfReaderEn16931Test extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition(), "has a first position");
diff --git a/tests/testcases/PdfReaderExtended2Test.php b/tests/testcases/PdfReaderExtended2Test.php
index d2517a1..1067b0f 100644
--- a/tests/testcases/PdfReaderExtended2Test.php
+++ b/tests/testcases/PdfReaderExtended2Test.php
@@ -980,6 +980,18 @@ class PdfReaderExtended2Test extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertTrue(self::$document->firstDocumentTradeAccountingAccount());
+
+        self::$document->getDocumentReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("BUYER ACCOUNT REF", $accountId);
+        $this->assertSame("", $accountType);
+
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition());
diff --git a/tests/testcases/PdfReaderExtendedTest.php b/tests/testcases/PdfReaderExtendedTest.php
index 8dbb97d..a9f6edd 100644
--- a/tests/testcases/PdfReaderExtendedTest.php
+++ b/tests/testcases/PdfReaderExtendedTest.php
@@ -976,6 +976,12 @@ class PdfReaderExtendedTest extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition());
diff --git a/tests/testcases/PdfReaderMinimumTest.php b/tests/testcases/PdfReaderMinimumTest.php
index 59f00b0..496a35e 100644
--- a/tests/testcases/PdfReaderMinimumTest.php
+++ b/tests/testcases/PdfReaderMinimumTest.php
@@ -847,6 +847,12 @@ class PdfReaderMinimumTest extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertFalse(self::$document->firstDocumentPosition(), "has a first position");
diff --git a/tests/testcases/PdfReaderXRechnungTest.php b/tests/testcases/PdfReaderXRechnungTest.php
index 10a44f5..9ccdb01 100644
--- a/tests/testcases/PdfReaderXRechnungTest.php
+++ b/tests/testcases/PdfReaderXRechnungTest.php
@@ -928,6 +928,12 @@ class PdfReaderXRechnungTest extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition(), "has a first position");
diff --git a/tests/testcases/ReaderBasicTest.php b/tests/testcases/ReaderBasicTest.php
index f4d2164..dec0fc2 100644
--- a/tests/testcases/ReaderBasicTest.php
+++ b/tests/testcases/ReaderBasicTest.php
@@ -921,6 +921,12 @@ class ReaderBasicTest extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition(), "has a first position");
diff --git a/tests/testcases/ReaderEn16931AllowanceChargeTest.php b/tests/testcases/ReaderEn16931AllowanceChargeTest.php
index ac89941..d9a2fb9 100644
--- a/tests/testcases/ReaderEn16931AllowanceChargeTest.php
+++ b/tests/testcases/ReaderEn16931AllowanceChargeTest.php
@@ -985,6 +985,12 @@ class ReaderEn16931AllowanceChargeTest extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition());
diff --git a/tests/testcases/ReaderEn16931Test.php b/tests/testcases/ReaderEn16931Test.php
index 594dda7..4e1aa8f 100644
--- a/tests/testcases/ReaderEn16931Test.php
+++ b/tests/testcases/ReaderEn16931Test.php
@@ -943,6 +943,12 @@ class ReaderEn16931Test extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition(), "has a first position");
diff --git a/tests/testcases/ReaderExtended2Test.php b/tests/testcases/ReaderExtended2Test.php
index 90d8e7b..456c266 100644
--- a/tests/testcases/ReaderExtended2Test.php
+++ b/tests/testcases/ReaderExtended2Test.php
@@ -996,6 +996,18 @@ class ReaderExtended2Test extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertTrue(self::$document->firstDocumentTradeAccountingAccount());
+
+        self::$document->getDocumentReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("BUYER ACCOUNT REF", $accountId);
+        $this->assertSame("", $accountType);
+
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition());
diff --git a/tests/testcases/ReaderExtendedTest.php b/tests/testcases/ReaderExtendedTest.php
index 836e392..ebbbe02 100644
--- a/tests/testcases/ReaderExtendedTest.php
+++ b/tests/testcases/ReaderExtendedTest.php
@@ -1054,6 +1054,12 @@ class ReaderExtendedTest extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition());
diff --git a/tests/testcases/ReaderXRechnungTest.php b/tests/testcases/ReaderXRechnungTest.php
index d957ce6..20324a5 100644
--- a/tests/testcases/ReaderXRechnungTest.php
+++ b/tests/testcases/ReaderXRechnungTest.php
@@ -944,6 +944,12 @@ class ReaderXRechnungTest extends TestCase
         $this->assertFalse(self::$document->nextDocumentPaymentTerms());
     }
 
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $this->assertFalse(self::$document->firstDocumentTradeAccountingAccount());
+        $this->assertFalse(self::$document->nextDocumentTradeAccountingAccount());
+    }
+
     public function testDocumentPositionLoop(): void
     {
         $this->assertTrue(self::$document->firstDocumentPosition(), "has a first position");
diff --git a/tests/testcases/issues/Issue270Test.php b/tests/testcases/issues/Issue270Test.php
new file mode 100644
index 0000000..37d66cf
--- /dev/null
+++ b/tests/testcases/issues/Issue270Test.php
@@ -0,0 +1,96 @@
+<?php
+
+namespace horstoeko\zugferd\tests\testcases\issues;
+
+use horstoeko\zugferd\tests\TestCase;
+use horstoeko\zugferd\ZugferdDocumentReader;
+
+class Issue270Test extends TestCase
+{
+    public function testDocumentReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $document = ZugferdDocumentReader::readAndGuessFromFile(__DIR__ . '/../../assets/xml_issue_268.xml');
+
+        $this->assertTrue($document->firstDocumentTradeAccountingAccount());
+
+        $document->getDocumentReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("567", $accountId);
+        $this->assertSame("", $accountType);
+
+        $this->assertFalse($document->nextDocumentTradeAccountingAccount());
+    }
+
+    public function testDocumentPositionReceivableSpecifiedTradeAccountingAccount(): void
+    {
+        $document = ZugferdDocumentReader::readAndGuessFromFile(__DIR__ . '/../../assets/xml_issue_268.xml');
+
+        $this->assertTrue($document->firstDocumentPosition());
+
+        $document->getDocumentPositionReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("567", $accountId);
+        $this->assertSame("", $accountType);
+
+        $this->assertTrue($document->nextDocumentPosition());
+
+        $document->getDocumentPositionReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("567", $accountId);
+        $this->assertSame("", $accountType);
+
+        $this->assertTrue($document->nextDocumentPosition());
+
+        $document->getDocumentPositionReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("740", $accountId);
+        $this->assertSame("", $accountType);
+    }
+
+    public function testDocumentReceivableSpecifiedTradeAccountingAccountExtended(): void
+    {
+        $document = ZugferdDocumentReader::readAndGuessFromFile(__DIR__ . '/../../assets/xml_issue_268_extended.xml');
+
+        $this->assertTrue($document->firstDocumentTradeAccountingAccount());
+
+        $document->getDocumentReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("567", $accountId);
+        $this->assertSame("1", $accountType);
+
+        $this->assertTrue($document->nextDocumentTradeAccountingAccount());
+
+        $document->getDocumentReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("740", $accountId);
+        $this->assertSame("2", $accountType);
+
+        $this->assertFalse($document->nextDocumentTradeAccountingAccount());
+    }
+
+    public function testDocumentPositionReceivableSpecifiedTradeAccountingAccountExtended(): void
+    {
+        $document = ZugferdDocumentReader::readAndGuessFromFile(__DIR__ . '/../../assets/xml_issue_268_extended.xml');
+
+        $this->assertTrue($document->firstDocumentPosition());
+
+        $document->getDocumentPositionReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("567", $accountId);
+        $this->assertSame("1", $accountType);
+
+        $this->assertTrue($document->nextDocumentPosition());
+
+        $document->getDocumentPositionReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("567", $accountId);
+        $this->assertSame("2", $accountType);
+
+        $this->assertTrue($document->nextDocumentPosition());
+
+        $document->getDocumentPositionReceivableSpecifiedTradeAccountingAccount($accountId, $accountType);
+
+        $this->assertSame("740", $accountId);
+        $this->assertSame("3", $accountType);
+    }
+}