From fe05c1f7548d8a37ef9c4f89f6db731c57e90d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Thu, 10 Sep 2026 11:06:15 +0200 Subject: [PATCH 01/14] FC#0135237 - Added SECCI request for CCD2 to the php lib --- src/Model/Request/SecciRequest.php | 31 +++++ src/Model/Request/SubModel/Content.php | 4 + .../Request/SubModel/Content/Payment.php | 5 + src/Model/Request/SubModel/Content/Secci.php | 121 ++++++++++++++++++ src/Model/Request/SubModel/Head.php | 3 + src/Model/Response/SecciRequest.php | 69 ++++++++++ src/Service/ModelMapper.php | 2 + 7 files changed, 235 insertions(+) create mode 100644 src/Model/Request/SecciRequest.php create mode 100644 src/Model/Request/SubModel/Content/Secci.php create mode 100644 src/Model/Response/SecciRequest.php diff --git a/src/Model/Request/SecciRequest.php b/src/Model/Request/SecciRequest.php new file mode 100644 index 0000000..b9932d0 --- /dev/null +++ b/src/Model/Request/SecciRequest.php @@ -0,0 +1,31 @@ +getHead()->admittedFields['TransactionId'])) { + $this->setErrorMsg('Secci Request does not allow transaction id'); + + return false; + } + + return true; + } +} diff --git a/src/Model/Request/SubModel/Content.php b/src/Model/Request/SubModel/Content.php index 53a2415..584bde6 100644 --- a/src/Model/Request/SubModel/Content.php +++ b/src/Model/Request/SubModel/Content.php @@ -75,5 +75,9 @@ class Content extends AbstractModel 'mandatory' => false, 'instanceOf' => 'Content\\Additional', ], + 'Secci' => [ + 'mandatory' => false, + 'instanceOf' => 'Content\\Secci', + ], ]; } diff --git a/src/Model/Request/SubModel/Content/Payment.php b/src/Model/Request/SubModel/Content/Payment.php index cd72c7b..2e3aca2 100644 --- a/src/Model/Request/SubModel/Content/Payment.php +++ b/src/Model/Request/SubModel/Content/Payment.php @@ -49,6 +49,11 @@ class Payment extends AbstractModel 'isAttribute' => true, 'uppercase' => true, ], + 'Currency' => [ + 'mandatoryByRule' => false, + 'isAttribute' => true, + 'uppercase' => true, + ], 'Amount' => [ 'mandatory' => true, ], diff --git a/src/Model/Request/SubModel/Content/Secci.php b/src/Model/Request/SubModel/Content/Secci.php new file mode 100644 index 0000000..4c3d480 --- /dev/null +++ b/src/Model/Request/SubModel/Content/Secci.php @@ -0,0 +1,121 @@ + [ + 'mandatory' => true, + ], + 'DeliveryMethod' => [ + 'mandatory' => true, + ], + 'Email' => [ + 'mandatory' => false, + ], + 'Action' => [ + 'mandatory' => false, + ], + 'Language' => [ + 'mandatory' => false, + ], + 'Country' => [ + 'mandatory' => false, + ], + ]; + + + /** + * @param string $paymentMethod + * + * @return self + * + * @throws \RatePAY\Exception\ModelException + */ + public function setPaymentMethod($paymentMethod) + { + return $this->__set('PaymentMethod', $paymentMethod); + } + + /** + * @param string $deliveryMethod + * + * @return self + * + * @throws \RatePAY\Exception\ModelException + */ + public function setDeliveryMethod($deliveryMethod) + { + return $this->__set('DeliveryMethod', $deliveryMethod); + } + + /** + * @param string $email + * + * @return self + * + * @throws \RatePAY\Exception\ModelException + */ + public function setEmail($email) + { + return $this->__set('Email', $email); + } + + /** + * @param string $action + * + * @return self + * + * @throws \RatePAY\Exception\ModelException + */ + public function setAction($action) + { + return $this->__set('Action', $action); + } + + /** + * @param string $language + * + * @return self + * + * @throws \RatePAY\Exception\ModelException + */ + public function setLanguage($language) + { + return $this->__set('Language', $language); + } + + /** + * @param string $country + * + * @return self + * + * @throws \RatePAY\Exception\ModelException + */ + public function setCountry($country) + { + return $this->__set('Country', $country); + } +} diff --git a/src/Model/Request/SubModel/Head.php b/src/Model/Request/SubModel/Head.php index bc48c0e..50fc27e 100644 --- a/src/Model/Request/SubModel/Head.php +++ b/src/Model/Request/SubModel/Head.php @@ -83,6 +83,9 @@ class Head extends AbstractModel 'mandatory' => true, 'instanceOf' => 'Head\\Meta', ], + 'AttestationToken' => [ + 'mandatory' => false, + ], ]; /** diff --git a/src/Model/Response/SecciRequest.php b/src/Model/Response/SecciRequest.php new file mode 100644 index 0000000..e1d6c7e --- /dev/null +++ b/src/Model/Response/SecciRequest.php @@ -0,0 +1,69 @@ +getStatusCode() == 'OK' && $this->getResultCode() == 504) { + $this->setResult(['attestationToken' => (string)$this->getResponse()->content->{'secci-result'}->{'attestation-token'}]); + $this->setResult(['documentId' => (string)$this->getResponse()->content->{'secci-result'}->{'document-id'}]); + if (isset($this->getResponse()->content->{'secci-result'}->{'document'})) { + $this->setResult(['document' => (string)$this->getResponse()->content->{'secci-result'}->{'document'}]); + $this->setResult(['contentType' => (string)$this->getResponse()->content->{'secci-result'}->{'content-type'}]); + } + $this->setSuccessful(); + } + } + + /** + * Returns attestation token. + * + * @return string|null + */ + public function getAttestationToken() + { + return (key_exists('attestationToken', $this->result)) ? $this->result['attestationToken'] : null; + } + + /** + * Returns document id. + * + * @return string|null + */ + public function getDocumentId() + { + return (key_exists('documentId', $this->result)) ? $this->result['documentId'] : null; + } + + /** + * Returns document. + * + * @return string|null + */ + public function getDocument() + { + return (key_exists('document', $this->result)) ? $this->result['document'] : null; + } + + /** + * Returns content type of the document. + * + * @return string|null + */ + public function getContentType() + { + return (key_exists('contentType', $this->result)) ? $this->result['contentType'] : null; + } +} diff --git a/src/Service/ModelMapper.php b/src/Service/ModelMapper.php index 2e79deb..3022871 100644 --- a/src/Service/ModelMapper.php +++ b/src/Service/ModelMapper.php @@ -23,6 +23,7 @@ class ModelMapper 'PaymentChange' => 'PaymentChange', 'PaymentConfirm' => 'PaymentConfirm', 'ProfileRequest' => 'ProfileRequest', + 'SecciRequest' => 'SecciRequest', ]; private static $subModelNamePathMapping = [ @@ -57,6 +58,7 @@ class ModelMapper 'Payment' => 'Content\\Payment', 'InstallmentDetails' => 'Content\\Payment\\InstallmentDetails', 'Invoicing' => 'Content\\Invoicing', + 'Secci' => 'Content\\Secci', ]; public static function getFullPathRequestModel($requestedModel) From 6accbe109eeda1a7dd21b9d91130e3fdc172b539 Mon Sep 17 00:00:00 2001 From: Krystian Czerwinski Date: Fri, 11 Sep 2026 16:56:05 +0200 Subject: [PATCH 02/14] FC#0135237 - Added SECCI tests --- tests/Support/GatewayResponses.php | 39 +++++ tests/Unit/Model/Request/SecciRequestTest.php | 121 ++++++++++++++++ .../Request/SubModel/Content/PaymentTest.php | 82 +++++++++++ .../Request/SubModel/Content/SecciTest.php | 133 ++++++++++++++++++ .../Model/Request/SubModel/ContentTest.php | 99 +++++++++++++ .../Unit/Model/Request/SubModel/HeadTest.php | 27 ++++ .../Unit/Model/Response/SecciRequestTest.php | 124 ++++++++++++++++ tests/Unit/RequestBuilderTest.php | 38 +++++ tests/Unit/Service/ModelMapperTest.php | 10 ++ 9 files changed, 673 insertions(+) create mode 100644 tests/Unit/Model/Request/SecciRequestTest.php create mode 100644 tests/Unit/Model/Request/SubModel/Content/PaymentTest.php create mode 100644 tests/Unit/Model/Request/SubModel/Content/SecciTest.php create mode 100644 tests/Unit/Model/Request/SubModel/ContentTest.php create mode 100644 tests/Unit/Model/Response/SecciRequestTest.php diff --git a/tests/Support/GatewayResponses.php b/tests/Support/GatewayResponses.php index dce3c83..df86682 100644 --- a/tests/Support/GatewayResponses.php +++ b/tests/Support/GatewayResponses.php @@ -157,6 +157,45 @@ public function getAutoConfirmationDeliveryResponse($params = []) return new Response($this->processXmlTemplate($xml, $bindings)); } + public function getSecciRequestResponse($params = []) + { + $bindings = array_merge( + [ + 'system-id' => 'FooSystem', + 'attestation-token' => 'foo-attestation-token', + 'document-id' => 'SCE2QIAE-10092026', + 'status-code' => 'OK', + 'reason-code' => '308', + 'result-code' => '504', + ], + $params + ); + + $xml = ' + + + {{ system-id }} + SECCI_REQUEST + SECCI_DOCUMENT + + + + + + + + + + + {{ attestation-token }} + {{ document-id }} + + + '; + + return new Response($this->processXmlTemplate($xml, $bindings)); + } + /** * @param string $template * @param array $bindings diff --git a/tests/Unit/Model/Request/SecciRequestTest.php b/tests/Unit/Model/Request/SecciRequestTest.php new file mode 100644 index 0000000..7102fd3 --- /dev/null +++ b/tests/Unit/Model/Request/SecciRequestTest.php @@ -0,0 +1,121 @@ +setHead($head->getModel()); + + $this->assertTrue($request->rule()); + } + + public function testRuleFailed() + { + $head = new ModelBuilder(); + $head->setTransactionId('foo-1234567890'); + + $request = new SecciRequest(); + $request->setHead($head->getModel()); + + $this->assertFalse($request->rule()); + $this->assertEquals('Secci Request does not allow transaction id', $request->getErrorMsg()); + } + + public function testArrayConversion() + { + $head = new ModelBuilder(); + $head->setArray([ + 'SystemId' => 'SuperSystem', + 'Operation' => 'SECCI', + 'Credential' => [ + 'ProfileId' => 'MY_AMAZING_PROFILE', + 'Securitycode' => 'super-secure-code', + ], + ]); + + $content = new ModelBuilder('Content'); + $content->setArray([ + 'Secci' => [ + 'PaymentMethod' => 'INSTALLMENT', + 'DeliveryMethod' => 'EMAIL', + 'Email' => 'test@example.com', + ], + ]); + + $request = new SecciRequest(); + $request->setHead($head->getModel()); + $request->setContent($content->getModel()); + + $data = $request->toArray(); + + $this->assertTypeIsArray($data); + $this->assertArrayHasKey('head', $data); + $this->assertArrayHasKey('content', $data); + + $expected = print_r([ + 'secci' => [ + 'payment-method' => ['value' => 'INSTALLMENT'], + 'delivery-method' => ['value' => 'EMAIL'], + 'email' => ['value' => 'test@example.com'], + ], + ], true); + $current = print_r($data['content'], true); + $this->assertEquals($expected, $current); + } + + public function testArrayConversionFailsOnTransactionId() + { + $head = new ModelBuilder(); + $head->setArray([ + 'SystemId' => 'SuperSystem', + 'Operation' => 'SECCI', + 'TransactionId' => 'foo-1234567890', + 'Credential' => [ + 'ProfileId' => 'MY_AMAZING_PROFILE', + 'Securitycode' => 'super-secure-code', + ], + ]); + + $content = new ModelBuilder('Content'); + $content->setArray([ + 'Secci' => [ + 'PaymentMethod' => 'INSTALLMENT', + 'DeliveryMethod' => 'EMAIL', + ], + ]); + + $request = new SecciRequest(); + $request->setHead($head->getModel()); + $request->setContent($content->getModel()); + + $this->expectException(RuleSetException::class); + $this->expectExceptionMessage('Secci Request does not allow transaction id'); + + $request->toArray(); + } + + public function assertTypeIsArray($data) + { + if (method_exists($this, 'assertIsArray')) { + $this->assertIsArray($data); + } else { + $this->assertInternalType('array', $data); + } + } +} diff --git a/tests/Unit/Model/Request/SubModel/Content/PaymentTest.php b/tests/Unit/Model/Request/SubModel/Content/PaymentTest.php new file mode 100644 index 0000000..12fb35a --- /dev/null +++ b/tests/Unit/Model/Request/SubModel/Content/PaymentTest.php @@ -0,0 +1,82 @@ +setMethod('INVOICE') + ->setCurrency('EUR') + ->setAmount(100.00); + + $array = $payment->toArray(); + + $expected = [ + 'attributes' => [ + 'method' => ['value' => 'INVOICE'], + 'currency' => ['value' => 'EUR'], + ], + 'amount' => ['value' => 100.00], + ]; + + $this->assertEquals($expected, $array); + } + + public function testCurrencyIsUppercased() + { + $payment = (new Payment()) + ->setMethod('INVOICE') + ->setCurrency('eur') + ->setAmount(100.00); + + $array = $payment->toArray(); + + $this->assertEquals('EUR', $array['attributes']['currency']['value']); + } + + public function testCurrencyIsOptional() + { + $payment = (new Payment()) + ->setMethod('INVOICE') + ->setAmount(100.00); + + $array = $payment->toArray(); + + $this->assertNull($payment->getCurrency()); + $this->assertArrayNotHasKey('currency', $array['attributes']); + } + + public function testGetCurrency() + { + $payment = new Payment(); + $payment->setCurrency('EUR'); + + $this->assertEquals('EUR', $payment->getCurrency()); + } + + public function testHandleCurrencyByModelBuilder() + { + $builder = new ModelBuilder('Payment'); + $builder->setArray([ + 'Method' => 'INVOICE', + 'Currency' => 'EUR', + 'Amount' => 100.00, + ]); + + $array = $builder->getModel()->toArray(); + + $this->assertEquals('EUR', $array['attributes']['currency']['value']); + } +} diff --git a/tests/Unit/Model/Request/SubModel/Content/SecciTest.php b/tests/Unit/Model/Request/SubModel/Content/SecciTest.php new file mode 100644 index 0000000..e8e8cd4 --- /dev/null +++ b/tests/Unit/Model/Request/SubModel/Content/SecciTest.php @@ -0,0 +1,133 @@ +setPaymentMethod('INSTALLMENT') + ->setDeliveryMethod('EMAIL'); + + $array = $secci->toArray(); + + $expected = [ + 'payment-method' => ['value' => 'INSTALLMENT'], + 'delivery-method' => ['value' => 'EMAIL'], + ]; + + $this->assertEquals($expected, $array); + } + + public function testToArrayWithAllFields() + { + $secci = (new Secci()) + ->setPaymentMethod('INSTALLMENT') + ->setDeliveryMethod('EMAIL') + ->setEmail('test@example.com') + ->setAction('REQUEST') + ->setLanguage('DE') + ->setCountry('DE'); + + $array = $secci->toArray(); + + $expected = [ + 'payment-method' => ['value' => 'INSTALLMENT'], + 'delivery-method' => ['value' => 'EMAIL'], + 'email' => ['value' => 'test@example.com'], + 'action' => ['value' => 'REQUEST'], + 'language' => ['value' => 'DE'], + 'country' => ['value' => 'DE'], + ]; + + $this->assertEquals($expected, $array); + } + + public function testSetterReturnsModel() + { + $secci = new Secci(); + + $this->assertSame($secci, $secci->setPaymentMethod('INSTALLMENT')); + } + + public function testGetters() + { + $secci = (new Secci()) + ->setPaymentMethod('INSTALLMENT') + ->setDeliveryMethod('EMAIL') + ->setEmail('test@example.com') + ->setAction('REQUEST') + ->setLanguage('DE') + ->setCountry('DE'); + + $this->assertEquals('INSTALLMENT', $secci->getPaymentMethod()); + $this->assertEquals('EMAIL', $secci->getDeliveryMethod()); + $this->assertEquals('test@example.com', $secci->getEmail()); + $this->assertEquals('REQUEST', $secci->getAction()); + $this->assertEquals('DE', $secci->getLanguage()); + $this->assertEquals('DE', $secci->getCountry()); + } + + public function testGetterReturnsNullIfNotSet() + { + $secci = new Secci(); + + $this->assertNull($secci->getEmail()); + } + + public function testThrowErrorIfNoPaymentMethod() + { + $secci = new Secci(); + $secci->setDeliveryMethod('EMAIL'); + + $this->expectException(ModelException::class); + $this->expectExceptionMessage('Model exception : Field \'PaymentMethod\' is required'); + + $secci->toArray(); + } + + public function testThrowErrorIfNoDeliveryMethod() + { + $secci = new Secci(); + $secci->setPaymentMethod('INSTALLMENT'); + + $this->expectException(ModelException::class); + $this->expectExceptionMessage('Model exception : Field \'DeliveryMethod\' is required'); + + $secci->toArray(); + } + + public function testBuildByModelBuilder() + { + $builder = new ModelBuilder('Secci'); + $builder->setArray([ + 'PaymentMethod' => 'INSTALLMENT', + 'DeliveryMethod' => 'EMAIL', + 'Email' => 'test@example.com', + ]); + + $secci = $builder->getModel(); + + $this->assertInstanceOf(Secci::class, $secci); + + $expected = [ + 'payment-method' => ['value' => 'INSTALLMENT'], + 'delivery-method' => ['value' => 'EMAIL'], + 'email' => ['value' => 'test@example.com'], + ]; + + $this->assertEquals($expected, $secci->toArray()); + } +} diff --git a/tests/Unit/Model/Request/SubModel/ContentTest.php b/tests/Unit/Model/Request/SubModel/ContentTest.php new file mode 100644 index 0000000..15e8f85 --- /dev/null +++ b/tests/Unit/Model/Request/SubModel/ContentTest.php @@ -0,0 +1,99 @@ +assertEquals([], $content->toArray()); + } + + public function testHandleSecci() + { + $secci = (new Secci()) + ->setPaymentMethod('INSTALLMENT') + ->setDeliveryMethod('EMAIL'); + + $content = new Content(); + $content->setSecci($secci); + + $array = $content->toArray(); + + $expectedSecci = [ + 'payment-method' => ['value' => 'INSTALLMENT'], + 'delivery-method' => ['value' => 'EMAIL'], + ]; + + $this->assertEquals($expectedSecci, $array['secci']); + } + + public function testGetSecci() + { + $secci = (new Secci()) + ->setPaymentMethod('INSTALLMENT') + ->setDeliveryMethod('EMAIL'); + + $content = new Content(); + $content->setSecci($secci); + + $this->assertSame($secci, $content->getSecci()); + } + + public function testSecciIsOptional() + { + $content = new Content(); + + $this->assertNull($content->getSecci()); + $this->assertArrayNotHasKey('secci', $content->toArray()); + } + + public function testThrowErrorOnWrongSecciInstance() + { + $content = new Content(); + + $this->expectException(ModelException::class); + $this->expectExceptionMessage('Model exception : Wrong class instance set to \'Secci\''); + + $content->setSecci(new Invoicing()); + } + + public function testHandleSecciByModelBuilder() + { + $builder = new ModelBuilder('Content'); + $builder->setArray([ + 'Secci' => [ + 'PaymentMethod' => 'INSTALLMENT', + 'DeliveryMethod' => 'EMAIL', + 'Email' => 'test@example.com', + ], + ]); + + $content = $builder->getModel(); + + $this->assertInstanceOf(Secci::class, $content->getSecci()); + + $expectedSecci = [ + 'payment-method' => ['value' => 'INSTALLMENT'], + 'delivery-method' => ['value' => 'EMAIL'], + 'email' => ['value' => 'test@example.com'], + ]; + + $this->assertEquals($expectedSecci, $content->toArray()['secci']); + } +} diff --git a/tests/Unit/Model/Request/SubModel/HeadTest.php b/tests/Unit/Model/Request/SubModel/HeadTest.php index eafcf0d..e653490 100644 --- a/tests/Unit/Model/Request/SubModel/HeadTest.php +++ b/tests/Unit/Model/Request/SubModel/HeadTest.php @@ -38,6 +38,33 @@ public function testSubtypeSet() $this->assertTrue($head->isSubtypeSet()); } + public function testAttestationTokenIsOptional() + { + $head = new Head(); + $head->setSystemId('test-system'); + $head->setOperation('testing'); + $head->setCredential((new Credential())->setProfileId('MY_PROFILE')->setSecuritycode('5€CUr|tyK0D3')); + + $array = $head->toArray(); + + $this->assertNull($head->getAttestationToken()); + $this->assertArrayNotHasKey('attestation-token', $array); + } + + public function testHandleAttestationToken() + { + $head = new Head(); + $head->setSystemId('test-system'); + $head->setOperation('testing'); + $head->setCredential((new Credential())->setProfileId('MY_PROFILE')->setSecuritycode('5€CUr|tyK0D3')); + $head->setAttestationToken('foo-attestation-token'); + + $array = $head->toArray(); + + $this->assertEquals('foo-attestation-token', $head->getAttestationToken()); + $this->assertEquals(['value' => 'foo-attestation-token'], $array['attestation-token']); + } + public function testThrowErrorIfNoSystemId() { $head = new Head(); diff --git a/tests/Unit/Model/Response/SecciRequestTest.php b/tests/Unit/Model/Response/SecciRequestTest.php new file mode 100644 index 0000000..70a4e13 --- /dev/null +++ b/tests/Unit/Model/Response/SecciRequestTest.php @@ -0,0 +1,124 @@ +getResponseXml($statusCode, $resultCode); + + $response = new SecciRequest($xml); + $response->validateResponse(); + + $this->assertEquals($expectedSuccess, $response->isSuccessful()); + } + + public function provideValidableResponses() + { + return [ + ['CLOSED', 200, false], + ['UNKNOWN', 504, false], + ['OK', 200, false], + ['OK', 504, true], + ]; + } + + public function testGetsSecciResult() + { + $xml = $this->getResponseXml('OK', 504); + + $response = new SecciRequest($xml); + $response->validateResponse(); + + $this->assertTrue($response->isSuccessful()); + $this->assertEquals('foo-attestation-token', $response->getAttestationToken()); + $this->assertEquals('SCE2QIAE-10092026', $response->getDocumentId()); + $this->assertNull($response->getDocument()); + $this->assertNull($response->getContentType()); + } + + public function testGetsSecciResultWithDocument() + { + $document = 'JVBERi0xLjQK + application/pdf'; + $xml = $this->getResponseXml('OK', 504, $document); + + $response = new SecciRequest($xml); + $response->validateResponse(); + + $this->assertTrue($response->isSuccessful()); + $this->assertEquals('JVBERi0xLjQK', $response->getDocument()); + $this->assertEquals('application/pdf', $response->getContentType()); + } + + public function testGetsEmptyAttestationToken() + { + $xml = $this->getResponseXml('OK', 504); + $xml->content->{'secci-result'}->{'attestation-token'} = ''; + + $response = new SecciRequest($xml); + $response->validateResponse(); + + $this->assertSame('', $response->getAttestationToken()); + } + + public function testGettersReturnNullIfResponseIsNotSuccessful() + { + $xml = $this->getResponseXml('CLOSED', 200); + + $response = new SecciRequest($xml); + $response->validateResponse(); + + $this->assertFalse($response->isSuccessful()); + $this->assertNull($response->getAttestationToken()); + $this->assertNull($response->getDocumentId()); + $this->assertNull($response->getDocument()); + $this->assertNull($response->getContentType()); + } + + /** + * @return \SimpleXMLElement + */ + protected function getResponseXml($statusCode, $resultCode, $document = '') + { + $content = ' + + + Example + SECCI_REQUEST + SECCI_DOCUMENT + + + 2026-09-10T11:03:58.000 + Successfully + SECCI document generated successfully + SECCI generation successful + + + + + foo-attestation-token + SCE2QIAE-10092026 + __DOCUMENT__ + + + '; + $content = str_replace('__STATUS_CODE__', $statusCode, $content); + $content = str_replace('__REASON_CODE__', '308', $content); + $content = str_replace('__RESULT_CODE__', $resultCode, $content); + $content = str_replace('__DOCUMENT__', $document, $content); + + return new \SimpleXMLElement($content); + } +} diff --git a/tests/Unit/RequestBuilderTest.php b/tests/Unit/RequestBuilderTest.php index 231da39..a0bca11 100644 --- a/tests/Unit/RequestBuilderTest.php +++ b/tests/Unit/RequestBuilderTest.php @@ -274,4 +274,42 @@ public function testCallPaymentChangeCredit() $this->assertTrue($response->isSuccessful()); } + + public function testCallSecciRequest() + { + self::$gateway->setResponseOfPath( + '/', + $this->getSecciRequestResponse() + ); + + $builder = new RequestBuilder(true, self::$gateway->getServerRoot()); + + $head = new ModelBuilder(); + $head->setArray([ + 'SystemId' => 'SuperSystem', + 'Credential' => [ + 'ProfileId' => 'MY_AMAZING_PROFILE', + 'Securitycode' => 'super-secure-code', + ], + ]); + + $content = new ModelBuilder('Content'); + $content->setArray([ + 'Secci' => [ + 'PaymentMethod' => 'INSTALLMENT', + 'DeliveryMethod' => 'EMAIL', + 'Email' => 'test@example.com', + ], + ]); + + $response = $builder->callSecciRequest($head, $content); + + $this->assertTrue($response->isSuccessful()); + $this->assertEquals('foo-attestation-token', $response->getAttestationToken()); + $this->assertEquals('SCE2QIAE-10092026', $response->getDocumentId()); + + $requestRaw = $builder->getRequestRaw(); + $this->assertStringContainsString('SECCI_REQUEST', $requestRaw); + $this->assertStringContainsString('INSTALLMENT', $requestRaw); + } } diff --git a/tests/Unit/Service/ModelMapperTest.php b/tests/Unit/Service/ModelMapperTest.php index 79a7678..3a49356 100644 --- a/tests/Unit/Service/ModelMapperTest.php +++ b/tests/Unit/Service/ModelMapperTest.php @@ -33,6 +33,7 @@ public function provideRequestModels() ["PaymentChange", \RatePAY\Model\Request\PaymentChange::class], ["PaymentConfirm", \RatePAY\Model\Request\PaymentConfirm::class], ["ProfileRequest", \RatePAY\Model\Request\ProfileRequest::class], + ["SecciRequest", \RatePAY\Model\Request\SecciRequest::class], ]; } @@ -75,6 +76,7 @@ public function provideRequestSubModels() ['Payment', \RatePAY\Model\Request\SubModel\Content\Payment::class], ['InstallmentDetails', \RatePAY\Model\Request\SubModel\Content\Payment\InstallmentDetails::class], ['Invoicing', \RatePAY\Model\Request\SubModel\Content\Invoicing::class], + ['Secci', \RatePAY\Model\Request\SubModel\Content\Secci::class], ]; } @@ -98,6 +100,14 @@ public function provideResponseModels() ['PaymentQuery', \RatePAY\Model\Response\PaymentQuery::class], ['PaymentRequest', \RatePAY\Model\Response\PaymentRequest::class], ['ProfileRequest', \RatePAY\Model\Response\ProfileRequest::class], + ['SecciRequest', \RatePAY\Model\Response\SecciRequest::class], ]; } + + public function testGetRequestModels() + { + $requestModels = ModelMapper::getRequestModels(); + + $this->assertContains('SecciRequest', $requestModels); + } } From d25f018683e0349d9b23c936e75743eb9353dd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 14 Sep 2026 15:51:30 +0200 Subject: [PATCH 03/14] FC#0135237 - Added SECCI request for CCD2 to the php lib --- src/Model/Response/SecciRequest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Model/Response/SecciRequest.php b/src/Model/Response/SecciRequest.php index e1d6c7e..715deb7 100644 --- a/src/Model/Response/SecciRequest.php +++ b/src/Model/Response/SecciRequest.php @@ -17,11 +17,11 @@ class SecciRequest extends AbstractResponse public function validateResponse() { if ($this->getStatusCode() == 'OK' && $this->getResultCode() == 504) { - $this->setResult(['attestationToken' => (string)$this->getResponse()->content->{'secci-result'}->{'attestation-token'}]); - $this->setResult(['documentId' => (string)$this->getResponse()->content->{'secci-result'}->{'document-id'}]); + $this->setResult(['attestationToken' => (string) $this->getResponse()->content->{'secci-result'}->{'attestation-token'}]); + $this->setResult(['documentId' => (string) $this->getResponse()->content->{'secci-result'}->{'document-id'}]); if (isset($this->getResponse()->content->{'secci-result'}->{'document'})) { - $this->setResult(['document' => (string)$this->getResponse()->content->{'secci-result'}->{'document'}]); - $this->setResult(['contentType' => (string)$this->getResponse()->content->{'secci-result'}->{'content-type'}]); + $this->setResult(['document' => (string) $this->getResponse()->content->{'secci-result'}->{'document'}]); + $this->setResult(['contentType' => (string) $this->getResponse()->content->{'secci-result'}->{'content-type'}]); } $this->setSuccessful(); } From f7d9bf8af6dffc6460d5f94c071e24b1d2fce01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 14 Sep 2026 15:55:19 +0200 Subject: [PATCH 04/14] FC#0135237 - Added SECCI request for CCD2 to the php lib --- src/Model/Request/SubModel/Content/Secci.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Model/Request/SubModel/Content/Secci.php b/src/Model/Request/SubModel/Content/Secci.php index 4c3d480..8229b2e 100644 --- a/src/Model/Request/SubModel/Content/Secci.php +++ b/src/Model/Request/SubModel/Content/Secci.php @@ -45,8 +45,7 @@ class Secci extends AbstractModel 'mandatory' => false, ], ]; - - + /** * @param string $paymentMethod * From e892ac8b5d1a7ba392f25efef5447703e6520b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 14 Sep 2026 15:59:51 +0200 Subject: [PATCH 05/14] FC#0135237 - Added SECCI request for CCD2 to the php lib --- src/Model/Request/SubModel/Content/Secci.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Model/Request/SubModel/Content/Secci.php b/src/Model/Request/SubModel/Content/Secci.php index 8229b2e..55fd6c1 100644 --- a/src/Model/Request/SubModel/Content/Secci.php +++ b/src/Model/Request/SubModel/Content/Secci.php @@ -1,5 +1,12 @@ false, ], ]; - + /** * @param string $paymentMethod * From de8a3167a0461636fe8df3aa9a7440a2e6a25305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 16 Sep 2026 18:16:11 +0200 Subject: [PATCH 06/14] FC#0135237 - Added SECCI request for CCD2 to the php lib --- src/Model/Request/SubModel/Content/Secci.php | 29 ++++++++++++++--- src/Model/Response/SecciRequest.php | 3 +- src/locales/de.php | 20 ++++++++++++ src/locales/en.php | 19 ++++++++++++ tests/Unit/Model/Request/SecciRequestTest.php | 3 -- .../Request/SubModel/Content/SecciTest.php | 31 +++++++------------ .../Model/Request/SubModel/ContentTest.php | 11 ++----- .../Unit/Model/Response/SecciRequestTest.php | 2 +- tests/Unit/RequestBuilderTest.php | 3 +- 9 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/Model/Request/SubModel/Content/Secci.php b/src/Model/Request/SubModel/Content/Secci.php index 55fd6c1..c5311a0 100644 --- a/src/Model/Request/SubModel/Content/Secci.php +++ b/src/Model/Request/SubModel/Content/Secci.php @@ -33,26 +33,45 @@ class Secci extends AbstractModel * @var array */ public $admittedFields = [ - 'PaymentMethod' => [ - 'mandatory' => true, - ], 'DeliveryMethod' => [ 'mandatory' => true, + 'uppercase' => true, ], 'Email' => [ - 'mandatory' => false, + 'mandatoryByRule' => true, ], 'Action' => [ 'mandatory' => false, + 'uppercase' => true, ], 'Language' => [ 'mandatory' => false, + 'uppercase' => true, ], - 'Country' => [ + 'CountryCode' => [ 'mandatory' => false, + 'uppercase' => true, ], ]; + /** + * Installment details rule : if payment method is installment, InstallmentDetails are mandatory. + * + * @return bool + */ + protected function rule() + { + if ('EMAIL' == $this->admittedFields['DeliveryMethod']['value'] && + (!key_exists('value', $this->admittedFields['Email'])) + ) { + $this->setErrorMsg('email details missing'); + + return false; + } + + return true; + } + /** * @param string $paymentMethod * diff --git a/src/Model/Response/SecciRequest.php b/src/Model/Response/SecciRequest.php index 715deb7..26b582e 100644 --- a/src/Model/Response/SecciRequest.php +++ b/src/Model/Response/SecciRequest.php @@ -54,7 +54,8 @@ public function getDocumentId() */ public function getDocument() { - return (key_exists('document', $this->result)) ? $this->result['document'] : null; + // Document variable comes as base64 encoded string! + return (key_exists('document', $this->result)) ? base64_decode($this->result['document']) : null; } /** diff --git a/src/locales/de.php b/src/locales/de.php index 2deddef..5ade66a 100644 --- a/src/locales/de.php +++ b/src/locales/de.php @@ -83,4 +83,24 @@ 'wcd_sepa_terms_block_1' => 'Ich ermächtige die Ratepay GmbH von meinem Konto mittels Lastschrift einzuziehen. Zugleich weise ich mein Kreditinstitut an, die von der Ratepay GmbH auf mein Konto gezogenen Lastschriften einzulösen.', 'wcd_sepa_terms_block_2' => 'Ich kann innerhalb von acht Wochen, beginnend mit dem Belastungsdatum, die Erstattung des belasteten Betrages verlangen.', 'wcd_sepa_terms_block_3' => 'Es gelten dabei die mit dem Kreditinstitut vereinbarten Bedingungen.', + 'rp_secci_header' => 'EU-Standardinformationen für Verbraucherkredite', + 'rp_secci_choose_delivery_method' => 'Wählen Sie vor Abschluss Ihrer Bestellung, wie Sie diese Informationen erhalten möchten.', + 'rp_secci_learn_more' => 'Mehr erfahren', + 'rp_secci_description' => 'Die EU-Verbraucherkreditrichtlinien haben sich geändert und erfordern nun zusätzliche Informationen für Zahlung in 3 Raten und bestimmte Rechnungskäufe. Diese Informationen helfen Ihnen, die wesentlichen Kreditkonditionen vor Abschluss Ihres Kaufs zu verstehen. Unser Zahlungspartner Ratepay verwendet Ihre E-Mail-Adresse ausschließlich zum Versand dieser Informationen über einen externen E-Mail-Dienstleister.', + 'rp_secci_get_by_email' => 'Per E-Mail erhalten', + 'rp_secci_download_pdf' => 'PDF herunterladen', + 'rp_secci_choose_email' => 'Wir haben die erforderlichen EU-Standardinformationen für Verbraucherkredite gesendet an', + 'rp_secci_payment_methods' => 'Zahlungsart', + 'rp_secci_choose_payment_method' => 'Wenn Sie Rechnungskauf oder Zahle in 3 Raten wählen, werden diese Informationen automatisch an', + 'rp_secci_choose_payment_method2' => 'gesendet.', + 'rp_secci_change_email' => 'E-Mail ändern', + 'rp_secci_save' => 'Speichern', + 'rp_secci_method_invoice' => 'Ratepay Rechnung', + 'rp_secci_method_invoice_desc' => 'In 30 Tagen bezahlen.', + 'rp_secci_method_paypal_desc' => 'Sie werden zu PayPal weitergeleitet.', + 'rp_secci_method_cod' => 'Nachnahme', + 'rp_secci_method_cod_desc' => 'Zahlung bei Erhalt der Ware.', + 'rp_secci_method_installment' => 'Ratepay Zahle in 3 Raten', + 'rp_secci_method_installment_desc' => 'In 3 monatlichen Raten bezahlen.', + 'rp_secci_method_installment_desc2' => '(Ratenrechner hier)', ]; diff --git a/src/locales/en.php b/src/locales/en.php index 9f8e798..59c5e35 100644 --- a/src/locales/en.php +++ b/src/locales/en.php @@ -84,4 +84,23 @@ 'wcd_sepa_terms_block_1' => 'I hereby authorise Ratepay GmbH to collect payments from my account by direct debit. At the same time, I authorise my bank to debit my account in accordance with the instructions from Ratepay GmbH.', 'wcd_sepa_terms_block_2' => 'As part of my rights, I am entitled to a refund from my bank under the terms and conditions of my agreement with my bank. A refund must be claimed within 8 weeks starting from the date on which my account was debited. ', 'wcd_sepa_terms_block_3' => 'My rights are explained in a statement that I can obtain from my bank.', + 'rp_secci_header' => 'Standard EU Consumer Credit Information', + 'rp_secci_choose_delivery_method' => 'Before placing your order, choose how you’d like to receive this information.', + 'rp_secci_learn_more' => 'Learn more', + 'rp_secci_description' => 'EU consumer credit rules have changed and now require additional information for this payment method. This information helps you understand the key credit terms before completing your purchase. If you choose Get by email, our payment partner Ratepay will use your email address only to send this information, using a third-party email delivery provider.', + 'rp_secci_get_by_email' => 'Get by email', + 'rp_secci_download_pdf' => 'Download PDF', + 'rp_secci_payment_methods' => 'Payment Method', + 'rp_secci_choose_payment_method' => 'Selecting Open invoice or installment purchase will automatically send this information to', + 'rp_secci_choose_payment_method2' => 'sent.', + 'rp_secci_change_email' => 'Change email', + 'rp_secci_save' => 'Save', + 'rp_secci_method_invoice' => 'Ratepay Invoice', + 'rp_secci_method_invoice_desc' => 'Pay in 30 days.', + 'rp_secci_method_paypal_desc' => 'You will be redirected to PayPal.', + 'rp_secci_method_cod' => 'Cash on delivery', + 'rp_secci_method_cod_desc' => 'Payment upon receipt of the goods.', + 'rp_secci_method_installment' => 'Ratepay Installment Purchase', + 'rp_secci_method_installment_desc' => 'Pay in monthly installments.', + 'rp_secci_method_installment_desc2' => '(Installment calculator here)', ]; diff --git a/tests/Unit/Model/Request/SecciRequestTest.php b/tests/Unit/Model/Request/SecciRequestTest.php index 7102fd3..8f6fd85 100644 --- a/tests/Unit/Model/Request/SecciRequestTest.php +++ b/tests/Unit/Model/Request/SecciRequestTest.php @@ -52,7 +52,6 @@ public function testArrayConversion() $content = new ModelBuilder('Content'); $content->setArray([ 'Secci' => [ - 'PaymentMethod' => 'INSTALLMENT', 'DeliveryMethod' => 'EMAIL', 'Email' => 'test@example.com', ], @@ -70,7 +69,6 @@ public function testArrayConversion() $expected = print_r([ 'secci' => [ - 'payment-method' => ['value' => 'INSTALLMENT'], 'delivery-method' => ['value' => 'EMAIL'], 'email' => ['value' => 'test@example.com'], ], @@ -95,7 +93,6 @@ public function testArrayConversionFailsOnTransactionId() $content = new ModelBuilder('Content'); $content->setArray([ 'Secci' => [ - 'PaymentMethod' => 'INSTALLMENT', 'DeliveryMethod' => 'EMAIL', ], ]); diff --git a/tests/Unit/Model/Request/SubModel/Content/SecciTest.php b/tests/Unit/Model/Request/SubModel/Content/SecciTest.php index e8e8cd4..11e5b6b 100644 --- a/tests/Unit/Model/Request/SubModel/Content/SecciTest.php +++ b/tests/Unit/Model/Request/SubModel/Content/SecciTest.php @@ -10,6 +10,7 @@ use PHPUnit\Framework\TestCase; use RatePAY\Exception\ModelException; +use RatePAY\Exception\RuleSetException; use RatePAY\Model\Request\SubModel\Content\Secci; use RatePAY\ModelBuilder; @@ -18,14 +19,12 @@ class SecciTest extends TestCase public function testToArrayWithMandatoryFields() { $secci = (new Secci()) - ->setPaymentMethod('INSTALLMENT') - ->setDeliveryMethod('EMAIL'); + ->setDeliveryMethod('PDF'); $array = $secci->toArray(); $expected = [ - 'payment-method' => ['value' => 'INSTALLMENT'], - 'delivery-method' => ['value' => 'EMAIL'], + 'delivery-method' => ['value' => 'PDF'], ]; $this->assertEquals($expected, $array); @@ -34,22 +33,20 @@ public function testToArrayWithMandatoryFields() public function testToArrayWithAllFields() { $secci = (new Secci()) - ->setPaymentMethod('INSTALLMENT') ->setDeliveryMethod('EMAIL') ->setEmail('test@example.com') ->setAction('REQUEST') ->setLanguage('DE') - ->setCountry('DE'); + ->setCountryCode('DE'); $array = $secci->toArray(); $expected = [ - 'payment-method' => ['value' => 'INSTALLMENT'], 'delivery-method' => ['value' => 'EMAIL'], 'email' => ['value' => 'test@example.com'], 'action' => ['value' => 'REQUEST'], 'language' => ['value' => 'DE'], - 'country' => ['value' => 'DE'], + 'country-code' => ['value' => 'DE'], ]; $this->assertEquals($expected, $array); @@ -59,25 +56,23 @@ public function testSetterReturnsModel() { $secci = new Secci(); - $this->assertSame($secci, $secci->setPaymentMethod('INSTALLMENT')); + $this->assertSame($secci, $secci->setDeliveryMethod('PDF')); } public function testGetters() { $secci = (new Secci()) - ->setPaymentMethod('INSTALLMENT') ->setDeliveryMethod('EMAIL') ->setEmail('test@example.com') ->setAction('REQUEST') ->setLanguage('DE') - ->setCountry('DE'); + ->setCountryCode('DE'); - $this->assertEquals('INSTALLMENT', $secci->getPaymentMethod()); $this->assertEquals('EMAIL', $secci->getDeliveryMethod()); $this->assertEquals('test@example.com', $secci->getEmail()); $this->assertEquals('REQUEST', $secci->getAction()); $this->assertEquals('DE', $secci->getLanguage()); - $this->assertEquals('DE', $secci->getCountry()); + $this->assertEquals('DE', $secci->getCountryCode()); } public function testGetterReturnsNullIfNotSet() @@ -87,13 +82,13 @@ public function testGetterReturnsNullIfNotSet() $this->assertNull($secci->getEmail()); } - public function testThrowErrorIfNoPaymentMethod() + public function testThrowErrorIfNoEmailAddress() { $secci = new Secci(); $secci->setDeliveryMethod('EMAIL'); - $this->expectException(ModelException::class); - $this->expectExceptionMessage('Model exception : Field \'PaymentMethod\' is required'); + $this->expectException(RuleSetException::class); + $this->expectExceptionMessage('Rule set exception : email details missing'); $secci->toArray(); } @@ -101,7 +96,7 @@ public function testThrowErrorIfNoPaymentMethod() public function testThrowErrorIfNoDeliveryMethod() { $secci = new Secci(); - $secci->setPaymentMethod('INSTALLMENT'); + $secci->setCountryCode('DE'); $this->expectException(ModelException::class); $this->expectExceptionMessage('Model exception : Field \'DeliveryMethod\' is required'); @@ -113,7 +108,6 @@ public function testBuildByModelBuilder() { $builder = new ModelBuilder('Secci'); $builder->setArray([ - 'PaymentMethod' => 'INSTALLMENT', 'DeliveryMethod' => 'EMAIL', 'Email' => 'test@example.com', ]); @@ -123,7 +117,6 @@ public function testBuildByModelBuilder() $this->assertInstanceOf(Secci::class, $secci); $expected = [ - 'payment-method' => ['value' => 'INSTALLMENT'], 'delivery-method' => ['value' => 'EMAIL'], 'email' => ['value' => 'test@example.com'], ]; diff --git a/tests/Unit/Model/Request/SubModel/ContentTest.php b/tests/Unit/Model/Request/SubModel/ContentTest.php index 15e8f85..43fcc26 100644 --- a/tests/Unit/Model/Request/SubModel/ContentTest.php +++ b/tests/Unit/Model/Request/SubModel/ContentTest.php @@ -27,8 +27,7 @@ public function testEmptyContent() public function testHandleSecci() { $secci = (new Secci()) - ->setPaymentMethod('INSTALLMENT') - ->setDeliveryMethod('EMAIL'); + ->setDeliveryMethod('PDF'); $content = new Content(); $content->setSecci($secci); @@ -36,8 +35,7 @@ public function testHandleSecci() $array = $content->toArray(); $expectedSecci = [ - 'payment-method' => ['value' => 'INSTALLMENT'], - 'delivery-method' => ['value' => 'EMAIL'], + 'delivery-method' => ['value' => 'PDF'], ]; $this->assertEquals($expectedSecci, $array['secci']); @@ -46,8 +44,7 @@ public function testHandleSecci() public function testGetSecci() { $secci = (new Secci()) - ->setPaymentMethod('INSTALLMENT') - ->setDeliveryMethod('EMAIL'); + ->setDeliveryMethod('PDF'); $content = new Content(); $content->setSecci($secci); @@ -78,7 +75,6 @@ public function testHandleSecciByModelBuilder() $builder = new ModelBuilder('Content'); $builder->setArray([ 'Secci' => [ - 'PaymentMethod' => 'INSTALLMENT', 'DeliveryMethod' => 'EMAIL', 'Email' => 'test@example.com', ], @@ -89,7 +85,6 @@ public function testHandleSecciByModelBuilder() $this->assertInstanceOf(Secci::class, $content->getSecci()); $expectedSecci = [ - 'payment-method' => ['value' => 'INSTALLMENT'], 'delivery-method' => ['value' => 'EMAIL'], 'email' => ['value' => 'test@example.com'], ]; diff --git a/tests/Unit/Model/Response/SecciRequestTest.php b/tests/Unit/Model/Response/SecciRequestTest.php index 70a4e13..6bc2d9f 100644 --- a/tests/Unit/Model/Response/SecciRequestTest.php +++ b/tests/Unit/Model/Response/SecciRequestTest.php @@ -50,7 +50,7 @@ public function testGetsSecciResult() public function testGetsSecciResultWithDocument() { - $document = 'JVBERi0xLjQK + $document = ''.base64_encode('JVBERi0xLjQK').' application/pdf'; $xml = $this->getResponseXml('OK', 504, $document); diff --git a/tests/Unit/RequestBuilderTest.php b/tests/Unit/RequestBuilderTest.php index a0bca11..8c68cc9 100644 --- a/tests/Unit/RequestBuilderTest.php +++ b/tests/Unit/RequestBuilderTest.php @@ -296,7 +296,6 @@ public function testCallSecciRequest() $content = new ModelBuilder('Content'); $content->setArray([ 'Secci' => [ - 'PaymentMethod' => 'INSTALLMENT', 'DeliveryMethod' => 'EMAIL', 'Email' => 'test@example.com', ], @@ -310,6 +309,6 @@ public function testCallSecciRequest() $requestRaw = $builder->getRequestRaw(); $this->assertStringContainsString('SECCI_REQUEST', $requestRaw); - $this->assertStringContainsString('INSTALLMENT', $requestRaw); + $this->assertStringContainsString('EMAIL', $requestRaw); } } From 4b7d558c7949861eefc8a33920899fd485ec71b9 Mon Sep 17 00:00:00 2001 From: Sebastian Goral Date: Thu, 24 Sep 2026 20:01:48 +0200 Subject: [PATCH 07/14] FC#0137699 - add missing set/getCurrency, rename country to countryCode --- src/Model/Request/SubModel/Content/Payment.php | 2 ++ src/Model/Request/SubModel/Content/Secci.php | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Model/Request/SubModel/Content/Payment.php b/src/Model/Request/SubModel/Content/Payment.php index 2e3aca2..4690f74 100644 --- a/src/Model/Request/SubModel/Content/Payment.php +++ b/src/Model/Request/SubModel/Content/Payment.php @@ -17,6 +17,8 @@ * @method string getMethod() * @method $this setAmount(float $amount) * @method float getAmount() + * @method $this setCurrency(string $currency) + * @method string getCurrency() * @method $this setInstallmentDetails(InstallmentDetails $installmentDetails) * @method InstallmentDetails getInstallmentDetails() * @method $this setDebitPayType(string $debitPayType) diff --git a/src/Model/Request/SubModel/Content/Secci.php b/src/Model/Request/SubModel/Content/Secci.php index c5311a0..a6ecbc3 100644 --- a/src/Model/Request/SubModel/Content/Secci.php +++ b/src/Model/Request/SubModel/Content/Secci.php @@ -139,8 +139,8 @@ public function setLanguage($language) * * @throws \RatePAY\Exception\ModelException */ - public function setCountry($country) + public function setCountryCode($country) { - return $this->__set('Country', $country); + return $this->__set('CountryCode', $country); } } From 2295e0c2613bb8e59b0a5619e3a1e8e2aceb3e19 Mon Sep 17 00:00:00 2001 From: Sebastian Goral Date: Thu, 24 Sep 2026 20:03:03 +0200 Subject: [PATCH 08/14] FC#0137699 - add missing set/getSecci --- src/Model/Request/SubModel/Content.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Model/Request/SubModel/Content.php b/src/Model/Request/SubModel/Content.php index 584bde6..3628001 100644 --- a/src/Model/Request/SubModel/Content.php +++ b/src/Model/Request/SubModel/Content.php @@ -14,6 +14,7 @@ use RatePAY\Model\Request\SubModel\Content\InstallmentCalculation; use RatePAY\Model\Request\SubModel\Content\Invoicing; use RatePAY\Model\Request\SubModel\Content\Payment; +use RatePAY\Model\Request\SubModel\Content\Secci; use RatePAY\Model\Request\SubModel\Content\ShoppingBasket; /** @@ -29,6 +30,8 @@ * @method InstallmentCalculation getInstallmentCalculation() * @method $this setAdditional(Additional $additional) * @method Additional getAdditional() + * @method $this setSecci(Secci $secci) + * @method Secci getSecci() */ class Content extends AbstractModel { From 16b929d1face3ebfd2eed157a0298dfa7b800e90 Mon Sep 17 00:00:00 2001 From: Sebastian Goral Date: Sun, 27 Sep 2026 16:35:37 +0200 Subject: [PATCH 09/14] FC#0137699 - add missing set/getAttestationToken --- src/Model/Request/SubModel/Head.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Model/Request/SubModel/Head.php b/src/Model/Request/SubModel/Head.php index 50fc27e..3d80196 100644 --- a/src/Model/Request/SubModel/Head.php +++ b/src/Model/Request/SubModel/Head.php @@ -23,6 +23,8 @@ * @method string getOperation() * @method $this setSubtype(string $subType) * @method string getSubtype() + * @method $this setAttestationToken(string $attestationToken) + * @method string getAttestationToken() * @method $this setCredential(Credential $credential) * @method Credential getCredential() * @method $this setExternal(External $external) From 77c322d7c6c2defd8a3760c8f87e6cb825a61b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 28 Sep 2026 13:25:38 +0200 Subject: [PATCH 10/14] FC#0135237 - Added mandatoryByRule for Action parameter --- src/Model/Request/SubModel/Content/Secci.php | 10 +++++++++- .../Unit/Model/Request/SubModel/Content/SecciTest.php | 4 +++- tests/Unit/Model/Request/SubModel/ContentTest.php | 4 +++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Model/Request/SubModel/Content/Secci.php b/src/Model/Request/SubModel/Content/Secci.php index a6ecbc3..75b57c1 100644 --- a/src/Model/Request/SubModel/Content/Secci.php +++ b/src/Model/Request/SubModel/Content/Secci.php @@ -41,7 +41,7 @@ class Secci extends AbstractModel 'mandatoryByRule' => true, ], 'Action' => [ - 'mandatory' => false, + 'mandatoryByRule' => true, 'uppercase' => true, ], 'Language' => [ @@ -69,6 +69,14 @@ protected function rule() return false; } + if ('PDF' == $this->admittedFields['DeliveryMethod']['value'] && + (!key_exists('value', $this->admittedFields['Action']) || strtoupper($this->admittedFields['Action']['value']) !== 'PRINT') + ) { + $this->setErrorMsg('action details missing or incorrect'); + + return false; + } + return true; } diff --git a/tests/Unit/Model/Request/SubModel/Content/SecciTest.php b/tests/Unit/Model/Request/SubModel/Content/SecciTest.php index 11e5b6b..4e23aa4 100644 --- a/tests/Unit/Model/Request/SubModel/Content/SecciTest.php +++ b/tests/Unit/Model/Request/SubModel/Content/SecciTest.php @@ -19,12 +19,14 @@ class SecciTest extends TestCase public function testToArrayWithMandatoryFields() { $secci = (new Secci()) - ->setDeliveryMethod('PDF'); + ->setDeliveryMethod('PDF') + ->setAction('PRINT'); $array = $secci->toArray(); $expected = [ 'delivery-method' => ['value' => 'PDF'], + 'action' => ['value' => 'PRINT'] ]; $this->assertEquals($expected, $array); diff --git a/tests/Unit/Model/Request/SubModel/ContentTest.php b/tests/Unit/Model/Request/SubModel/ContentTest.php index 43fcc26..ec268df 100644 --- a/tests/Unit/Model/Request/SubModel/ContentTest.php +++ b/tests/Unit/Model/Request/SubModel/ContentTest.php @@ -27,7 +27,8 @@ public function testEmptyContent() public function testHandleSecci() { $secci = (new Secci()) - ->setDeliveryMethod('PDF'); + ->setDeliveryMethod('PDF') + ->setAction('PRINT'); $content = new Content(); $content->setSecci($secci); @@ -36,6 +37,7 @@ public function testHandleSecci() $expectedSecci = [ 'delivery-method' => ['value' => 'PDF'], + 'action' => ['value' => 'PRINT'] ]; $this->assertEquals($expectedSecci, $array['secci']); From 2efdd319a323a2161ee7a6f966070b7acbcadb25 Mon Sep 17 00:00:00 2001 From: Sebastian Goral Date: Tue, 29 Sep 2026 17:23:29 +0200 Subject: [PATCH 11/14] FC#0137699 - fix typoe of last installment amount --- .../Content/Payment/InstallmentDetails.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Model/Request/SubModel/Content/Payment/InstallmentDetails.php b/src/Model/Request/SubModel/Content/Payment/InstallmentDetails.php index a7c8423..38a80ab 100644 --- a/src/Model/Request/SubModel/Content/Payment/InstallmentDetails.php +++ b/src/Model/Request/SubModel/Content/Payment/InstallmentDetails.php @@ -12,16 +12,16 @@ use RatePAY\Model\Request\SubModel\AbstractModel; /** - * @method $this setInstallmentNumber(string $installmentNumber) - * @method string getInstallmentNumber() - * @method $this setInstallmentAmount(float $installmentAmount) - * @method float getInstallmentAmount() - * @method $this setLastInstallmentAmount(InstallmentDetails $lastInstallmentAmount) - * @method InstallmentDetails getLastInstallmentAmount() - * @method $this setInterestRate(string $interestRate) - * @method string getInterestRate() - * @method $this setPaymentFirstday(string $paymentFirstday) - * @method string getPaymentFirstday() + * @method $this setInstallmentNumber(string $installmentNumber) + * @method string getInstallmentNumber() + * @method $this setInstallmentAmount(float $installmentAmount) + * @method float getInstallmentAmount() + * @method $this setLastInstallmentAmount(float $lastInstallmentAmount) + * @method float getLastInstallmentAmount() + * @method $this setInterestRate(string $interestRate) + * @method string getInterestRate() + * @method $this setPaymentFirstday(string $paymentFirstday) + * @method string getPaymentFirstday() */ class InstallmentDetails extends AbstractModel { From b9fc33b409188734e725067c3a6e752b2d04b793 Mon Sep 17 00:00:00 2001 From: Sebastian Goral Date: Wed, 30 Sep 2026 15:02:04 +0200 Subject: [PATCH 12/14] FC#0137699 - fix SECCI deliveryType PDF not allowing Action DOWNLOAD --- src/Model/Request/SubModel/Content/Secci.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/Request/SubModel/Content/Secci.php b/src/Model/Request/SubModel/Content/Secci.php index 75b57c1..c3a151e 100644 --- a/src/Model/Request/SubModel/Content/Secci.php +++ b/src/Model/Request/SubModel/Content/Secci.php @@ -70,7 +70,7 @@ protected function rule() } if ('PDF' == $this->admittedFields['DeliveryMethod']['value'] && - (!key_exists('value', $this->admittedFields['Action']) || strtoupper($this->admittedFields['Action']['value']) !== 'PRINT') + (!key_exists('value', $this->admittedFields['Action']) || !in_array(strtoupper($this->admittedFields['Action']['value']), ['PRINT', 'DOWNLOAD'])) ) { $this->setErrorMsg('action details missing or incorrect'); From 5d00955497a1a7260d6cde53f4b9d16e27650be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 14 Oct 2026 12:50:49 +0200 Subject: [PATCH 13/14] FC#0135237 - Added missing translation key --- src/locales/en.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/locales/en.php b/src/locales/en.php index 59c5e35..09c7560 100644 --- a/src/locales/en.php +++ b/src/locales/en.php @@ -90,6 +90,7 @@ 'rp_secci_description' => 'EU consumer credit rules have changed and now require additional information for this payment method. This information helps you understand the key credit terms before completing your purchase. If you choose Get by email, our payment partner Ratepay will use your email address only to send this information, using a third-party email delivery provider.', 'rp_secci_get_by_email' => 'Get by email', 'rp_secci_download_pdf' => 'Download PDF', + 'rp_secci_choose_email' => "We've sent the required Standard European Consumer Credit Information to", 'rp_secci_payment_methods' => 'Payment Method', 'rp_secci_choose_payment_method' => 'Selecting Open invoice or installment purchase will automatically send this information to', 'rp_secci_choose_payment_method2' => 'sent.', From 4d5b6a4fd465af839d9d476cdfe5853e5807c7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Thu, 15 Oct 2026 13:02:43 +0200 Subject: [PATCH 14/14] FC#0135237 - Improvements to the library --- .../Request/SubModel/Content/Payment.php | 7 -- src/Model/Request/SubModel/Content/Secci.php | 29 +++---- src/Model/Response/SecciRequest.php | 59 ++++++++++++-- src/locales/en.php | 2 +- tests/Unit/Model/Request/SecciRequestTest.php | 5 +- .../Request/SubModel/Content/PaymentTest.php | 50 +++--------- .../Request/SubModel/Content/SecciTest.php | 23 ++---- .../Model/Request/SubModel/ContentTest.php | 10 +-- .../Unit/Model/Response/SecciRequestTest.php | 80 +++++++++++++++++-- 9 files changed, 166 insertions(+), 99 deletions(-) diff --git a/src/Model/Request/SubModel/Content/Payment.php b/src/Model/Request/SubModel/Content/Payment.php index 4690f74..cd72c7b 100644 --- a/src/Model/Request/SubModel/Content/Payment.php +++ b/src/Model/Request/SubModel/Content/Payment.php @@ -17,8 +17,6 @@ * @method string getMethod() * @method $this setAmount(float $amount) * @method float getAmount() - * @method $this setCurrency(string $currency) - * @method string getCurrency() * @method $this setInstallmentDetails(InstallmentDetails $installmentDetails) * @method InstallmentDetails getInstallmentDetails() * @method $this setDebitPayType(string $debitPayType) @@ -51,11 +49,6 @@ class Payment extends AbstractModel 'isAttribute' => true, 'uppercase' => true, ], - 'Currency' => [ - 'mandatoryByRule' => false, - 'isAttribute' => true, - 'uppercase' => true, - ], 'Amount' => [ 'mandatory' => true, ], diff --git a/src/Model/Request/SubModel/Content/Secci.php b/src/Model/Request/SubModel/Content/Secci.php index c3a151e..9acea02 100644 --- a/src/Model/Request/SubModel/Content/Secci.php +++ b/src/Model/Request/SubModel/Content/Secci.php @@ -11,13 +11,20 @@ use RatePAY\Model\Request\SubModel\AbstractModel; +/** + * @method string getDeliveryMethod() + * @method string getEmail() + * @method string getAction() + * @method string getLanguage() + * @method string getCountryCode() + */ class Secci extends AbstractModel { /** * List of admitted fields. * Each field is public accessible by certain getter and setter. * E.g: - * Set payment method value by using setPaymentMethod(var). Get payment method by using getPaymentMethod(). (Please consider the camel case). + * Set delivery method value by using setDeliveryMethod(var). Get delivery method by using getDeliveryMethod(). (Please consider the camel case). * * Settings: * mandatory = field is mandatory (or optional) @@ -55,7 +62,7 @@ class Secci extends AbstractModel ]; /** - * Installment details rule : if payment method is installment, InstallmentDetails are mandatory. + * Secci rule : if DeliveryMethod is EMAIL, Email parameter must be given. if DeliveryMethod is PDF, Action parameter must be either PRINT or DOWNLOAD. * * @return bool */ @@ -80,18 +87,6 @@ protected function rule() return true; } - /** - * @param string $paymentMethod - * - * @return self - * - * @throws \RatePAY\Exception\ModelException - */ - public function setPaymentMethod($paymentMethod) - { - return $this->__set('PaymentMethod', $paymentMethod); - } - /** * @param string $deliveryMethod * @@ -141,14 +136,14 @@ public function setLanguage($language) } /** - * @param string $country + * @param string $countryCode * * @return self * * @throws \RatePAY\Exception\ModelException */ - public function setCountryCode($country) + public function setCountryCode($countryCode) { - return $this->__set('CountryCode', $country); + return $this->__set('CountryCode', $countryCode); } } diff --git a/src/Model/Response/SecciRequest.php b/src/Model/Response/SecciRequest.php index 26b582e..f0f44eb 100644 --- a/src/Model/Response/SecciRequest.php +++ b/src/Model/Response/SecciRequest.php @@ -17,16 +17,57 @@ class SecciRequest extends AbstractResponse public function validateResponse() { if ($this->getStatusCode() == 'OK' && $this->getResultCode() == 504) { - $this->setResult(['attestationToken' => (string) $this->getResponse()->content->{'secci-result'}->{'attestation-token'}]); - $this->setResult(['documentId' => (string) $this->getResponse()->content->{'secci-result'}->{'document-id'}]); - if (isset($this->getResponse()->content->{'secci-result'}->{'document'})) { - $this->setResult(['document' => (string) $this->getResponse()->content->{'secci-result'}->{'document'}]); - $this->setResult(['contentType' => (string) $this->getResponse()->content->{'secci-result'}->{'content-type'}]); + if (!isset($this->getResponse()->content->{'secci-result'})) { + return; + } + $secciResult = $this->getResponse()->content->{'secci-result'}; + + $attestationToken = $this->getNodeValue($secciResult, 'attestation-token'); + $documentId = $this->getNodeValue($secciResult, 'document-id'); + if ($attestationToken === null || $documentId === null) { + return; + } + + $document = null; + $contentType = null; + if (isset($secciResult->{'document'})) { + $document = $this->getNodeValue($secciResult, 'document'); + $contentType = $this->getNodeValue($secciResult, 'content-type'); + // Document is base64 encoded and must be decodable + if ($document === null || $contentType === null || base64_decode($document, true) === false) { + return; + } + } + + $this->setResult(['attestationToken' => $attestationToken]); + $this->setResult(['documentId' => $documentId]); + if ($document !== null) { + $this->setResult(['document' => $document]); + $this->setResult(['contentType' => $contentType]); } $this->setSuccessful(); } } + /** + * Returns the trimmed value of a child node or null if the node is missing or empty. + * + * @param \SimpleXMLElement $parent + * @param string $name + * + * @return string|null + */ + private function getNodeValue($parent, $name) + { + if (!isset($parent->{$name})) { + return null; + } + + $value = trim((string) $parent->{$name}); + + return ($value !== '') ? $value : null; + } + /** * Returns attestation token. * @@ -55,7 +96,13 @@ public function getDocumentId() public function getDocument() { // Document variable comes as base64 encoded string! - return (key_exists('document', $this->result)) ? base64_decode($this->result['document']) : null; + if (!key_exists('document', $this->result)) { + return null; + } + + $document = base64_decode($this->result['document'], true); + + return ($document !== false) ? $document : null; } /** diff --git a/src/locales/en.php b/src/locales/en.php index 09c7560..ab4c842 100644 --- a/src/locales/en.php +++ b/src/locales/en.php @@ -93,7 +93,7 @@ 'rp_secci_choose_email' => "We've sent the required Standard European Consumer Credit Information to", 'rp_secci_payment_methods' => 'Payment Method', 'rp_secci_choose_payment_method' => 'Selecting Open invoice or installment purchase will automatically send this information to', - 'rp_secci_choose_payment_method2' => 'sent.', + 'rp_secci_choose_payment_method2' => '.', 'rp_secci_change_email' => 'Change email', 'rp_secci_save' => 'Save', 'rp_secci_method_invoice' => 'Ratepay Invoice', diff --git a/tests/Unit/Model/Request/SecciRequestTest.php b/tests/Unit/Model/Request/SecciRequestTest.php index 8f6fd85..f78ac40 100644 --- a/tests/Unit/Model/Request/SecciRequestTest.php +++ b/tests/Unit/Model/Request/SecciRequestTest.php @@ -42,7 +42,7 @@ public function testArrayConversion() $head = new ModelBuilder(); $head->setArray([ 'SystemId' => 'SuperSystem', - 'Operation' => 'SECCI', + 'Operation' => 'SECCI_REQUEST', 'Credential' => [ 'ProfileId' => 'MY_AMAZING_PROFILE', 'Securitycode' => 'super-secure-code', @@ -82,7 +82,7 @@ public function testArrayConversionFailsOnTransactionId() $head = new ModelBuilder(); $head->setArray([ 'SystemId' => 'SuperSystem', - 'Operation' => 'SECCI', + 'Operation' => 'SECCI_REQUEST', 'TransactionId' => 'foo-1234567890', 'Credential' => [ 'ProfileId' => 'MY_AMAZING_PROFILE', @@ -94,6 +94,7 @@ public function testArrayConversionFailsOnTransactionId() $content->setArray([ 'Secci' => [ 'DeliveryMethod' => 'EMAIL', + 'Email' => 'test@example.com', ], ]); diff --git a/tests/Unit/Model/Request/SubModel/Content/PaymentTest.php b/tests/Unit/Model/Request/SubModel/Content/PaymentTest.php index 12fb35a..277022d 100644 --- a/tests/Unit/Model/Request/SubModel/Content/PaymentTest.php +++ b/tests/Unit/Model/Request/SubModel/Content/PaymentTest.php @@ -14,11 +14,10 @@ class PaymentTest extends TestCase { - public function testHandleCurrency() + public function testToArray() { $payment = (new Payment()) ->setMethod('INVOICE') - ->setCurrency('EUR') ->setAmount(100.00); $array = $payment->toArray(); @@ -26,7 +25,6 @@ public function testHandleCurrency() $expected = [ 'attributes' => [ 'method' => ['value' => 'INVOICE'], - 'currency' => ['value' => 'EUR'], ], 'amount' => ['value' => 100.00], ]; @@ -34,49 +32,25 @@ public function testHandleCurrency() $this->assertEquals($expected, $array); } - public function testCurrencyIsUppercased() - { - $payment = (new Payment()) - ->setMethod('INVOICE') - ->setCurrency('eur') - ->setAmount(100.00); - - $array = $payment->toArray(); - - $this->assertEquals('EUR', $array['attributes']['currency']['value']); - } - - public function testCurrencyIsOptional() - { - $payment = (new Payment()) - ->setMethod('INVOICE') - ->setAmount(100.00); - - $array = $payment->toArray(); - - $this->assertNull($payment->getCurrency()); - $this->assertArrayNotHasKey('currency', $array['attributes']); - } - - public function testGetCurrency() - { - $payment = new Payment(); - $payment->setCurrency('EUR'); - - $this->assertEquals('EUR', $payment->getCurrency()); - } - - public function testHandleCurrencyByModelBuilder() + public function testHandleByModelBuilder() { $builder = new ModelBuilder('Payment'); $builder->setArray([ 'Method' => 'INVOICE', - 'Currency' => 'EUR', 'Amount' => 100.00, ]); $array = $builder->getModel()->toArray(); - $this->assertEquals('EUR', $array['attributes']['currency']['value']); + $this->assertEquals('INVOICE', $array['attributes']['method']['value']); + $this->assertEquals(100.00, $array['amount']['value']); + } + + public function testCurrencyIsNotAdmitted() + { + // Currency is delivered by ShoppingBasket, not by Payment + $payment = new Payment(); + + $this->assertArrayNotHasKey('Currency', $payment->admittedFields); } } diff --git a/tests/Unit/Model/Request/SubModel/Content/SecciTest.php b/tests/Unit/Model/Request/SubModel/Content/SecciTest.php index 4e23aa4..b19d37b 100644 --- a/tests/Unit/Model/Request/SubModel/Content/SecciTest.php +++ b/tests/Unit/Model/Request/SubModel/Content/SecciTest.php @@ -10,7 +10,6 @@ use PHPUnit\Framework\TestCase; use RatePAY\Exception\ModelException; -use RatePAY\Exception\RuleSetException; use RatePAY\Model\Request\SubModel\Content\Secci; use RatePAY\ModelBuilder; @@ -19,14 +18,14 @@ class SecciTest extends TestCase public function testToArrayWithMandatoryFields() { $secci = (new Secci()) - ->setDeliveryMethod('PDF') - ->setAction('PRINT'); + ->setDeliveryMethod('EMAIL') + ->setEmail('test@example.com'); $array = $secci->toArray(); $expected = [ - 'delivery-method' => ['value' => 'PDF'], - 'action' => ['value' => 'PRINT'] + 'delivery-method' => ['value' => 'EMAIL'], + 'email' => ['value' => 'test@example.com'], ]; $this->assertEquals($expected, $array); @@ -58,7 +57,7 @@ public function testSetterReturnsModel() { $secci = new Secci(); - $this->assertSame($secci, $secci->setDeliveryMethod('PDF')); + $this->assertSame($secci, $secci->setDeliveryMethod('EMAIL')); } public function testGetters() @@ -84,21 +83,9 @@ public function testGetterReturnsNullIfNotSet() $this->assertNull($secci->getEmail()); } - public function testThrowErrorIfNoEmailAddress() - { - $secci = new Secci(); - $secci->setDeliveryMethod('EMAIL'); - - $this->expectException(RuleSetException::class); - $this->expectExceptionMessage('Rule set exception : email details missing'); - - $secci->toArray(); - } - public function testThrowErrorIfNoDeliveryMethod() { $secci = new Secci(); - $secci->setCountryCode('DE'); $this->expectException(ModelException::class); $this->expectExceptionMessage('Model exception : Field \'DeliveryMethod\' is required'); diff --git a/tests/Unit/Model/Request/SubModel/ContentTest.php b/tests/Unit/Model/Request/SubModel/ContentTest.php index ec268df..d436995 100644 --- a/tests/Unit/Model/Request/SubModel/ContentTest.php +++ b/tests/Unit/Model/Request/SubModel/ContentTest.php @@ -27,8 +27,8 @@ public function testEmptyContent() public function testHandleSecci() { $secci = (new Secci()) - ->setDeliveryMethod('PDF') - ->setAction('PRINT'); + ->setDeliveryMethod('EMAIL') + ->setEmail('test@example.com'); $content = new Content(); $content->setSecci($secci); @@ -36,8 +36,8 @@ public function testHandleSecci() $array = $content->toArray(); $expectedSecci = [ - 'delivery-method' => ['value' => 'PDF'], - 'action' => ['value' => 'PRINT'] + 'delivery-method' => ['value' => 'EMAIL'], + 'email' => ['value' => 'test@example.com'], ]; $this->assertEquals($expectedSecci, $array['secci']); @@ -46,7 +46,7 @@ public function testHandleSecci() public function testGetSecci() { $secci = (new Secci()) - ->setDeliveryMethod('PDF'); + ->setDeliveryMethod('EMAIL'); $content = new Content(); $content->setSecci($secci); diff --git a/tests/Unit/Model/Response/SecciRequestTest.php b/tests/Unit/Model/Response/SecciRequestTest.php index 6bc2d9f..ff5fe99 100644 --- a/tests/Unit/Model/Response/SecciRequestTest.php +++ b/tests/Unit/Model/Response/SecciRequestTest.php @@ -50,7 +50,7 @@ public function testGetsSecciResult() public function testGetsSecciResultWithDocument() { - $document = ''.base64_encode('JVBERi0xLjQK').' + $document = 'JVBERi0xLjQK application/pdf'; $xml = $this->getResponseXml('OK', 504, $document); @@ -58,19 +58,89 @@ public function testGetsSecciResultWithDocument() $response->validateResponse(); $this->assertTrue($response->isSuccessful()); - $this->assertEquals('JVBERi0xLjQK', $response->getDocument()); + // Document is delivered base64 encoded and returned decoded + $this->assertSame("%PDF-1.4\n", $response->getDocument()); $this->assertEquals('application/pdf', $response->getContentType()); } - public function testGetsEmptyAttestationToken() + /** @dataProvider provideEmptySecciResultFields */ + public function testIsNotSuccessfulOnEmptySecciResultField($field) { $xml = $this->getResponseXml('OK', 504); - $xml->content->{'secci-result'}->{'attestation-token'} = ''; + $xml->content->{'secci-result'}->{$field} = ' '; $response = new SecciRequest($xml); $response->validateResponse(); - $this->assertSame('', $response->getAttestationToken()); + $this->assertFalse($response->isSuccessful()); + $this->assertNull($response->getAttestationToken()); + $this->assertNull($response->getDocumentId()); + } + + public function provideEmptySecciResultFields() + { + return [ + ['attestation-token'], + ['document-id'], + ]; + } + + /** @dataProvider provideMissingSecciResultFields */ + public function testIsNotSuccessfulOnMissingSecciResultField($field) + { + $xml = $this->getResponseXml('OK', 504); + unset($xml->content->{'secci-result'}->{$field}); + + $response = new SecciRequest($xml); + $response->validateResponse(); + + $this->assertFalse($response->isSuccessful()); + $this->assertNull($response->getAttestationToken()); + $this->assertNull($response->getDocumentId()); + } + + public function provideMissingSecciResultFields() + { + return [ + ['attestation-token'], + ['document-id'], + ]; + } + + public function testIsNotSuccessfulOnMissingSecciResult() + { + $xml = $this->getResponseXml('OK', 504); + unset($xml->content->{'secci-result'}); + + $response = new SecciRequest($xml); + $response->validateResponse(); + + $this->assertFalse($response->isSuccessful()); + $this->assertNull($response->getAttestationToken()); + $this->assertNull($response->getDocumentId()); + } + + /** @dataProvider provideInvalidDocuments */ + public function testIsNotSuccessfulOnInvalidDocument($document) + { + $xml = $this->getResponseXml('OK', 504, $document); + + $response = new SecciRequest($xml); + $response->validateResponse(); + + $this->assertFalse($response->isSuccessful()); + $this->assertNull($response->getDocument()); + $this->assertNull($response->getContentType()); + } + + public function provideInvalidDocuments() + { + return [ + 'empty document' => ['application/pdf'], + 'invalid base64' => ['!!!no-base64!!!application/pdf'], + 'missing content type' => ['JVBERi0xLjQK'], + 'empty content type' => ['JVBERi0xLjQK'], + ]; } public function testGettersReturnNullIfResponseIsNotSuccessful()