From 1692d4d5f2daab29c62bef6c54a0258d6fc927d6 Mon Sep 17 00:00:00 2001 From: "andrii.svirin" Date: Wed, 16 Aug 2023 21:19:58 +0300 Subject: [PATCH] Add XE3. Update builder for uplaod documents Fixed CCT, CDD builder. --- CHANGELOG.md | 3 + README.md | 1 + .../CustomerSwissCreditTransferBuilder.php | 17 ++- .../CustomerDirectDebitBuilder.php | 13 +- src/Contracts/EbicsClientInterface.php | 10 ++ src/EbicsClient.php | 39 +++++- src/Factories/RequestFactory.php | 2 + src/Factories/RequestFactoryV2.php | 65 ++++++++++ src/Factories/RequestFactoryV3.php | 13 ++ tests/AbstractEbicsTestCase.php | 101 +++++++++++++++- tests/EbicsClientV2Test.php | 112 +++++++----------- tests/EbicsClientV3Test.php | 86 +++++++------- tests/_fixtures/yct.pain001.xml | 3 +- 13 files changed, 332 insertions(+), 133 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0255e6..4df3333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,6 @@ * Added CurlHttpClient and PsrHttpClient to use standard client. * Updated AbstractX509Generator to handle custom options. * Improved Bank-letter +* Fixed padding for encoding that caused problems for upload methods. +* Added XE3 +* Fixed CCT, CDD builder. diff --git a/README.md b/README.md index 317f5ae..6624281 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,7 @@ try { | CCT | Upload initiation of the credit transfer per Single Euro Payments Area. | | CIP | Upload initiation of the instant credit transfer per Single Euro Payments Area. | | XE2 | Upload initiation of the Swiss credit transfer (i.e available in Switzerland). | +| XE3 | Upload SEPA Direct Debit Initiation, CH definitions, CORE (i.e available in Switzerland). | | YCT | Upload Credit transfer CGI (SEPA & non SEPA). | | CDD | Upload initiation of the direct debit transaction. | | BTD | Download request files of any BTF structure. | diff --git a/src/Builders/CustomerCreditTransfer/CustomerSwissCreditTransferBuilder.php b/src/Builders/CustomerCreditTransfer/CustomerSwissCreditTransferBuilder.php index 5229c58..11628a5 100644 --- a/src/Builders/CustomerCreditTransfer/CustomerSwissCreditTransferBuilder.php +++ b/src/Builders/CustomerCreditTransfer/CustomerSwissCreditTransferBuilder.php @@ -32,7 +32,17 @@ public function __construct() $this->randomService = new RandomService(); } + /** + * @param string $schema has next formula urn:iso:std:iso:20022:tech:xsd:msgName.001.msgNameVersion + * @param string $debitorFinInstBIC + * @param string $debitorIBAN + * @param string $debitorName + * + * @return $this + * @throws \DOMException + */ public function createInstance( + string $schema, string $debitorFinInstBIC, string $debitorIBAN, string $debitorName @@ -41,7 +51,7 @@ public function createInstance( $now = new DateTime(); $xmDocument = $this->instance->createElementNS( - 'http://www.six-interbank-clearing.com/de/pain.001.001.03.ch.02.xsd', + $schema, 'Document' ); $xmDocument->setAttributeNS( @@ -49,11 +59,6 @@ public function createInstance( 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance' ); - $xmDocument->setAttributeNS( - 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation', - 'http://www.six-interbank-clearing.com/de/pain.001.001.03.ch.02.xsd pain.001.001.03.ch.02.xsd' - ); $this->instance->appendChild($xmDocument); $xmlCstmrCdtTrfInitn = $this->instance->createElement('CstmrCdtTrfInitn'); diff --git a/src/Builders/CustomerDirectDebit/CustomerDirectDebitBuilder.php b/src/Builders/CustomerDirectDebit/CustomerDirectDebitBuilder.php index 21d45f9..c0a88b2 100644 --- a/src/Builders/CustomerDirectDebit/CustomerDirectDebitBuilder.php +++ b/src/Builders/CustomerDirectDebit/CustomerDirectDebitBuilder.php @@ -27,6 +27,7 @@ public function __construct() } /** + * @param string $schema has next formula urn:iso:std:iso:20022:tech:xsd:msgName.001.msgNameVersion * @param string $creditorFinInstBic * @param string $creditorIban * @param string $creditorName @@ -39,9 +40,12 @@ public function __construct() * least for 15 days. Used for rejecting duplicated transactions (max length: 35 characters) * @param string|null $paymentReference Overwrite default payment reference - * visible on creditors bank statement (max length: 35 characters) + * * @return $this + * @throws \DOMException */ public function createInstance( + string $schema, string $creditorFinInstBic, string $creditorIban, string $creditorName, @@ -56,7 +60,7 @@ public function createInstance( $now = new DateTime(); $xmDocument = $this->instance->createElementNS( - 'urn:iso:std:iso:20022:tech:xsd:pain.008.001.02', + $schema, 'Document' ); $xmDocument->setAttributeNS( @@ -64,11 +68,6 @@ public function createInstance( 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance' ); - $xmDocument->setAttributeNS( - 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation', - 'urn:iso:std:iso:20022:tech:xsd:pain.008.001.02.xsdpain.008.001.02' - ); $this->instance->appendChild($xmDocument); $xmlCstmrDrctDbtInitn = $this->instance->createElement('CstmrDrctDbtInitn'); @@ -252,7 +251,7 @@ public function addTransaction( $xmlEndToEndId->nodeValue = $endToEndId; } else { $xmlEndToEndId->nodeValue = $this->randomService->uniqueIdWithDate( - 'pete' . str_pad((string)$nbOfTxs, 2, '0') + 'pete'.str_pad((string)$nbOfTxs, 2, '0') ); } diff --git a/src/Contracts/EbicsClientInterface.php b/src/Contracts/EbicsClientInterface.php index d26ec70..51769a9 100644 --- a/src/Contracts/EbicsClientInterface.php +++ b/src/Contracts/EbicsClientInterface.php @@ -328,6 +328,16 @@ public function CDD(OrderDataInterface $orderData, DateTimeInterface $dateTime = */ public function XE2(OrderDataInterface $orderData, DateTimeInterface $dateTime = null): UploadOrderResult; + /** + * Upload SEPA Direct Debit Initiation, CH definitions, CORE. + * FileFormat pain.008.001.03.ch.02 + * OrderType:BTU, Service Name:SDD, Scope:CH,Service Option:COR Container:, MsgName:pain.008,Version: 02 + * @param OrderDataInterface $orderData + * @param DateTimeInterface|null $dateTime + * @return UploadOrderResult + */ + public function XE3(OrderDataInterface $orderData, DateTimeInterface $dateTime = null): UploadOrderResult; + /** * Upload Credit transfer CGI (SEPA & non SEPA). * OrderType:BTU, Service Name:MCT, Scope:BIL, Container:, MsgName:pain.001 diff --git a/src/EbicsClient.php b/src/EbicsClient.php index 901f86a..9b1b100 100644 --- a/src/EbicsClient.php +++ b/src/EbicsClient.php @@ -278,9 +278,10 @@ public function BTU(BTUContext $btuContext, DateTimeInterface $dateTime = null): $dateTime = new DateTime(); } - $transaction = $this->uploadTransaction(function (UploadTransaction $transaction) use ($btuContext, $dateTime) { + $transaction = $this->uploadTransaction(function (UploadTransaction $transaction) use ($dateTime, $btuContext) { $transaction->setOrderData($btuContext->getFileData()); $transaction->setDigest($this->cryptService->hash($transaction->getOrderData())); + return $this->requestFactory->createBTU( $btuContext, $dateTime, @@ -736,6 +737,7 @@ public function FUL( ) { $transaction->setOrderData($orderData->getContent()); $transaction->setDigest($this->cryptService->hash($transaction->getOrderData())); + return $this->requestFactory->createFUL( $dateTime, $fileFormat, @@ -761,6 +763,7 @@ public function CCT(OrderDataInterface $orderData, DateTimeInterface $dateTime = $transaction = $this->uploadTransaction(function (UploadTransaction $transaction) use ($orderData, $dateTime) { $transaction->setOrderData($orderData->getContent()); $transaction->setDigest($this->cryptService->hash($transaction->getOrderData())); + return $this->requestFactory->createCCT( $dateTime, $transaction @@ -784,6 +787,7 @@ public function CDD(OrderDataInterface $orderData, DateTimeInterface $dateTime = $transaction = $this->uploadTransaction(function (UploadTransaction $transaction) use ($dateTime, $orderData) { $transaction->setOrderData($orderData->getContent()); $transaction->setDigest($this->cryptService->hash($transaction->getOrderData())); + return $this->requestFactory->createCDD( $dateTime, $transaction @@ -807,6 +811,7 @@ public function XE2(OrderDataInterface $orderData, DateTimeInterface $dateTime = $transaction = $this->uploadTransaction(function (UploadTransaction $transaction) use ($dateTime, $orderData) { $transaction->setOrderData($orderData->getContent()); $transaction->setDigest($this->cryptService->hash($transaction->getOrderData())); + return $this->requestFactory->createXE2( $dateTime, $transaction @@ -816,6 +821,30 @@ public function XE2(OrderDataInterface $orderData, DateTimeInterface $dateTime = return $this->createUploadOrderResult($transaction, $orderData); } + /** + * @inheritDoc + * @throws Exceptions\EbicsResponseException + * @throws EbicsException + */ + public function XE3(OrderDataInterface $orderData, DateTimeInterface $dateTime = null): UploadOrderResult + { + if (null === $dateTime) { + $dateTime = new DateTime(); + } + + $transaction = $this->uploadTransaction(function (UploadTransaction $transaction) use ($dateTime, $orderData) { + $transaction->setOrderData($orderData->getContent()); + $transaction->setDigest($this->cryptService->hash($transaction->getOrderData())); + + return $this->requestFactory->createXE3( + $dateTime, + $transaction + ); + }); + + return $this->createUploadOrderResult($transaction, $orderData); + } + /** * @inheritDoc * @throws Exceptions\EbicsResponseException @@ -830,6 +859,7 @@ public function YCT(OrderDataInterface $orderData, DateTimeInterface $dateTime = $transaction = $this->uploadTransaction(function (UploadTransaction $transaction) use ($dateTime, $orderData) { $transaction->setOrderData($orderData->getContent()); $transaction->setDigest($this->cryptService->hash($transaction->getOrderData())); + return $this->requestFactory->createYCT( $dateTime, $transaction @@ -853,6 +883,7 @@ public function CIP(OrderDataInterface $orderData, DateTimeInterface $dateTime = $transaction = $this->uploadTransaction(function (UploadTransaction $transaction) use ($dateTime, $orderData) { $transaction->setOrderData($orderData->getContent()); $transaction->setDigest($this->cryptService->hash($transaction->getOrderData())); + return $this->requestFactory->createCIP( $dateTime, $transaction @@ -921,6 +952,7 @@ public function HVE(HVEContext $hveContext, DateTimeInterface $dateTime = null): $hveContext ) { $transaction->setDigest($hveContext->getDigest()); + return $this->requestFactory->createHVE( $hveContext, $dateTime, @@ -1118,7 +1150,7 @@ private function downloadTransaction(callable $requestClosure, callable $storeCl $requestClosure, [ $transaction->getLastSegment()->getNextSegmentNumber(), - $transaction->getLastSegment()->isLastNextSegmentNumber() + $transaction->getLastSegment()->isLastNextSegmentNumber(), ] ); @@ -1340,6 +1372,7 @@ public function setHttpClient(HttpClientInterface $httpClient): void /** * Get user signature. + * * @param string $type One of allowed user signature type. * @param bool $createNew Flag to generate new signature force. * @@ -1371,7 +1404,9 @@ private function getUserSignature(string $type, bool $createNew = false): Signat /** * Create new signature. + * * @param string $type + * * @return SignatureInterface * @throws EbicsException */ diff --git a/src/Factories/RequestFactory.php b/src/Factories/RequestFactory.php index b34dc13..6d35be4 100644 --- a/src/Factories/RequestFactory.php +++ b/src/Factories/RequestFactory.php @@ -855,6 +855,8 @@ abstract public function createCDD(DateTimeInterface $dateTime, UploadTransactio abstract public function createXE2(DateTimeInterface $dateTime, UploadTransaction $transaction): Request; + abstract public function createXE3(DateTimeInterface $dateTime, UploadTransaction $transaction): Request; + abstract public function createYCT(DateTimeInterface $dateTime, UploadTransaction $transaction): Request; /** diff --git a/src/Factories/RequestFactoryV2.php b/src/Factories/RequestFactoryV2.php index 6415c35..d2b020a 100644 --- a/src/Factories/RequestFactoryV2.php +++ b/src/Factories/RequestFactoryV2.php @@ -71,6 +71,7 @@ protected function addOrderType(OrderDetailsBuilder $orderDetailsBuilder, string case 'CCT': case 'CDD': case 'XE2': + case 'XE3': case 'CIP': $orderAttribute = OrderDetailsBuilder::ORDER_ATTRIBUTE_OZHNN; break; @@ -771,6 +772,70 @@ public function createXE2(DateTimeInterface $dateTime, UploadTransaction $transa return $request; } + /** + * @throws EbicsException + */ + public function createXE3(DateTimeInterface $dateTime, UploadTransaction $transaction): Request + { + $signatureData = new UserSignature(); + $this->userSignatureHandler->handle($signatureData, $transaction->getDigest()); + + $context = (new RequestContext()) + ->setBank($this->bank) + ->setUser($this->user) + ->setKeyRing($this->keyRing) + ->setDateTime($dateTime) + ->setTransactionKey($transaction->getKey()) + ->setNumSegments($transaction->getNumSegments()) + ->setSignatureData($signatureData); + + $request = $this + ->createRequestBuilderInstance() + ->addContainerSecured(function (XmlBuilder $builder) use ($context) { + $builder->addHeader(function (HeaderBuilder $builder) use ($context) { + $builder->addStatic(function (StaticBuilder $builder) use ($context) { + $builder + ->addHostId($context->getBank()->getHostId()) + ->addRandomNonce() + ->addTimestamp($context->getDateTime()) + ->addPartnerId($context->getUser()->getPartnerId()) + ->addUserId($context->getUser()->getUserId()) + ->addProduct('Ebics client PHP', 'de') + ->addOrderDetails(function (OrderDetailsBuilder $orderDetailsBuilder) { + $this + ->addOrderType($orderDetailsBuilder, 'XE3') + ->addStandardOrderParams(); + }) + ->addBankPubKeyDigests( + $context->getKeyRing()->getBankSignatureXVersion(), + $this->digestResolver->digest($context->getKeyRing()->getBankSignatureX()), + $context->getKeyRing()->getBankSignatureEVersion(), + $this->digestResolver->digest($context->getKeyRing()->getBankSignatureE()) + ) + ->addSecurityMedium(StaticBuilder::SECURITY_MEDIUM_0000) + ->addNumSegments($context->getNumSegments()); + })->addMutable(function (MutableBuilder $builder) { + $builder->addTransactionPhase(MutableBuilder::PHASE_INITIALIZATION); + }); + })->addBody(function (BodyBuilder $builder) use ($context) { + $builder->addDataTransfer(function (DataTransferBuilder $builder) use ($context) { + $builder + ->addDataEncryptionInfo(function (DataEncryptionInfoBuilder $builder) use ($context) { + $builder + ->addEncryptionPubKeyDigest($context->getKeyRing()) + ->addTransactionKey($context->getTransactionKey(), $context->getKeyRing()); + }) + ->addSignatureData($context->getSignatureData(), $context->getTransactionKey()); + }); + }); + }) + ->popInstance(); + + $this->authSignatureHandler->handle($request); + + return $request; + } + public function createYCT(DateTimeInterface $dateTime, UploadTransaction $transaction): Request { throw new LogicException('Method not implemented yet for EBICS 2.5'); diff --git a/src/Factories/RequestFactoryV3.php b/src/Factories/RequestFactoryV3.php index dff0777..d991efa 100644 --- a/src/Factories/RequestFactoryV3.php +++ b/src/Factories/RequestFactoryV3.php @@ -296,6 +296,7 @@ public function createZ54( $btfContext->setServiceName('REP'); $btfContext->setScope('CH'); $btfContext->setMsgName('camt.054'); + $btfContext->setMsgNameVersion('04'); $btfContext->setContainerFlag('ZIP'); return $this->createBTD($dateTime, $btfContext, $startDateTime, $endDateTime, $segmentNumber, $isLastSegment); @@ -335,6 +336,18 @@ public function createXE2(DateTimeInterface $dateTime, UploadTransaction $transa throw new LogicException('Method not implemented yet for EBICS 3.0'); } + public function createXE3(DateTimeInterface $dateTime, UploadTransaction $transaction): Request + { + $btfContext = new BTUContext(); + $btfContext->setServiceName('SDD'); + $btfContext->setScope('CH'); + $btfContext->setMsgName('pain.008'); + $btfContext->setMsgNameVersion('02'); + $btfContext->setFileName('xe3.pain008.xml'); + + return $this->createBTU($btfContext, $dateTime, $transaction); + } + public function createYCT(DateTimeInterface $dateTime, UploadTransaction $transaction): Request { $btfContext = new BTUContext(); diff --git a/tests/AbstractEbicsTestCase.php b/tests/AbstractEbicsTestCase.php index a3f1d34..c5c6e49 100644 --- a/tests/AbstractEbicsTestCase.php +++ b/tests/AbstractEbicsTestCase.php @@ -2,13 +2,18 @@ namespace AndrewSvirin\Ebics\Tests; +use AndrewSvirin\Ebics\Builders\CustomerCreditTransfer\CustomerSwissCreditTransferBuilder; +use AndrewSvirin\Ebics\Builders\CustomerDirectDebit\CustomerDirectDebitBuilder; use AndrewSvirin\Ebics\Contracts\EbicsClientInterface; -use AndrewSvirin\Ebics\Contracts\KeyRingManagerInterface; use AndrewSvirin\Ebics\Contracts\X509GeneratorInterface; use AndrewSvirin\Ebics\EbicsClient; use AndrewSvirin\Ebics\Factories\SignatureFactory; use AndrewSvirin\Ebics\Models\Bank; +use AndrewSvirin\Ebics\Models\CustomerCreditTransfer; +use AndrewSvirin\Ebics\Models\CustomerDirectDebit; use AndrewSvirin\Ebics\Models\KeyRing; +use AndrewSvirin\Ebics\Models\StructuredPostalAddress; +use AndrewSvirin\Ebics\Models\UnstructuredPostalAddress; use AndrewSvirin\Ebics\Models\User; use AndrewSvirin\Ebics\Services\FileKeyringManager; use PHPUnit\Framework\TestCase; @@ -23,9 +28,9 @@ abstract class AbstractEbicsTestCase extends TestCase { - protected $data = __DIR__ . '/_data'; + protected $data = __DIR__.'/_data'; - protected $fixtures = __DIR__ . '/_fixtures'; + protected $fixtures = __DIR__.'/_fixtures'; protected function setupClientV2( int $credentialsId, @@ -91,7 +96,7 @@ protected function saveKeyRing($credentialsId, KeyRing $keyRing): void protected function setupKeys(KeyRing $keyRing) { - $keys = json_decode(file_get_contents($this->fixtures . '/keys.json')); + $keys = json_decode(file_get_contents($this->fixtures.'/keys.json')); $keyRing->setPassword('mysecret'); $signatureFactory = new SignatureFactory(); @@ -170,4 +175,92 @@ public function credentialsDataProvider(int $credentialsId): array 'userId' => $credentialsEnc['userId'], ]; } + + /** + * Create simple instance of CustomerCreditTransfer. + * + * @param string $schema + * + * @return CustomerCreditTransfer + * @throws \DOMException + */ + protected function buildCustomerCreditTransfer(string $schema): CustomerCreditTransfer + { + $builder = new CustomerSwissCreditTransferBuilder(); + $customerCreditTransfer = $builder + ->createInstance( + $schema, + 'ZKBKCHZZ80A', + 'SE7500800000000000001123', + 'Debitor Name' + ) + ->addBankTransaction( + 'MARKDEF1820', + 'DE09820000000083001503', + new StructuredPostalAddress('CH', 'Triesen', '9495'), + 100.10, + 'CHF', + 'Test payment 1' + ) + ->addSEPATransaction( + 'GIBASKBX', + 'SK4209000000000331819272', + 'Creditor Name 4', + null, // new UnstructuredPostalAddress(), + 200.02, + 'EUR', + 'Test payment 2' + ) + ->addForeignTransaction( + 'NWBKGB2L', + 'GB29 NWBK 6016 1331 9268 19', + 'United Development Ltd', + new UnstructuredPostalAddress('GB', 'George Street', 'BA1 2FJ Bath'), + 65.10, + 'GBP', + 'Test payment 3' + ) + ->popInstance(); + + return $customerCreditTransfer; + } + + /** + * Create simple instance of CustomerDirectDebit. + * + * @param string $schema + * + * @return CustomerDirectDebit + * @throws \DOMException + */ + protected function buildCustomerDirectDebit(string $schema): CustomerDirectDebit + { + $builder = new CustomerDirectDebitBuilder(); + $customerDirectDebit = $builder + ->createInstance( + $schema, + 'ZKBKCHZZ80A', + 'SE7500800000000000001123', + 'Creditor Name' + ) + ->addTransaction( + 'MARKDEF1820', + 'DE09820000000083001503', + 'Debitor Name 1', + 100.10, + 'EUR', + 'Test payment 1' + ) + ->addTransaction( + 'GIBASKBX', + 'SK4209000000000331819272', + 'Debitor Name 2', + 200.02, + 'EUR', + 'Test payment 2' + ) + ->popInstance(); + + return $customerDirectDebit; + } } diff --git a/tests/EbicsClientV2Test.php b/tests/EbicsClientV2Test.php index c5f6e9c..b95110c 100644 --- a/tests/EbicsClientV2Test.php +++ b/tests/EbicsClientV2Test.php @@ -2,9 +2,6 @@ namespace AndrewSvirin\Ebics\Tests; -use AndrewSvirin\Ebics\Builders\CustomerCreditTransfer\CustomerCreditTransferBuilder; -use AndrewSvirin\Ebics\Builders\CustomerCreditTransfer\CustomerSwissCreditTransferBuilder; -use AndrewSvirin\Ebics\Builders\CustomerDirectDebit\CustomerDirectDebitBuilder; use AndrewSvirin\Ebics\Contexts\FULContext; use AndrewSvirin\Ebics\Contexts\HVDContext; use AndrewSvirin\Ebics\Contexts\HVEContext; @@ -12,9 +9,6 @@ use AndrewSvirin\Ebics\Contracts\X509GeneratorInterface; use AndrewSvirin\Ebics\Exceptions\InvalidUserOrUserStateException; use AndrewSvirin\Ebics\Factories\DocumentFactory; -use AndrewSvirin\Ebics\Models\StructuredPostalAddress; -use AndrewSvirin\Ebics\Models\UnstructuredPostalAddress; -use AndrewSvirin\Ebics\Tests\Factories\X509\WeBankX509Generator; use DateTime; use Silarhi\Cfonb\CfonbParser; @@ -682,26 +676,7 @@ public function testCCT(int $credentialsId, array $codes, X509GeneratorInterface $this->assertExceptionCode($codes['CCT']['code']); - $builder = new CustomerCreditTransferBuilder(); - $customerCreditTransfer = $builder - ->createInstance('ZKBKCHZZ80A', 'SE7500800000000000001123', 'Debitor Name') - ->addTransaction( - 'MARKDEF1820', - 'DE09820000000083001503', - 'Creditor Name 1', - 100.10, - 'EUR', - 'Test payment 1' - ) - ->addTransaction( - 'GIBASKBX', - 'SK4209000000000331819272', - 'Creditor Name 2', - 200.02, - 'EUR', - 'Test payment 2' - ) - ->popInstance(); + $customerCreditTransfer = $this->buildCustomerCreditTransfer('urn:iso:std:iso:20022:tech:xsd:pain.001.001.03'); $cct = $client->CCT($customerCreditTransfer); @@ -733,13 +708,7 @@ public function testCIP(int $credentialsId, array $codes, X509GeneratorInterface $this->assertExceptionCode($codes['CIP']['code']); - $builder = new CustomerDirectDebitBuilder(); - $customerDirectDebit = $builder - ->createInstance('ZKBKCHZZ80A', 'SE7500800000000000001123', 'Creditor Name') - ->addTransaction('MARKDEF1820', 'DE09820000000083001503', 'Debitor Name 1', 100.10, 'EUR', - 'Test payment 1') - ->addTransaction('GIBASKBX', 'SK4209000000000331819272', 'Debitor Name 2', 200.02, 'EUR', 'Test payment 2') - ->popInstance(); + $customerDirectDebit = $this->buildCustomerDirectDebit('urn:iso:std:iso:20022:tech:xsd:pain.008.001.02'); $cip = $client->CIP($customerDirectDebit); @@ -773,36 +742,7 @@ public function testXE2(int $credentialsId, array $codes, X509GeneratorInterface $this->assertExceptionCode($codes['XE2']['code']); - $builder = new CustomerSwissCreditTransferBuilder(); - $customerCreditTransfer = $builder - ->createInstance('ZKBKCHZZ80A', 'SE7500800000000000001123', 'Debitor Name') - ->addBankTransaction( - 'MARKDEF1820', - 'DE09820000000083001503', - new StructuredPostalAddress('CH', 'Triesen', '9495'), - 100.10, - 'CHF', - 'Test payment 1' - ) - ->addSEPATransaction( - 'GIBASKBX', - 'SK4209000000000331819272', - 'Creditor Name 4', - null, // new UnstructuredPostalAddress(), - 200.02, - 'EUR', - 'Test payment 2' - ) - ->addForeignTransaction( - 'NWBKGB2L', - 'GB29 NWBK 6016 1331 9268 19', - 'United Development Ltd', - new UnstructuredPostalAddress('GB', 'George Street', 'BA1 2FJ Bath'), - 65.10, - 'GBP', - 'Test payment 3' - ) - ->popInstance(); + $customerCreditTransfer = $this->buildCustomerCreditTransfer('urn:iso:std:iso:20022:tech:xsd:pain.001.001.02'); $xe2 = $client->XE2($customerCreditTransfer); @@ -817,6 +757,40 @@ public function testXE2(int $credentialsId, array $codes, X509GeneratorInterface $this->assertResponseOk($code, $reportText); } + /** + * @dataProvider serversDataProvider + * + * @group XE3 + * @group V2 + * @group XE3-V2 + * + * @param int $credentialsId + * @param array $codes + * @param X509GeneratorInterface|null $x509Generator + * + * @covers + */ + public function testXE3(int $credentialsId, array $codes, X509GeneratorInterface $x509Generator = null) + { + $client = $this->setupClientV2($credentialsId, $x509Generator, $codes['XE3']['fake']); + + $this->assertExceptionCode($codes['XE3']['code']); + + $customerCreditTransfer = $this->buildCustomerCreditTransfer('urn:iso:std:iso:20022:tech:xsd:pain.001.001.02'); + + $xe3 = $client->XE3($customerCreditTransfer); + + $responseHandler = $client->getResponseHandler(); + $code = $responseHandler->retrieveH00XReturnCode($xe3->getTransaction()->getLastSegment()->getResponse()); + $reportText = $responseHandler->retrieveH00XReportText($xe3->getTransaction()->getLastSegment()->getResponse()); + $this->assertResponseOk($code, $reportText); + + $code = $responseHandler->retrieveH00XReturnCode($xe3->getTransaction()->getInitialization()->getResponse()); + $reportText = $responseHandler->retrieveH00XReportText($xe3->getTransaction()->getInitialization()->getResponse()); + + $this->assertResponseOk($code, $reportText); + } + /** * @dataProvider serversDataProvider * @@ -834,13 +808,7 @@ public function testCDD(int $credentialsId, array $codes, X509GeneratorInterface $this->assertExceptionCode($codes['CDD']['code']); - $builder = new CustomerDirectDebitBuilder(); - $customerDirectDebit = $builder - ->createInstance('ZKBKCHZZ80A', 'SE7500800000000000001123', 'Creditor Name') - ->addTransaction('MARKDEF1820', 'DE09820000000083001503', 'Debitor Name 1', 100.10, 'EUR', - 'Test payment 1') - ->addTransaction('GIBASKBX', 'SK4209000000000331819272', 'Debitor Name 2', 200.02, 'EUR', 'Test payment 2') - ->popInstance(); + $customerDirectDebit = $this->buildCustomerDirectDebit('urn:iso:std:iso:20022:tech:xsd:pain.008.001.02'); $cdd = $client->CDD($customerDirectDebit); @@ -1079,6 +1047,7 @@ public function serversDataProvider() ], 'CCT' => ['code' => null, 'fake' => false], 'XE2' => ['code' => null, 'fake' => false], + 'XE3' => ['code' => null, 'fake' => false], 'CDD' => ['code' => null, 'fake' => false], 'CIP' => ['code' => '091005', 'fake' => false], 'HVU' => ['code' => '090003', 'fake' => false], @@ -1153,6 +1122,7 @@ public function serversDataProvider() ], 'CCT' => ['code' => null, 'fake' => false], 'XE2' => ['code' => null, 'fake' => false], + 'XE3' => ['code' => null, 'fake' => false], 'CDD' => ['code' => null, 'fake' => false], 'CIP' => ['code' => '091005', 'fake' => false], 'HVU' => ['code' => '090003', 'fake' => false], @@ -1197,6 +1167,7 @@ public function serversDataProvider() ], 'CCT' => ['code' => '090003', 'fake' => false], 'XE2' => ['code' => null, 'fake' => false], + 'XE3' => ['code' => null, 'fake' => false], 'CDD' => ['code' => '090003', 'fake' => false], 'CIP' => ['code' => '091005', 'fake' => false], 'HVU' => ['code' => '090003', 'fake' => false], @@ -1241,6 +1212,7 @@ public function serversDataProvider() ], 'CCT' => ['code' => null, 'fake' => false], 'XE2' => ['code' => null, 'fake' => false], + 'XE3' => ['code' => null, 'fake' => false], 'CDD' => ['code' => null, 'fake' => false], 'CIP' => ['code' => '091005', 'fake' => false], 'HVU' => ['code' => '090003', 'fake' => false], diff --git a/tests/EbicsClientV3Test.php b/tests/EbicsClientV3Test.php index e7dfee7..ceb62b1 100644 --- a/tests/EbicsClientV3Test.php +++ b/tests/EbicsClientV3Test.php @@ -2,8 +2,6 @@ namespace AndrewSvirin\Ebics\Tests; -use AndrewSvirin\Ebics\Builders\CustomerCreditTransfer\CustomerCreditTransferBuilder; -use AndrewSvirin\Ebics\Builders\CustomerDirectDebit\CustomerDirectDebitBuilder; use AndrewSvirin\Ebics\Contexts\BTDContext; use AndrewSvirin\Ebics\Contexts\BTUContext; use AndrewSvirin\Ebics\Contexts\HVDContext; @@ -267,44 +265,17 @@ public function testBTU(int $credentialsId, array $codes, X509GeneratorInterface $this->assertExceptionCode($codes['BTU']['code']); - $builder = new CustomerCreditTransferBuilder(); - $customerCreditTransfer = $builder - ->createInstance( - 'ZKBKCHZZ80A', - 'SE7500800000000000001123', - 'Debitor Name', - null, - true, - 'msg-123', - 'pr-123' - ) - ->addTransaction( - 'MARKDEF1820', - 'DE09820000000083001503', - 'Creditor Name 1', - 100.10, - 'EUR', - 'Test payment 1' - ) - ->addTransaction( - 'GIBASKBX', - 'SK4209000000000331819272', - 'Creditor Name 2', - 200.02, - 'EUR', - 'Test payment 2' - ) - ->popInstance(); + $customerCreditTransfer = $this->buildCustomerCreditTransfer('urn:iso:std:iso:20022:tech:xsd:pain.001.001.09'); + // XE2 $context = new BTUContext(); - $context->setServiceName('MCT'); $context->setScope('CH'); $context->setMsgName('pain.001'); - $context->setMsgNameVersion('03'); + $context->setMsgNameVersion('09'); + $context->setFileName('xe2.pain001.xml'); $context->setFileData($customerCreditTransfer->getContent()); $context->setFileDocument($customerCreditTransfer); - $context->setFileName('MCT.xml'); $btu = $client->BTU($context); @@ -319,6 +290,41 @@ public function testBTU(int $credentialsId, array $codes, X509GeneratorInterface $this->assertResponseOk($code, $reportText); } + /** + * @dataProvider serversDataProvider + * + * @group XE3 + * @group V3 + * @group XE3-V3 + * + * @param int $credentialsId + * @param array $codes + * @param X509GeneratorInterface|null $x509Generator + * + * @covers + */ + public function testXE3(int $credentialsId, array $codes, X509GeneratorInterface $x509Generator = null) + { + $client = $this->setupClientV3($credentialsId, $x509Generator, $codes['XE3']['fake']); + + $this->assertExceptionCode($codes['XE3']['code']); + + $documentFactory = new DocumentFactory(); + $context = $documentFactory->create(file_get_contents($this->fixtures.'/yct.pain001.xml')); + + $xe3 = $client->XE3($context); + + $responseHandler = $client->getResponseHandler(); + $code = $responseHandler->retrieveH00XReturnCode($xe3->getTransaction()->getLastSegment()->getResponse()); + $reportText = $responseHandler->retrieveH00XReportText($xe3->getTransaction()->getLastSegment()->getResponse()); + $this->assertResponseOk($code, $reportText); + + $code = $responseHandler->retrieveH00XReturnCode($xe3->getTransaction()->getInitialization()->getResponse()); + $reportText = $responseHandler->retrieveH00XReportText($xe3->getTransaction()->getInitialization()->getResponse()); + + $this->assertResponseOk($code, $reportText); + } + /** * @dataProvider serversDataProvider * @@ -339,7 +345,7 @@ public function testYCT(int $credentialsId, array $codes, X509GeneratorInterface $this->assertExceptionCode($codes['YCT']['code']); $documentFactory = new DocumentFactory(); - $context = $documentFactory->create(file_get_contents($this->fixtures . '/yct.pain001.xml')); + $context = $documentFactory->create(file_get_contents($this->fixtures.'/yct.pain001.xml')); $yct = $client->YCT($context); @@ -373,13 +379,7 @@ public function testCIP(int $credentialsId, array $codes, X509GeneratorInterface $this->assertExceptionCode($codes['CIP']['code']); - $builder = new CustomerDirectDebitBuilder(); - $customerDirectDebit = $builder - ->createInstance('ZKBKCHZZ80A', 'SE7500800000000000001123', 'Creditor Name') - ->addTransaction('MARKDEF1820', 'DE09820000000083001503', 'Debitor Name 1', 100.10, 'EUR', - 'Test payment 1') - ->addTransaction('GIBASKBX', 'SK4209000000000331819272', 'Debitor Name 2', 200.02, 'EUR', 'Test payment 2') - ->popInstance(); + $customerDirectDebit = $this->buildCustomerDirectDebit('urn:iso:std:iso:20022:tech:xsd:pain.008.001.02'); $cip = $client->CIP($customerDirectDebit); @@ -765,7 +765,8 @@ public function serversDataProvider() 'PTK' => ['code' => null, 'fake' => false], 'Z54' => ['code' => '091005', 'fake' => false], 'ZSR' => ['code' => '091005', 'fake' => false], - 'BTU' => ['code' => '091005', 'fake' => false], + 'BTU' => ['code' => null, 'fake' => false], + 'XE3' => ['code' => null, 'fake' => false], 'YCT' => ['code' => '091005', 'fake' => false], 'HPD' => ['code' => null, 'fake' => false], 'HAA' => ['code' => null, 'fake' => false], @@ -791,6 +792,7 @@ public function serversDataProvider() 'Z54' => ['code' => '091005', 'fake' => false], 'ZSR' => ['code' => '091005', 'fake' => false], 'BTU' => ['code' => null, 'fake' => false], + 'XE3' => ['code' => null, 'fake' => false], 'YCT' => ['code' => '091005', 'fake' => false], 'HPD' => ['code' => null, 'fake' => false], 'HAA' => ['code' => null, 'fake' => false], diff --git a/tests/_fixtures/yct.pain001.xml b/tests/_fixtures/yct.pain001.xml index 06ef0e0..26c9d0c 100644 --- a/tests/_fixtures/yct.pain001.xml +++ b/tests/_fixtures/yct.pain001.xml @@ -1,5 +1,4 @@ - @@ -138,4 +137,4 @@ - \ No newline at end of file +