From 0fbb1f3c833bfdd8a44fbe4af7d9a4d8e45e9b26 Mon Sep 17 00:00:00 2001 From: Remco Tolsma <869674+remcotolsma@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:38:24 +0100 Subject: [PATCH 1/8] Update merchant.order.status.changed.http --- tests/http/merchant.order.status.changed.http | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/http/merchant.order.status.changed.http b/tests/http/merchant.order.status.changed.http index 4590bc3..8dea518 100644 --- a/tests/http/merchant.order.status.changed.http +++ b/tests/http/merchant.order.status.changed.http @@ -2,15 +2,15 @@ HTTP/1.1 200 OK Content-Type: application/json { - "moreOrderResultsAvailable": false, + "moreOrderResultsAvailable": true, "orderResults": [ { "merchantOrderId": "order123", "omnikassaOrderId": "1d0a95f4-2589-439b-9562-c50aa19f9caf", "poiId": "2004", "orderStatus": "COMPLETED", - "orderStatusDateTime": "2018-11-25T12:20:03.157+00:00", - "errorCode": "fakekmirima", + "orderStatusDateTime": "2018-11-25T13:20:03.157+01:00", + "errorCode": "epcuzkadfobuuzoo", "paidAmount": { "amount": 10997, "currency": "EUR" @@ -21,10 +21,10 @@ Content-Type: application/json }, "transactions": [ { - "transactionId": "22b36073-57a3-4c3d-9585-87f2e55275a5", + "id": "22b36073-57a3-4c3d-9585-87f2e55275a5", "paymentBrand": "IDEAL", - "transactionType": "AUTHORIZE", - "transactionStatus": "SUCCESS", + "type": "AUTHORIZE", + "status": "SUCCESS", "amount": { "amount": 10997, "currency": "EUR" @@ -33,7 +33,7 @@ Content-Type: application/json "amount": 10997, "currency": "EUR" }, - "startDateTime": "2018-03-20T09:12:28Z", + "startTime": "2018-03-20T09:12:28Z", "lastUpdateTime": "2018-03-20T09:12:28Z" } ] @@ -43,8 +43,8 @@ Content-Type: application/json "omnikassaOrderId": "1d0a95f4-2589-439b-9562-c50aa19f9caf", "poiId": "2004", "orderStatus": "COMPLETED", - "orderStatusDateTime": "2018-11-25T12:20:03.157+00:00", - "errorCode": "gupohaa", + "orderStatusDateTime": "2018-11-25T13:20:03.157+01:00", + "errorCode": "vihreotufop", "paidAmount": { "amount": 10997, "currency": "EUR" @@ -55,10 +55,10 @@ Content-Type: application/json }, "transactions": [ { - "transactionId": "22b36073-57a3-4c3d-9585-87f2e55275a5", + "id": "22b36073-57a3-4c3d-9585-87f2e55275a5", "paymentBrand": "IDEAL", - "transactionType": "AUTHORIZE", - "transactionStatus": "SUCCESS", + "type": "AUTHORIZE", + "status": "SUCCESS", "amount": { "amount": 10997, "currency": "EUR" @@ -67,7 +67,7 @@ Content-Type: application/json "amount": 10997, "currency": "EUR" }, - "startDateTime": "2018-03-20T09:12:28Z", + "startTime": "2018-03-20T09:12:28Z", "lastUpdateTime": "2018-03-20T09:12:28Z" } ] @@ -77,8 +77,8 @@ Content-Type: application/json "omnikassaOrderId": "1d0a95f4-2589-439b-9562-c50aa19f9caf", "poiId": "2004", "orderStatus": "COMPLETED", - "orderStatusDateTime": "2018-11-25T12:20:03.157+00:00", - "errorCode": "voldeholu", + "orderStatusDateTime": "2018-11-25T13:20:03.157+01:00", + "errorCode": "faufa", "paidAmount": { "amount": 10997, "currency": "EUR" @@ -89,10 +89,10 @@ Content-Type: application/json }, "transactions": [ { - "transactionId": "22b36073-57a3-4c3d-9585-87f2e55275a5", + "id": "22b36073-57a3-4c3d-9585-87f2e55275a5", "paymentBrand": "IDEAL", - "transactionType": "AUTHORIZE", - "transactionStatus": "SUCCESS", + "type": "AUTHORIZE", + "status": "SUCCESS", "amount": { "amount": 10997, "currency": "EUR" @@ -101,11 +101,11 @@ Content-Type: application/json "amount": 10997, "currency": "EUR" }, - "startDateTime": "2018-03-20T09:12:28Z", + "startTime": "2018-03-20T09:12:28Z", "lastUpdateTime": "2018-03-20T09:12:28Z" } ] } ], - "signature": "d93b58c02302450800bcbce07ecf836277789023481e04f74f96c2627f8e2e1745917be1531cea0910d390f5f82d4fd526bb9f260836898a70b6b769be8fef80" + "signature": "99ca2487243fbad72bbaa456a3219db7b0d2a19777f436cedb3c045e999b86c05001bb0837b43caa3d1757321d00959ac2a161f473a103af72bf440db5147b4a" } From 44caa427cce402a7ca96581abf405bdeeaeddd06 Mon Sep 17 00:00:00 2001 From: Remco Tolsma <869674+remcotolsma@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:49:00 +0100 Subject: [PATCH 2/8] Update merchant.order.status.changed-cancelled.http --- ...rchant.order.status.changed-cancelled.http | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/http/merchant.order.status.changed-cancelled.http b/tests/http/merchant.order.status.changed-cancelled.http index b28b3d6..59a9327 100644 --- a/tests/http/merchant.order.status.changed-cancelled.http +++ b/tests/http/merchant.order.status.changed-cancelled.http @@ -9,8 +9,8 @@ Content-Type: application/json "omnikassaOrderId": "1d0a95f4-2589-439b-9562-c50aa19f9caf", "poiId": "2004", "orderStatus": "CANCELLED", - "orderStatusDateTime": "2018-11-25T12:20:03.157+00:00", - "errorCode": "fakekmirima", + "orderStatusDateTime": "2018-11-25T13:20:03.157+01:00", + "errorCode": "epcuzkadfobuuzoo", "paidAmount": { "amount": 10997, "currency": "EUR" @@ -21,10 +21,10 @@ Content-Type: application/json }, "transactions": [ { - "transactionId": "22b36073-57a3-4c3d-9585-87f2e55275a5", + "id": "22b36073-57a3-4c3d-9585-87f2e55275a5", "paymentBrand": "IDEAL", - "transactionType": "AUTHORIZE", - "transactionStatus": "CANCELLED", + "type": "AUTHORIZE", + "status": "CANCELLED", "amount": { "amount": 10997, "currency": "EUR" @@ -33,7 +33,7 @@ Content-Type: application/json "amount": 10997, "currency": "EUR" }, - "startDateTime": "2018-03-20T09:12:28Z", + "startTime": "2018-03-20T09:12:28Z", "lastUpdateTime": "2018-03-20T09:12:28Z" } ] @@ -43,8 +43,8 @@ Content-Type: application/json "omnikassaOrderId": "1d0a95f4-2589-439b-9562-c50aa19f9caf", "poiId": "2004", "orderStatus": "CANCELLED", - "orderStatusDateTime": "2018-11-25T12:20:03.157+00:00", - "errorCode": "gupohaa", + "orderStatusDateTime": "2018-11-25T13:20:03.157+01:00", + "errorCode": "vihreotufop", "paidAmount": { "amount": 10997, "currency": "EUR" @@ -55,10 +55,10 @@ Content-Type: application/json }, "transactions": [ { - "transactionId": "22b36073-57a3-4c3d-9585-87f2e55275a5", + "id": "22b36073-57a3-4c3d-9585-87f2e55275a5", "paymentBrand": "IDEAL", - "transactionType": "AUTHORIZE", - "transactionStatus": "CANCELLED", + "type": "AUTHORIZE", + "status": "SUCCESS", "amount": { "amount": 10997, "currency": "EUR" @@ -67,7 +67,7 @@ Content-Type: application/json "amount": 10997, "currency": "EUR" }, - "startDateTime": "2018-03-20T09:12:28Z", + "startTime": "2018-03-20T09:12:28Z", "lastUpdateTime": "2018-03-20T09:12:28Z" } ] @@ -77,8 +77,8 @@ Content-Type: application/json "omnikassaOrderId": "1d0a95f4-2589-439b-9562-c50aa19f9caf", "poiId": "2004", "orderStatus": "CANCELLED", - "orderStatusDateTime": "2018-11-25T12:20:03.157+00:00", - "errorCode": "voldeholu", + "orderStatusDateTime": "2018-11-25T13:20:03.157+01:00", + "errorCode": "faufa", "paidAmount": { "amount": 10997, "currency": "EUR" @@ -89,10 +89,10 @@ Content-Type: application/json }, "transactions": [ { - "transactionId": "22b36073-57a3-4c3d-9585-87f2e55275a5", + "id": "22b36073-57a3-4c3d-9585-87f2e55275a5", "paymentBrand": "IDEAL", - "transactionType": "AUTHORIZE", - "transactionStatus": "CANCELLED", + "type": "AUTHORIZE", + "status": "CANCELLED", "amount": { "amount": 10997, "currency": "EUR" @@ -101,11 +101,11 @@ Content-Type: application/json "amount": 10997, "currency": "EUR" }, - "startDateTime": "2018-03-20T09:12:28Z", + "startTime": "2018-03-20T09:12:28Z", "lastUpdateTime": "2018-03-20T09:12:28Z" } ] } ], - "signature": "338429f1d2ca959a3203921c94c246b8fd4d0ae75e3989eb6c2ce49601e838644b1c31f26a77179cfd6a62e6c24c2b5f99825f59bb1a6f828d72ca4948fd32b1" + "signature": "99ca2487243fbad72bbaa456a3219db7b0d2a19777f436cedb3c045e999b86c05001bb0837b43caa3d1757321d00959ac2a161f473a103af72bf440db5147b4a" } From 56e188ecba7f00efbb771ce21b4c51441a7cc742 Mon Sep 17 00:00:00 2001 From: Remco Tolsma <869674+remcotolsma@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:49:19 +0100 Subject: [PATCH 3/8] Update Transaction.php --- src/Transaction.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Transaction.php b/src/Transaction.php index 256aa73..28faf1d 100644 --- a/src/Transaction.php +++ b/src/Transaction.php @@ -103,10 +103,10 @@ public static function from_object( $data ) { $object_access = new ObjectAccess( $data ); return new self( - $object_access->get_string( 'transactionId' ), + $object_access->get_string( 'id' ), $object_access->get_string( 'paymentBrand' ), - $object_access->get_string( 'transactionType' ), - $object_access->get_string( 'transactionStatus' ) + $object_access->get_string( 'type' ), + $object_access->get_string( 'status' ) ); } } From f6dd3c15cf0795a1dd81d123f5d6add903f83a13 Mon Sep 17 00:00:00 2001 From: Remco Tolsma <869674+remcotolsma@users.noreply.github.com> Date: Wed, 8 Nov 2023 11:41:33 +0100 Subject: [PATCH 4/8] Add a `verify_signature( $siging_key )` method for nicer exception message. Fixes https://github.com/pronamic/wp-pronamic-pay-omnikassa-2/issues/25. --- src/Gateway.php | 9 +-------- src/Message.php | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/Gateway.php b/src/Gateway.php index dc6f1e0..d22d638 100644 --- a/src/Gateway.php +++ b/src/Gateway.php @@ -567,14 +567,7 @@ private function handle_merchant_order_status_changed( Notification $notificatio do { $order_results = $this->client->get_order_results( $notification->get_authentication() ); - if ( ! $order_results->is_valid( $this->config->signing_key ) ) { - throw new \Pronamic\WordPress\Pay\Gateways\OmniKassa2\InvalidSignatureException( - \sprintf( - 'Signature on order results message does not match gateway configuration signature (%s).', - \esc_html( \substr( $this->config->signing_key, 0, 7 ) ) - ) - ); - } + $order_results->verify_signature( $this->config->signing_key ); foreach ( $order_results as $order_result ) { $omnikassa_order_id = $order_result->get_omnikassa_order_id(); diff --git a/src/Message.php b/src/Message.php index 604885c..3c7fb24 100644 --- a/src/Message.php +++ b/src/Message.php @@ -63,18 +63,43 @@ public function sign( $signing_key ) { * @return bool True if valid, false otherwise. */ public function is_valid( $signing_key ) { - $signature_a = Security::get_signature( $this, $signing_key ); + try { + $this->verify_signature( $signing_key ); - if ( empty( $signature_a ) ) { + return true; + } catch ( \Exception $e ) { return false; } + } + + /** + * Verify signature. + * + * @throws \Exception Throws an exception when the signature cannot be verified. + * @return void + */ + public function verify_signature( $signing_key ) { + $signature_enclosed = $this->get_signature(); - $signature_b = $this->get_signature(); + $signature_calculated = Security::get_signature( $this, $signing_key ); - if ( empty( $signature_b ) ) { - return false; - } + $result = Security::validate_signature( $signature_enclosed, $signature_calculated ); - return Security::validate_signature( $signature_a, $signature_b ); + if ( false === $result ) { + throw new \Pronamic\WordPress\Pay\Gateways\OmniKassa2\InvalidSignatureException( + \sprintf( + 'Signature `%s` in message does not match signature `%s` calculated with signing key: `%s`.', + \esc_html( $signature_enclosed ), + \esc_html( $signature_calculated ), + \esc_html( + \str_pad( + \substr( $signing_key, 0, 7 ), + \strlen( $signing_key ), + '*' + ) + ) + ) + ); + } } } From 2cd30221f19fdbc1e2a9870825bffb4e1bc71c76 Mon Sep 17 00:00:00 2001 From: Remco Tolsma <869674+remcotolsma@users.noreply.github.com> Date: Wed, 8 Nov 2023 11:41:47 +0100 Subject: [PATCH 5/8] Update merchant.order.status.changed-v2.json --- .../merchant.order.status.changed-v2.json | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/json/merchant.order.status.changed-v2.json b/tests/json/merchant.order.status.changed-v2.json index b549a60..accf737 100644 --- a/tests/json/merchant.order.status.changed-v2.json +++ b/tests/json/merchant.order.status.changed-v2.json @@ -6,8 +6,8 @@ "omnikassaOrderId": "1d0a95f4-2589-439b-9562-c50aa19f9caf", "poiId": "2004", "orderStatus": "COMPLETED", - "orderStatusDateTime": "2018-11-25T12:20:03.157+00:00", - "errorCode": "fakekmirima", + "orderStatusDateTime": "2018-11-25T13:20:03.157+01:00", + "errorCode": "epcuzkadfobuuzoo", "paidAmount": { "amount": 10997, "currency": "EUR" @@ -18,10 +18,10 @@ }, "transactions": [ { - "transactionId": "22b36073-57a3-4c3d-9585-87f2e55275a5", + "id": "22b36073-57a3-4c3d-9585-87f2e55275a5", "paymentBrand": "IDEAL", - "transactionType": "AUTHORIZE", - "transactionStatus": "SUCCESS", + "type": "AUTHORIZE", + "status": "SUCCESS", "amount": { "amount": 10997, "currency": "EUR" @@ -30,7 +30,7 @@ "amount": 10997, "currency": "EUR" }, - "startDateTime": "2018-03-20T09:12:28Z", + "startTime": "2018-03-20T09:12:28Z", "lastUpdateTime": "2018-03-20T09:12:28Z" } ] @@ -40,8 +40,8 @@ "omnikassaOrderId": "1d0a95f4-2589-439b-9562-c50aa19f9caf", "poiId": "2004", "orderStatus": "COMPLETED", - "orderStatusDateTime": "2018-11-25T12:20:03.157+00:00", - "errorCode": "gupohaa", + "orderStatusDateTime": "2018-11-25T13:20:03.157+01:00", + "errorCode": "vihreotufop", "paidAmount": { "amount": 10997, "currency": "EUR" @@ -52,10 +52,10 @@ }, "transactions": [ { - "transactionId": "22b36073-57a3-4c3d-9585-87f2e55275a5", + "id": "22b36073-57a3-4c3d-9585-87f2e55275a5", "paymentBrand": "IDEAL", - "transactionType": "AUTHORIZE", - "transactionStatus": "SUCCESS", + "type": "AUTHORIZE", + "status": "SUCCESS", "amount": { "amount": 10997, "currency": "EUR" @@ -64,7 +64,7 @@ "amount": 10997, "currency": "EUR" }, - "startDateTime": "2018-03-20T09:12:28Z", + "startTime": "2018-03-20T09:12:28Z", "lastUpdateTime": "2018-03-20T09:12:28Z" } ] @@ -74,8 +74,8 @@ "omnikassaOrderId": "1d0a95f4-2589-439b-9562-c50aa19f9caf", "poiId": "2004", "orderStatus": "COMPLETED", - "orderStatusDateTime": "2018-11-25T12:20:03.157+00:00", - "errorCode": "voldeholu", + "orderStatusDateTime": "2018-11-25T13:20:03.157+01:00", + "errorCode": "faufa", "paidAmount": { "amount": 10997, "currency": "EUR" @@ -86,10 +86,10 @@ }, "transactions": [ { - "transactionId": "22b36073-57a3-4c3d-9585-87f2e55275a5", + "id": "22b36073-57a3-4c3d-9585-87f2e55275a5", "paymentBrand": "IDEAL", - "transactionType": "AUTHORIZE", - "transactionStatus": "SUCCESS", + "type": "AUTHORIZE", + "status": "SUCCESS", "amount": { "amount": 10997, "currency": "EUR" @@ -98,7 +98,7 @@ "amount": 10997, "currency": "EUR" }, - "startDateTime": "2018-03-20T09:12:28Z", + "startTime": "2018-03-20T09:12:28Z", "lastUpdateTime": "2018-03-20T09:12:28Z" } ] From b23acd2f0144a83576de2ee21dd74575d0fd8de5 Mon Sep 17 00:00:00 2001 From: Remco Tolsma <869674+remcotolsma@users.noreply.github.com> Date: Wed, 8 Nov 2023 11:41:55 +0100 Subject: [PATCH 6/8] Fix signature for testing. --- tests/http/merchant.order.status.changed-cancelled.http | 2 +- tests/http/merchant.order.status.changed.http | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/http/merchant.order.status.changed-cancelled.http b/tests/http/merchant.order.status.changed-cancelled.http index 59a9327..c6f9240 100644 --- a/tests/http/merchant.order.status.changed-cancelled.http +++ b/tests/http/merchant.order.status.changed-cancelled.http @@ -107,5 +107,5 @@ Content-Type: application/json ] } ], - "signature": "99ca2487243fbad72bbaa456a3219db7b0d2a19777f436cedb3c045e999b86c05001bb0837b43caa3d1757321d00959ac2a161f473a103af72bf440db5147b4a" + "signature": "dc00219d04c8e9910c0b08df7b1db2119ef77181a9929ed4d3995d655aa5a295b66412f131ea173affa1ae71fab7cd7314f4c7f234d56e381d851091b630dc4b" } diff --git a/tests/http/merchant.order.status.changed.http b/tests/http/merchant.order.status.changed.http index 8dea518..8bac8d3 100644 --- a/tests/http/merchant.order.status.changed.http +++ b/tests/http/merchant.order.status.changed.http @@ -2,7 +2,7 @@ HTTP/1.1 200 OK Content-Type: application/json { - "moreOrderResultsAvailable": true, + "moreOrderResultsAvailable": false, "orderResults": [ { "merchantOrderId": "order123", @@ -107,5 +107,5 @@ Content-Type: application/json ] } ], - "signature": "99ca2487243fbad72bbaa456a3219db7b0d2a19777f436cedb3c045e999b86c05001bb0837b43caa3d1757321d00959ac2a161f473a103af72bf440db5147b4a" + "signature": "93c0f76f65a98ff61dc65fdbae17b62a82b04491d796b4476dee070ed99c68d686052fa0606f03d6570996303d02f4d40e4e2905944c302eb5d7e28d9bec87ad" } From b5a30685c37925f08018c2259d32eaee838d99fd Mon Sep 17 00:00:00 2001 From: Remco Tolsma <869674+remcotolsma@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:08:29 +0100 Subject: [PATCH 7/8] Fix webhook handling. --- src/Gateway.php | 1 - src/Message.php | 7 +- src/OrderResult.php | 24 ++++ src/OrderResults.php | 10 +- src/Transaction.php | 113 ++++++++++++++++-- ...rchant.order.status.changed-cancelled.http | 2 +- tests/http/merchant.order.status.changed.http | 2 +- ...atus.changed-v2-confirmed-amount-null.json | 37 ++++++ tests/src/OrderResultsTest.php | 41 ++++++- 9 files changed, 211 insertions(+), 26 deletions(-) create mode 100644 tests/json/merchant.order.status.changed-v2-confirmed-amount-null.json diff --git a/src/Gateway.php b/src/Gateway.php index d22d638..abaed36 100644 --- a/src/Gateway.php +++ b/src/Gateway.php @@ -558,7 +558,6 @@ private function get_payment_by_omnikassa_order_id( $omnikassa_order_id ) { * * @param Notification $notification Notification. * @return void - * @throws \Pronamic\WordPress\Pay\Gateways\OmniKassa2\InvalidSignatureException Throws invalid signature exception when order results message does not match gateway configuration signature. * @throws \Pronamic\WordPress\Pay\Gateways\OmniKassa2\UnknownOrderIdsException Throws unknown order IDs exception when no payment could be found for on ore more OmniKassa order IDs. */ private function handle_merchant_order_status_changed( Notification $notification ) { diff --git a/src/Message.php b/src/Message.php index 3c7fb24..92e04fe 100644 --- a/src/Message.php +++ b/src/Message.php @@ -75,11 +75,12 @@ public function is_valid( $signing_key ) { /** * Verify signature. * - * @throws \Exception Throws an exception when the signature cannot be verified. + * @param string $signing_key Signing key. * @return void + * @throws \Pronamic\WordPress\Pay\Gateways\OmniKassa2\InvalidSignatureException Throws an exception when the signature cannot be verified. */ public function verify_signature( $signing_key ) { - $signature_enclosed = $this->get_signature(); + $signature_enclosed = (string) $this->get_signature(); $signature_calculated = Security::get_signature( $this, $signing_key ); @@ -90,7 +91,7 @@ public function verify_signature( $signing_key ) { \sprintf( 'Signature `%s` in message does not match signature `%s` calculated with signing key: `%s`.', \esc_html( $signature_enclosed ), - \esc_html( $signature_calculated ), + \esc_html( $signature_calculated ), \esc_html( \str_pad( \substr( $signing_key, 0, 7 ), diff --git a/src/OrderResult.php b/src/OrderResult.php index 4114952..3fc6905 100644 --- a/src/OrderResult.php +++ b/src/OrderResult.php @@ -195,6 +195,30 @@ public function get_transactions() { return $this->transactions; } + /** + * Get signature fields. + * + * @param array $fields Fields. + * @return array + */ + public function get_signature_fields( $fields = [] ) { + $fields[] = $this->get_merchant_order_id(); + $fields[] = $this->get_omnikassa_order_id(); + $fields[] = \strval( $this->get_poi_id() ); + $fields[] = $this->get_order_status(); + $fields[] = $this->get_order_status_datetime(); + $fields[] = $this->get_error_code(); + + $fields = $this->get_paid_amount()->get_signature_fields( $fields ); + $fields = $this->get_total_amount()->get_signature_fields( $fields ); + + foreach ( $this->get_transactions() as $item ) { + $fields = $item->get_signature_fields( $fields ); + } + + return $fields; + } + /** * Get JSON. * diff --git a/src/OrderResults.php b/src/OrderResults.php index 8004cfe..c4eea36 100644 --- a/src/OrderResults.php +++ b/src/OrderResults.php @@ -67,15 +67,7 @@ public function get_signature_fields() { $fields[] = $this->more_available() ? 'true' : 'false'; foreach ( $this->order_results as $order_result ) { - $fields[] = $order_result->get_merchant_order_id(); - $fields[] = $order_result->get_omnikassa_order_id(); - $fields[] = \strval( $order_result->get_poi_id() ); - $fields[] = $order_result->get_order_status(); - $fields[] = $order_result->get_order_status_datetime(); - $fields[] = $order_result->get_error_code(); - - $fields = $order_result->get_paid_amount()->get_signature_fields( $fields ); - $fields = $order_result->get_total_amount()->get_signature_fields( $fields ); + $fields = $order_result->get_signature_fields( $fields ); } return $fields; diff --git a/src/Transaction.php b/src/Transaction.php index 28faf1d..8704682 100644 --- a/src/Transaction.php +++ b/src/Transaction.php @@ -29,7 +29,7 @@ final class Transaction { private $payment_brand; /** - * Type. + * Type of the transaction. * * @var string */ @@ -42,6 +42,44 @@ final class Transaction { */ private $status; + /** + * Amount. + * + * The total order amount in cents, including VAT. The amount must be equal + * to the sum over all order items of the piece price (including VAT) + * multiplied by the quantity. Note: if the amount is not equal to the sum + * of the amounts of the order items then 1. the order items from the order + * announcement are filtered, and 2. Riverty/AfterPay is not possible as a + * payment method + * + * @var Money + */ + private $amount; + + /** + * Amount. + * + * The amount that was confirmed by the external payment processor. This + * field is only filled when the transaction status is SUCCESS or ACCEPTED. + * + * @var Money|null + */ + private $confirmed_amount; + + /** + * Start time. + * + * @var string + */ + private $start_time; + + /** + * Last update time. + * + * @var string + */ + private $last_update_time; + /** * Construct transaction. * @@ -49,12 +87,18 @@ final class Transaction { * @param string $payment_brand Payment brand. * @param string $type Transaction type. * @param string $status Transaction status. + * @param Money $amount Amount. + * @param string $start_time Start time. + * @param string $last_update_time Last update time. */ - public function __construct( $id, $payment_brand, $type, $status ) { - $this->id = $id; - $this->payment_brand = $payment_brand; - $this->type = $type; - $this->status = $status; + public function __construct( $id, $payment_brand, $type, $status, Money $amount, $start_time, $last_update_time ) { + $this->id = $id; + $this->payment_brand = $payment_brand; + $this->type = $type; + $this->status = $status; + $this->amount = $amount; + $this->start_time = $start_time; + $this->last_update_time = $last_update_time; } /** @@ -93,6 +137,48 @@ public function get_status() { return $this->status; } + /** + * Get amount. + * + * @return Money + */ + public function get_amount() { + return $this->amount; + } + + /** + * Get confirmed amount. + * + * @return Money|null + */ + public function get_confirmed_amount() { + return $this->confirmed_amount; + } + + /** + * Get signature fields. + * + * @param array $fields Fields. + * @return array + */ + public function get_signature_fields( $fields = [] ) { + $fields[] = $this->get_id(); + $fields[] = $this->get_payment_brand(); + $fields[] = $this->get_type(); + $fields[] = $this->get_status(); + + $fields = $this->amount->get_signature_fields( $fields ); + + if ( null !== $this->confirmed_amount ) { + $fields = $this->confirmed_amount->get_signature_fields( $fields ); + } + + $fields[] = $this->start_time; + $fields[] = $this->last_update_time; + + return $fields; + } + /** * Create transaction from object. * @@ -102,11 +188,22 @@ public function get_status() { public static function from_object( $data ) { $object_access = new ObjectAccess( $data ); - return new self( + $transaction = new self( $object_access->get_string( 'id' ), $object_access->get_string( 'paymentBrand' ), $object_access->get_string( 'type' ), - $object_access->get_string( 'status' ) + $object_access->get_string( 'status' ), + Money::from_object( $object_access->get_object( 'amount' ) ), + $object_access->get_string( 'startTime' ), + $object_access->get_string( 'lastUpdateTime' ) ); + + $object = $object_access->get_property( 'confirmedAmount' ); + + if ( \is_object( $object ) ) { + $transaction->confirmed_amount = Money::from_object( $object ); + } + + return $transaction; } } diff --git a/tests/http/merchant.order.status.changed-cancelled.http b/tests/http/merchant.order.status.changed-cancelled.http index c6f9240..0f37ec9 100644 --- a/tests/http/merchant.order.status.changed-cancelled.http +++ b/tests/http/merchant.order.status.changed-cancelled.http @@ -107,5 +107,5 @@ Content-Type: application/json ] } ], - "signature": "dc00219d04c8e9910c0b08df7b1db2119ef77181a9929ed4d3995d655aa5a295b66412f131ea173affa1ae71fab7cd7314f4c7f234d56e381d851091b630dc4b" + "signature": "020728ec8d94e389f68f2ff1a6b3a703a606ee02fcfe38a660162a17b0d3cdb005b292b4d5becf7a4e498583ffd04aef5c55ae53994941f1580e9c3e78630f02" } diff --git a/tests/http/merchant.order.status.changed.http b/tests/http/merchant.order.status.changed.http index 8bac8d3..5a7816f 100644 --- a/tests/http/merchant.order.status.changed.http +++ b/tests/http/merchant.order.status.changed.http @@ -107,5 +107,5 @@ Content-Type: application/json ] } ], - "signature": "93c0f76f65a98ff61dc65fdbae17b62a82b04491d796b4476dee070ed99c68d686052fa0606f03d6570996303d02f4d40e4e2905944c302eb5d7e28d9bec87ad" + "signature": "7430f5a6b7c9d4855c8b709701a60646bfb93752d7aaa24f908f961b690c77e1f80983161cfac0f360cd8d1e1b072e3693250e9b53b4cef4c57729e5795256b4" } diff --git a/tests/json/merchant.order.status.changed-v2-confirmed-amount-null.json b/tests/json/merchant.order.status.changed-v2-confirmed-amount-null.json new file mode 100644 index 0000000..f00cde8 --- /dev/null +++ b/tests/json/merchant.order.status.changed-v2-confirmed-amount-null.json @@ -0,0 +1,37 @@ +{ + "signature":"e60e2a7b4b4c7a20bbdc1711a5db7baca373f4d0685abde75245ae391f5eb384235da6b54eb2ce77072bcb132f886f3f7b999a9a5f0b1ad5fe2280ffbfdd8d21", + "moreOrderResultsAvailable":false, + "orderResults":[ + { + "merchantOrderId":"941", + "omnikassaOrderId":"da608eb4-b20b-40e4-8045-10bbd1309084", + "poiId":"5000", + "orderStatus":"EXPIRED", + "orderStatusDateTime":"2023-11-08T13:10:00.281+01:00", + "errorCode":"", + "paidAmount":{ + "currency":"EUR", + "amount":"0" + }, + "totalAmount":{ + "currency":"EUR", + "amount":"123700" + }, + "transactions":[ + { + "id":"2d8a6da6-77cc-45fb-8974-64a0f80d2517", + "paymentBrand":"MASTERCARD", + "type":"PAYMENT", + "status":"EXPIRED", + "amount":{ + "currency":"EUR", + "amount":"123700" + }, + "confirmedAmount":null, + "startTime":"2023-11-08T12:37:39.366+01:00", + "lastUpdateTime":"2023-11-08T13:10:00.281+01:00" + } + ] + } + ] +} diff --git a/tests/src/OrderResultsTest.php b/tests/src/OrderResultsTest.php index 7b7526a..149430f 100644 --- a/tests/src/OrderResultsTest.php +++ b/tests/src/OrderResultsTest.php @@ -60,9 +60,12 @@ public function test_order_results() { * * @link https://developer.rabobank.nl/product/10685/api/9770#/RaboSmartPayOnlinePaymentAPI_1013/operation/%2Forder%2Fserver%2Fapi%2Fv2%2Fevents%2Fresults%2Fmerchant.order.status.changed/get * @link https://github.com/pronamic/wp-pronamic-pay-omnikassa-2/issues/21 + * @dataProvider order_results_provider + * @param string $file JSON test file. + * @param string $transaction_id Transaction ID. */ - public function test_order_results_v2() { - $json = \file_get_contents( __DIR__ . '/../json/merchant.order.status.changed-v2.json', true ); + public function test_order_results_v2( $file, $transaction_id, $expected_confirmed_amount ) { + $json = \file_get_contents( $file, true ); $order_results = OrderResults::from_json( $json ); @@ -74,6 +77,38 @@ public function test_order_results_v2() { $transaction = \reset( $transactions ); - $this->assertEquals( '22b36073-57a3-4c3d-9585-87f2e55275a5', $transaction->get_id() ); + $this->assertEquals( $transaction_id, $transaction->get_id() ); + + $confirmed_amount = $transaction->get_confirmed_amount(); + + if ( null === $expected_confirmed_amount ) { + $this->assertNull( $confirmed_amount ); + } + + if ( null !== $expected_confirmed_amount ) { + $this->assertInstanceOf( Money::class, $confirmed_amount ); + $this->assertEquals( $expected_confirmed_amount, $confirmed_amount->get_amount() ); + } + } + + /** + * Order results test provider. + * + * @return array + */ + public static function order_results_provider() { + return [ + [ + __DIR__ . '/../json/merchant.order.status.changed-v2.json', + '22b36073-57a3-4c3d-9585-87f2e55275a5', + 10997 + + ], + [ + __DIR__ . '/../json/merchant.order.status.changed-v2-confirmed-amount-null.json', + '2d8a6da6-77cc-45fb-8974-64a0f80d2517', + null + ], + ]; } } From c67da404a103a068c4c8620ef45c39162efb154c Mon Sep 17 00:00:00 2001 From: Remco Tolsma <869674+remcotolsma@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:11:49 +0100 Subject: [PATCH 8/8] Update OrderResultsTest.php --- tests/src/OrderResultsTest.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/src/OrderResultsTest.php b/tests/src/OrderResultsTest.php index 149430f..8134b38 100644 --- a/tests/src/OrderResultsTest.php +++ b/tests/src/OrderResultsTest.php @@ -61,11 +61,12 @@ public function test_order_results() { * @link https://developer.rabobank.nl/product/10685/api/9770#/RaboSmartPayOnlinePaymentAPI_1013/operation/%2Forder%2Fserver%2Fapi%2Fv2%2Fevents%2Fresults%2Fmerchant.order.status.changed/get * @link https://github.com/pronamic/wp-pronamic-pay-omnikassa-2/issues/21 * @dataProvider order_results_provider - * @param string $file JSON test file. - * @param string $transaction_id Transaction ID. + * @param string $file JSON test file. + * @param string $transaction_id Transaction ID. + * @param int|null $expected_confirmed_amount Expected confirmed amount. */ public function test_order_results_v2( $file, $transaction_id, $expected_confirmed_amount ) { - $json = \file_get_contents( $file, true ); + $json = \file_get_contents( __DIR__ . '/../json/' . $file, true ); $order_results = OrderResults::from_json( $json ); @@ -99,15 +100,15 @@ public function test_order_results_v2( $file, $transaction_id, $expected_confirm public static function order_results_provider() { return [ [ - __DIR__ . '/../json/merchant.order.status.changed-v2.json', + 'merchant.order.status.changed-v2.json', '22b36073-57a3-4c3d-9585-87f2e55275a5', - 10997 + 10997, ], [ - __DIR__ . '/../json/merchant.order.status.changed-v2-confirmed-amount-null.json', + 'merchant.order.status.changed-v2-confirmed-amount-null.json', '2d8a6da6-77cc-45fb-8974-64a0f80d2517', - null + null, ], ]; }