Skip to content

Commit

Permalink
Merge pull request #29 from pronamic/27-webhook-problem-object-does-n…
Browse files Browse the repository at this point in the history
…ot-have-transactionid-property

27 webhook problem object does not have transactionid property
  • Loading branch information
remcotolsma committed Nov 8, 2023
2 parents d07077f + c67da40 commit 81be3d1
Show file tree
Hide file tree
Showing 10 changed files with 298 additions and 94 deletions.
10 changes: 1 addition & 9 deletions src/Gateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Expand All @@ -567,14 +566,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();
Expand Down
40 changes: 33 additions & 7 deletions src/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,44 @@ 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;
}
}

$signature_b = $this->get_signature();
/**
* Verify signature.
*
* @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 = (string) $this->get_signature();

if ( empty( $signature_b ) ) {
return false;
}
$signature_calculated = Security::get_signature( $this, $signing_key );

return Security::validate_signature( $signature_a, $signature_b );
$result = Security::validate_signature( $signature_enclosed, $signature_calculated );

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 ),
'*'
)
)
)
);
}
}
}
24 changes: 24 additions & 0 deletions src/OrderResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,30 @@ public function get_transactions() {
return $this->transactions;
}

/**
* Get signature fields.
*
* @param array<string> $fields Fields.
* @return array<string>
*/
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.
*
Expand Down
10 changes: 1 addition & 9 deletions src/OrderResults.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
117 changes: 107 additions & 10 deletions src/Transaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ final class Transaction {
private $payment_brand;

/**
* Type.
* Type of the transaction.
*
* @var string
*/
Expand All @@ -42,19 +42,63 @@ 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.
*
* @param string $id Transaction ID.
* @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;
}

/**
Expand Down Expand Up @@ -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<string> $fields Fields.
* @return array<string>
*/
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.
*
Expand All @@ -102,11 +188,22 @@ public function get_status() {
public static function from_object( $data ) {
$object_access = new ObjectAccess( $data );

return new self(
$object_access->get_string( 'transactionId' ),
$transaction = new self(
$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' ),
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;
}
}
38 changes: 19 additions & 19 deletions tests/http/merchant.order.status.changed-cancelled.http
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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"
}
]
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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"
}
]
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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": "020728ec8d94e389f68f2ff1a6b3a703a606ee02fcfe38a660162a17b0d3cdb005b292b4d5becf7a4e498583ffd04aef5c55ae53994941f1580e9c3e78630f02"
}
Loading

0 comments on commit 81be3d1

Please sign in to comment.