Skip to content

Commit

Permalink
Release 0.7.0 (rvvup#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
aashwin-rvvup authored Nov 9, 2022
1 parent cacd049 commit 494bb1c
Show file tree
Hide file tree
Showing 21 changed files with 537 additions and 98 deletions.
45 changes: 45 additions & 0 deletions Api/Data/WebhookInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php declare(strict_types=1);

namespace Rvvup\Payments\Api\Data;

interface WebhookInterface
{
/**
* String constants for property names
*/
public const WEBHOOK_ID = "webhook_id";
public const ID = "id";
public const PAYLOAD = "payload";

/**
* Getter for Id.
*
* @return int|null
*/
public function getId();

/**
* Setter for Id.
*
* @param int|null $id
*
* @return void
*/
public function setId($id);

/**
* Getter for Payload.
*
* @return string|null
*/
public function getPayload(): ?string;

/**
* Setter for Payload.
*
* @param string|null $payload
*
* @return void
*/
public function setPayload(?string $payload): void;
}
32 changes: 32 additions & 0 deletions Api/WebhookRepositoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);

namespace Rvvup\Payments\Api;

use Rvvup\Payments\Api\Data\WebhookInterface;

interface WebhookRepositoryInterface
{
/**
* @param array $data
* @return WebhookInterface
*/
public function new(array $data = []): WebhookInterface;

/**
* @param WebhookInterface $webhook
* @return WebhookInterface
*/
public function save(WebhookInterface $webhook): WebhookInterface;

/**
* @param int $id
* @return WebhookInterface
*/
public function getById(int $id): WebhookInterface;

/**
* @param WebhookInterface $webhook
* @return WebhookInterface
*/
public function delete(WebhookInterface $webhook): WebhookInterface;
}
134 changes: 41 additions & 93 deletions Controller/Webhook/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Controller\ResultInterface;
use Magento\Sales\Api\Data\OrderPaymentInterface;
use Magento\Sales\Api\OrderPaymentRepositoryInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Framework\Serialize\SerializerInterface;
use Psr\Log\LoggerInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\MessageQueue\PublisherInterface;
use Rvvup\Payments\Model\ConfigInterface;
use Rvvup\Payments\Model\Payment\PaymentDataGetInterface;
use Rvvup\Payments\Model\ProcessOrder\ProcessorPool;
use Rvvup\Payments\Model\WebhookRepository;

/**
* The purpose of this controller is to accept incoming webhooks from Rvvup to update the status of payments
Expand All @@ -26,20 +23,16 @@ class Index implements HttpPostActionInterface, CsrfAwareActionInterface
{
/** @var RequestInterface */
private $request;
/** @var ResultFactory */
private $resultFactory;
/** @var ConfigInterface */
private $config;
/** @var SearchCriteriaBuilder */
private $searchCriteriaBuilder;
/** @var OrderPaymentRepositoryInterface */
private $orderPaymentRepository;
/** @var OrderRepositoryInterface */
private $orderRepository;
/** @var PaymentDataGetInterface */
private $paymentDataGet;
/** @var ProcessorPool */
private $processorPool;
/** @var SerializerInterface */
private $serializer;
/** @var ResultFactory */
private $resultFactory;
/** @var PublisherInterface */
private $publisher;
/** @var WebhookRepository */
private $webhookRepository;

/**
* Set via di.xml
Expand All @@ -50,48 +43,40 @@ class Index implements HttpPostActionInterface, CsrfAwareActionInterface

/**
* @param RequestInterface $request
* @param ResultFactory $resultFactory
* @param ConfigInterface $config
* @param SearchCriteriaBuilder $searchCriteriaBuilder
* @param OrderPaymentRepositoryInterface $orderPaymentRepository
* @param OrderRepositoryInterface $orderRepository
* @param PaymentDataGetInterface $paymentDataGet
* @param ProcessorPool $processorPool
* @param SerializerInterface $serializer
* @param ResultFactory $resultFactory
* @param LoggerInterface $logger
* @param PublisherInterface $publisher
* @param WebhookRepository $webhookRepository
*/
public function __construct(
RequestInterface $request,
ResultFactory $resultFactory,
ConfigInterface $config,
SearchCriteriaBuilder $searchCriteriaBuilder,
OrderPaymentRepositoryInterface $orderPaymentRepository,
OrderRepositoryInterface $orderRepository,
PaymentDataGetInterface $paymentDataGet,
ProcessorPool $processorPool,
LoggerInterface $logger
SerializerInterface $serializer,
ResultFactory $resultFactory,
LoggerInterface $logger,
PublisherInterface $publisher,
WebhookRepository $webhookRepository
) {
$this->request = $request;
$this->resultFactory = $resultFactory;
$this->config = $config;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
$this->orderPaymentRepository = $orderPaymentRepository;
$this->orderRepository = $orderRepository;
$this->paymentDataGet = $paymentDataGet;
$this->processorPool = $processorPool;
$this->serializer = $serializer;
$this->resultFactory = $resultFactory;
$this->logger = $logger;
$this->publisher = $publisher;
$this->webhookRepository = $webhookRepository;
}

/**
* ToDO: Move process logic in service running in queue. Controller should just store data and return success.
*
* @return ResultInterface
*/
public function execute(): ResultInterface
{
$merchantId = $this->request->getParam('merchant_id', false);
$rvvupOrderId = $this->request->getParam('order_id', false);

try {
$merchantId = $this->request->getParam('merchant_id', false);
$rvvupOrderId = $this->request->getParam('order_id', false);

// Ensure required params are present
if (!$merchantId || !$rvvupOrderId) {
/**
Expand All @@ -102,65 +87,24 @@ public function execute(): ResultInterface
return $this->returnInvalidResponse();
}

// Ensure configured merchant_id matches request
// Merchant ID does not match, no need to process
if ($merchantId !== $this->config->getMerchantId()) {
/**
* The configuration in Magento is different from the webhook. We don't want Rvvup's backend to
* continually make repeated calls so return a 200 and log the issue.
*/
$this->logger->warning("`merchant_id` from webhook does not match configuration");
return $this->returnSuccessfulResponse();
}

// Saerch for the payment record by the Rvvup order ID which is stored in the credit card field.
$searchCriteria = $this->searchCriteriaBuilder->addFilter(
OrderPaymentInterface::CC_TRANS_ID,
$rvvupOrderId
)->create();

$resultSet = $this->orderPaymentRepository->getList($searchCriteria);

// We always expect 1 payment object for a Rvvup Order ID.
// Otherwise, this could be a malicious attempt, so log issue & return 200.
if ($resultSet->getTotalCount() !== 1) {
$this->logger->warning('Webhook error. Payment not found for order.', [
'rvvup_order_id' => $rvvupOrderId,
'payments_count' => $resultSet->getTotalCount()
]);

return $this->returnSuccessfulResponse();
}

$payments = $resultSet->getItems();

/** @var \Magento\Sales\Api\Data\OrderPaymentInterface $payment */
$payment = reset($payments);

$order = $this->orderRepository->get($payment->getParentId());

// if Payment method is not Rvvup, continue.
if (stripos($payment->getMethod(), 'rvvup_') !== 0) {
return $this->returnSuccessfulResponse();
}

$rvvupData = $this->paymentDataGet->execute($rvvupOrderId);

if (empty($rvvupData) || !isset($rvvupData['status'])) {
$this->logger->error('Webhook error. Rvvup order data could not be fetched.', [
'rvvup_order_id' => $rvvupOrderId
]);

return $this->returnExceptionResponse();
return $this->returnInvalidResponse();
}

$this->processorPool->getProcessor($rvvupData['status'])->execute($order, $rvvupData);
$payload = $this->serializer->serialize([
'order_id' => $rvvupOrderId,
'merchant_id' => $merchantId,
]);
$webhook = $this->webhookRepository->new(['payload' => $payload]);
$this->webhookRepository->save($webhook);
$this->publisher->publish('rvvup.webhook', (int) $webhook->getId());

return $this->returnSuccessfulResponse();
} catch (Exception $e) {
$this->logger->debug('Webhook exception:' . $e->getMessage(), [
'order_id' => $rvvupOrderId,
]);

return $this->returnExceptionResponse();
}
}
Expand Down Expand Up @@ -189,7 +133,11 @@ public function createCsrfValidationException(RequestInterface $request): ?Inval
private function returnSuccessfulResponse(): ResultInterface
{
$response = $this->resultFactory->create($this->resultFactory::TYPE_RAW);
$response->setHttpResponseCode(200);
/**
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202
* 202 Accepted: request has been accepted for processing, but the processing has not been completed
*/
$response->setHttpResponseCode(202);

return $response;
}
Expand Down
43 changes: 43 additions & 0 deletions Model/Data/WebhookData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php declare(strict_types=1);

namespace Rvvup\Payments\Model\Data;

use Magento\Framework\Model\AbstractModel;
use Rvvup\Payments\Api\Data\WebhookInterface;
use Rvvup\Payments\Model\ResourceModel\WebhookResource;

class WebhookData extends AbstractModel implements WebhookInterface
{
/** @var string */
protected $_eventPrefix = 'rvvup_webhook';

/**
* Set resource
*/
protected function _construct()
{
$this->_init(WebhookResource::class);
}

/**
* Getter for Payload.
*
* @return string|null
*/
public function getPayload(): ?string
{
return $this->getData(self::PAYLOAD);
}

/**
* Setter for Payload.
*
* @param string|null $payload
*
* @return void
*/
public function setPayload(?string $payload): void
{
$this->setData(self::PAYLOAD, $payload);
}
}
4 changes: 3 additions & 1 deletion Model/ProcessOrder/Cancel.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ public function execute(OrderInterface $order, array $rvvupData): ProcessOrderRe

if (!$result) {
$this->logger->debug('Could not cancel order on cancel processor', [
'order_id' => $order->getEntityId()
'order_id' => $order->getEntityId(),
'order_state' => $order->getState(),
'order_status' => $order->getStatus()
]);
}

Expand Down
Loading

0 comments on commit 494bb1c

Please sign in to comment.