Skip to content

Commit

Permalink
Merge pull request #62 from omise/webhook
Browse files Browse the repository at this point in the history
Introduce WebHooks feature
  • Loading branch information
guzzilar committed Sep 13, 2017
2 parents d04df8f + 231510a commit 3b0c6c2
Show file tree
Hide file tree
Showing 10 changed files with 486 additions and 6 deletions.
32 changes: 32 additions & 0 deletions includes/admin/views/omise-page-settings.php
Expand Up @@ -65,6 +65,38 @@
</tbody>
</table>

<hr />

<table class="form-table">
<tbody>
<tr>
<th scope="row"><label><?php _e( 'Webhook endpoint', 'omise' ); ?></label></th>
<td>
<fieldset>
<code><?php echo get_rest_url( null, 'omise/webhooks' ); ?></code>
<p class="description">
<?php
echo sprintf(
wp_kses(
__( 'To enable <a href="%s">WebHooks</a> feature, you must setup an endpoint at <a href="%s"><strong>Omise dashboard</strong></a> by using the above url <em>(HTTPS only)</em>.', 'omise' ),
array(
'a' => array( 'href' => array() ),
'em' => array(),
'strong' => array()
)
),
esc_url( 'https://www.omise.co/api-webhooks' ),
esc_url( 'https://dashboard.omise.co/test/webhooks/edit' )
);
?>
</fieldset>
</td>
</tr>
</tbody>
</table>

<hr />

<h3><?php _e( 'Payment Methods', 'omise' ); ?></h3>
<p><?php _e( 'The table below is a list of available payment methods that you can enable in your WooCommerce store.', 'omise' ); ?></p>
<table class="form-table">
Expand Down
60 changes: 60 additions & 0 deletions includes/class-omise-events.php
@@ -0,0 +1,60 @@
<?php
defined( 'ABSPATH' ) or die( 'No direct script access allowed.' );

if ( class_exists( 'Omise_Events' ) ) {
return;
}

class Omise_Events {
/**
* @var array of event classes that we can handle.
*/
protected $events = array();

public function __construct() {
$events = array(
'Omise_Event_Charge_Capture',
'Omise_Event_Charge_Complete',
'Omise_Event_Charge_Create'
);

foreach ( $events as $event ) {
$clazz = new $event;
$this->events[ $clazz->event ] = $clazz;
}
}

/**
* Note. It doesn't return anything back because nobody using the result
* unless we have a 'log' system.
*
* @param string $event
* @param mixed $data
*
* @return void
*/
public function handle( $event, $data ) {
if ( ! isset( $this->events[ $event ] ) ) {
return;
}

/**
* Hook before Omise handle an event from webhook.
*
* @param mixed $data a data of an event object
*/
do_action( 'omise_before_handle_event_' . $event, $data );

$result = $this->events[ $event ]->handle( $data );

/**
* Hook after Omise handle an event from webhook.
*
* @param mixed $data a data of an event object
* @param mixed $result a result of an event handler
*/
do_action( 'omise_after_handle_event_' . $event, $data, $result );

return $result;
}
}
56 changes: 56 additions & 0 deletions includes/class-omise-rest-webhooks-controller.php
@@ -0,0 +1,56 @@
<?php
defined( 'ABSPATH' ) or die( 'No direct script access allowed.' );

if ( class_exists( 'Omise_Rest_Webhooks_Controller' ) ) {
return;
}

class Omise_Rest_Webhooks_Controller {
/**
* Endpoint namespace.
*
* @var string
*/
const ENDPOINT_NAMESPACE = 'omise';

/**
* @var string
*/
const ENDPOINT = 'webhooks';

/**
* Register the routes for webhooks.
*/
public function register_routes() {
register_rest_route(
self::ENDPOINT_NAMESPACE,
'/' . self::ENDPOINT,
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'callback' ),
)
);
}

/**
* @param WP_REST_Request $request
*
* @return WP_Error|WP_REST_Response
*/
public function callback( $request ) {
if ( 'application/json' !== $request->get_header( 'Content-Type' ) ) {
return new WP_Error( 'omise_rest_wrong_header', __( 'Wrong header type.', 'omise' ), array( 'status' => 400 ) );
}

$body = json_decode( $request->get_body() );

if ( 'event' !== $body->object ) {
return new WP_Error( 'omise_rest_wrong_object', __( 'Wrong object type.', 'omise' ), array( 'status' => 400 ) );
}

$event = new Omise_Events;
$event = $event->handle( $body->key, $body->data );

return rest_ensure_response( $event );
}
}
85 changes: 85 additions & 0 deletions includes/events/class-omise-event-charge-capture.php
@@ -0,0 +1,85 @@
<?php
defined( 'ABSPATH' ) or die( 'No direct script access allowed.' );

if ( class_exists( 'Omise_Event_Charge_Capture' ) ) {
return;
}

class Omise_Event_Charge_Capture {
/**
* @var string of an event name.
*/
public $event = 'charge.capture';

/**
* There are several cases that can trigger the 'charge.capture' event.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* Credit Card
* charge data in payload will be:
* [status: 'successful'], [authorized: 'true'], [paid: 'true']
*
* @param mixed $data
*
* @return void
*/
public function handle( $data ) {
if ( 'charge' !== $data->object || ! isset( $data->metadata->order_id ) ) {
return;
}

if ( ! $order = wc_get_order( $data->metadata->order_id ) ) {
return;
}

$order->add_order_note(
__(
'Omise: an event charge.capture has been caught (webhook).',
'omise'
)
);

switch ($data->status) {
case 'successful':
// Backward compatible with Omise API version 2014-07-27 by checking if 'captured' exist.
$paid = isset( $data->captured ) ? $data->captured : $data->paid;

if ( $data->authorized && $paid ) {
$order->add_order_note(
sprintf(
wp_kses(
__( 'Omise: Payment successful (manual capture).<br/>An amount %1$s %2$s has been paid', 'omise' ),
array( 'br' => array() )
),
$order->get_total(),
$order->get_order_currency()
)
);

$order->payment_complete( $data->id );
}

break;

default:
$order->add_order_note(
wp_kses(
__( 'Omise: Payment invalid.<br/>There was something wrong in the Webhook payload. Please contact Omise support team to investigate further.', 'omise' ),
array( 'br' => array() )
)
);

break;
}

/**
* Hook after Omise handle an event from webhook.
*
* @param WC_Order $order an order object.
* @param mixed $data a data of an event object
*/
do_action( 'omise_handled_event_charge_capture', $order, $data );

return;
}
}
118 changes: 118 additions & 0 deletions includes/events/class-omise-event-charge-complete.php
@@ -0,0 +1,118 @@
<?php
defined( 'ABSPATH' ) or die( 'No direct script access allowed.' );

if ( class_exists( 'Omise_Event_Charge_Complete' ) ) {
return;
}

class Omise_Event_Charge_Complete {
/**
* @var string of an event name.
*/
public $event = 'charge.complete';

/**
* There are several cases with the following payment methods
* that would trigger the 'charge.complete' event.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* Alipay
* charge data in payload:
* [status: 'successful'], [authorized: 'true'], [paid: 'true']
* [status: 'failed'], [authorized: 'false'], [paid: 'false']
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* Internet Banking
* charge data in payload:
* [status: 'successful'], [authorized: 'true'], [paid: 'true']
* [status: 'failed'], [authorized: 'false'], [paid: 'false']
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* Credit Card (3-D Secure)
* CAPTURE = FALSE
* charge data in payload could be one of these sets:
* [status: 'pending'], [authorized: 'true'], [paid: 'false']
* [status: 'failed'], [authorized: 'false'], [paid: 'false']
*
* CAPTURE = TRUE
* charge data in payload could be one of these sets:
* [status: 'successful'], [authorized: 'true'], [paid: 'true']
* [status: 'failed'], [authorized: 'false'], [paid: 'false']
*
* @param mixed $data
*
* @return void
*/
public function handle( $data ) {
if ( 'charge' !== $data->object || ! isset( $data->metadata->order_id ) ) {
return;
}

if ( ! $order = wc_get_order( $data->metadata->order_id ) ) {
return;
}

$order->add_order_note(
__(
'Omise: an event charge.complete has been caught (webhook).',
'omise'
)
);

switch ($data->status) {
case 'failed':
$order->add_order_note(
sprintf(
wp_kses(
__( 'Omise: Payment failed.<br/>%s', 'omise' ),
array( 'br' => array() )
),
$data->failure_message . ' (code: ' . $data->failure_code . ')'
)
);

$order->update_status( 'failed' );
break;

case 'successful':
// Backward compatible with Omise API version 2014-07-27 by checking if 'captured' exist.
$paid = isset( $data->captured ) ? $data->captured : $data->paid;

if ( $data->authorized && $paid ) {
$order->add_order_note(
sprintf(
wp_kses(
__( 'Omise: Payment successful.<br/>An amount %1$s %2$s has been paid', 'omise' ),
array( 'br' => array() )
),
$order->get_total(),
$order->get_order_currency()
)
);

$order->payment_complete( $data->id );
}
break;

case 'pending':
// Credit Card 3-D Secure with 'authorize only' payment action case.
if ( $data->authorized ) {
$order->update_status( 'processing' );
}
break;

default:
break;
}

/**
* Hook after Omise handle an event from webhook.
*
* @param WC_Order $order an order object.
* @param mixed $data a data of an event object
*/
do_action( 'omise_handled_event_charge_complete', $order, $data );

return;
}
}

0 comments on commit 3b0c6c2

Please sign in to comment.