Skip to content

Commit

Permalink
Merge pull request #45 from omise/handle-charge-complete-event
Browse files Browse the repository at this point in the history
  • Loading branch information
nimid committed Nov 20, 2017
2 parents ce98674 + e15d012 commit 314cc4d
Show file tree
Hide file tree
Showing 12 changed files with 548 additions and 1 deletion.
3 changes: 3 additions & 0 deletions omise/classes/omise_charge_class.php
Expand Up @@ -11,6 +11,9 @@

class OmiseChargeClass
{
const STATUS_FAILED = 'failed';
const STATUS_SUCCESSFUL = 'successful';

protected $context;
protected $charge_response;
protected $setting;
Expand Down
40 changes: 40 additions & 0 deletions omise/classes/omise_logger.php
@@ -0,0 +1,40 @@
<?php
if (! defined('_PS_VERSION_')) {
exit();
}

class OmiseLogger
{
const ERROR = 3;
const INFO = 1;
const MAJOR_ISSUE = 4;
const WARNING = 2;

/**
* Add log message to PrestaShop database.
* The added log message will be displayed in PrestaShop back office.
*
* @param string $message
* @param int $severity
*
* @return bool
*
* @see PrestaShopLoggerCore::addLog()
*/
public function add($message, $severity = OmiseLogger::INFO)
{
$allow_duplicate = true;
$error_code = null;
$object_id = null;
$object_type = null;

return Logger::addLog(
$message,
$severity,
$error_code,
$object_type,
$object_id,
$allow_duplicate
);
}
}
26 changes: 26 additions & 0 deletions omise/classes/omise_transaction_model.php
Expand Up @@ -67,4 +67,30 @@ public function getIdCharge($id_order)

return $result['id_charge'];
}

/**
* Return a PrestaShop order ID by searching from a given parameter, Omise charge ID.
*
* @param string $id_charge An Omise charge ID.
*
* @return int|false A PrestaShop order ID or false, if a PrestaShop order ID is not found.
*/
public function getIdOrder($id_charge)
{
$query = new DbQuery();
$query->select('id_order');
$query->from('omise_transaction');
$query->where('id_charge = \'' . pSQL($id_charge) . '\'');

$result = Db::getInstance()->getRow($query);

if (! $result
|| empty($result)
|| ! array_key_exists('id_order', $result)
) {
return false;
}

return $result['id_order'];
}
}
32 changes: 32 additions & 0 deletions omise/classes/omise_webhooks.php
@@ -0,0 +1,32 @@
<?php
if (! defined('_PS_VERSION_')) {
exit();
}

class OmiseWebhooks
{
/**
* Return the request body that received from Omise server.
*
* @return mixed|null The null will be returned. For examples,
*
* - The request from Omise server is HTTP GET not HTTP POST.
* - The request body is empty.
* - The request body is invalid JSON format.
*/
public function getRequestBody()
{
$return_value_as_array = true;

$data = file_get_contents('php://input');

return json_decode($data, $return_value_as_array);
}

public function sendRawHeaderAsBadRequest()
{
$replace_previous_similar_header = true;

header('HTTP/1.1 400 Bad Request', $replace_previous_similar_header, 400);
}
}
70 changes: 70 additions & 0 deletions omise/controllers/front/webhooks.php
Expand Up @@ -3,10 +3,80 @@
exit();
}

if (defined('_PS_MODULE_DIR_')) {
require_once _PS_MODULE_DIR_ . 'omise/classes/omise_webhooks.php';
require_once _PS_MODULE_DIR_ . 'omise/events/omise_event_handler.php';
}

class OmiseWebhooksModuleFrontController extends ModuleFrontController
{
/**
* @var OmiseEventHandler
*/
protected $omise_event_handler;

/**
* @var OmiseWebhooks
*/
protected $omise_webhooks;

public function __construct()
{
parent::__construct();

$this->setOmiseEventHandler(new OmiseEventHandler());
$this->setOmiseWebhooks(new OmiseWebhooks());
}

/**
* @param mixed $request_body The array of JSON decoded from Omise event object.
*
* @return bool
*/
protected function isRequestValid($request_body)
{
if (is_null($request_body)) {
return false;
}

if (! array_key_exists('object', $request_body)) {
return false;
}

if ($request_body['object'] !== 'event') {
return false;
}

return true;
}

public function postProcess()
{
$this->setTemplate('module:omise/views/templates/front/webhooks.tpl');

$request_body = $this->omise_webhooks->getRequestBody();

if (! $this->isRequestValid($request_body)) {
$this->omise_webhooks->sendRawHeaderAsBadRequest();
return;
}

$this->omise_event_handler->handle($request_body);
}

/**
* @param OmiseEventHandler $omise_event_handler The instance of class, OmiseEventHandler.
*/
public function setOmiseEventHandler($omise_event_handler)
{
$this->omise_event_handler = $omise_event_handler;
}

/**
* @param OmiseWebhooks $omise_webhooks The instance of class, OmiseWebhooks.
*/
public function setOmiseWebhooks($omise_webhooks)
{
$this->omise_webhooks = $omise_webhooks;
}
}
25 changes: 25 additions & 0 deletions omise/events/omise_base_event.php
@@ -0,0 +1,25 @@
<?php
if (! defined('_PS_VERSION_')) {
exit();
}

if (defined('_PS_MODULE_DIR_')) {
require_once _PS_MODULE_DIR_ . 'omise/classes/omise_logger.php';
require_once _PS_MODULE_DIR_ . 'omise/classes/payment_order.php';
}

abstract class OmiseBaseEvent
{
protected $omise_logger;
protected $omise_transaction_model;
protected $payment_order;

public function __construct()
{
$this->omise_logger = new OmiseLogger();
$this->omise_transaction_model = new OmiseTransactionModel();
$this->payment_order = new PaymentOrder();
}

public abstract function handle($event);
}
51 changes: 51 additions & 0 deletions omise/events/omise_event_charge_complete.php
@@ -0,0 +1,51 @@
<?php
if (! defined('_PS_VERSION_')) {
exit();
}

if (defined('_PS_MODULE_DIR_')) {
require_once _PS_MODULE_DIR_ . 'omise/classes/omise_charge_class.php';
require_once _PS_MODULE_DIR_ . 'omise/events/omise_base_event.php';
}

class OmiseEventChargeComplete extends OmiseBaseEvent
{
const KEY = 'charge.complete';

/**
* @param mixed $event The array of JSON decoded from Omise event object.
*
* @return bool
*/
public function handle($event)
{
$charge = $event['data'];

$id_order = $this->omise_transaction_model->getIdOrder($charge['id']);
$order = new Order($id_order);

if (! Validate::isLoadedObject($order)) {
return false;
}

$message = 'Omise Webhooks: an event charge.complete, ' . $event['id'] . ', has been caught.';

switch ($charge['status']) {
case OmiseChargeClass::STATUS_FAILED:
$this->payment_order->updateStateToBeCanceled($order);

$message .= ' The status of order, ' . $id_order . ', has been updated to be Canceled.';
$this->omise_logger->add($message);
break;

case OmiseChargeClass::STATUS_SUCCESSFUL:
$this->payment_order->updateStateToBeSuccess($order);

$message .= ' The status of order, ' . $id_order . ', has been updated to be Payment accepted.';
$this->omise_logger->add($message);
break;
}

return true;
}
}
33 changes: 33 additions & 0 deletions omise/events/omise_event_handler.php
@@ -0,0 +1,33 @@
<?php
if (! defined('_PS_VERSION_')) {
exit();
}

if (defined('_PS_MODULE_DIR_')) {
require_once _PS_MODULE_DIR_ . 'omise/events/omise_event_charge_complete.php';
}

class OmiseEventHandler
{
/**
* Call another class to perform function for each event. The class to be used for handling event has been
* determined by using the attribute named, key, of Omise event object.
*
* @param mixed $event The array of JSON decoded from Omise event object.
*
* @return bool
*/
public function handle($event)
{
switch ($event['key']) {
case OmiseEventChargeComplete::KEY:
$omise_event = new OmiseEventChargeComplete();
break;

default:
return false;
}

return $omise_event->handle($event);
}
}
48 changes: 48 additions & 0 deletions tests/unit/classes/OmiseLoggerTest.php
@@ -0,0 +1,48 @@
<?php
use \Mockery as m;

class OmiseLoggerTest extends Mockery\Adapter\Phpunit\MockeryTestCase
{
private $omise_logger;

public function setup()
{
$this->omise_logger = new OmiseLogger();
}

public function testAdd_addLogWithoutSeverityParameter_logMustBeAddedWithDefaultSeverity()
{
$message = 'message';

m::mock('alias:\Logger')
->shouldReceive('addLog')
->with(
$message,
OmiseLogger::INFO,
null,
null,
null,
true
);

$this->omise_logger->add($message);
}

public function testAdd_addLogWithSeverityParameter_logMustBeAddedWithSpecifiedSeverityParameter()
{
$message = 'message';

m::mock('alias:\Logger')
->shouldReceive('addLog')
->with(
$message,
OmiseLogger::ERROR,
null,
null,
null,
true
);

$this->omise_logger->add($message, OmiseLogger::ERROR);
}
}

0 comments on commit 314cc4d

Please sign in to comment.