Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Checkout Widget #21

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Api/Transaction/Data/DataInterface.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface DataInterface extends ExtensibleDataInterface
*/
public const ENTITY_ID = 'entity_id';
public const QUOTE_ID = 'quote_id';
public const AMOUNT = 'amount';
public const ORDER_ID = 'order_id';
public const UUID = 'uuid';
public const TOKEN = 'token';
Expand Down Expand Up @@ -50,6 +51,21 @@ public function getQuoteId(): ?int;
*/
public function setQuoteId(int $quoteId): self;

/**
* Returns transaction amount.
*
* @return int quote ID.
*/
public function getAmount(): int;

/**
* Sets transaction amount.
*
* @param int $amount
* @return $this
*/
public function setAmount(int $amount): self;

/**
* Returns the order ID.
*
Expand Down
16 changes: 16 additions & 0 deletions Model/Transaction/DataModel.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ public function setQuoteId(int $quoteId): DataInterface
return $this->setData(self::QUOTE_ID, $quoteId);
}

/**
* @inheritDoc
*/
public function getAmount(): int
{
return (int)$this->getData(self::AMOUNT);
}

/**
* @inheritDoc
*/
public function setAmount(int $amount): DataInterface
{
return $this->setData(self::AMOUNT, $amount);
}

/**
* @inheritDoc
*/
Expand Down
4 changes: 2 additions & 2 deletions Model/Webapi/Checkout.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ public function orderRequest(bool $isLoggedIn, string $cartId)
//web api can't return first level associative array
$return = [];
try {
$paymentUrl = $this->orderRequest->execute($token);
$return['response'] = ['success' => true, 'payment_page_url' => $paymentUrl];
$response = $this->orderRequest->execute($token);
$return['response'] = ['success' => true, 'response' => $response];
return $return;
} catch (\Exception $exception) {
$this->logRepository->addErrorLog('Checkout endpoint', $exception->getMessage());
Expand Down
92 changes: 12 additions & 80 deletions Service/Order/MakeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public function __construct(
* Executes TrueLayer Api for Order Request and returns redirect to platform Url
*
* @param string $token
* @return string
* @return array
* @throws AuthenticationException
* @throws CouldNotSaveException
* @throws InputException
Expand All @@ -133,7 +133,7 @@ public function __construct(
* @throws \TrueLayer\Exceptions\InvalidArgumentException
* @throws \TrueLayer\Exceptions\ValidationException
*/
public function execute(string $token): string
public function execute(string $token)
{
$transaction = $this->transactionRepository->getByToken($token);
$quote = $this->quoteRepository->get($transaction->getQuoteId());
Expand Down Expand Up @@ -163,15 +163,15 @@ public function execute(string $token): string
}

if ($payment->getId()) {
$transaction->setUuid($payment->getId());
$transaction->setUuid($payment->getId())
->setAmount($paymentData['amount_in_minor']);
$this->transactionRepository->save($transaction);
$this->duplicateCurrentQuote($quote);
return $payment->hostedPaymentsPage()
->returnUri($this->getReturnUrl())
->primaryColour($this->configProvider->getPaymentPagePrimaryColor())
->secondaryColour($this->configProvider->getPaymentPageSecondaryColor())
->tertiaryColour($this->configProvider->getPaymentPageTertiaryColor())
->toUrl();

return [
'payment_id' => $payment->getId(),
'resource_token' => $payment->getResourceToken(),
'transaction_id' => $transaction->getUuid(),
];
}

$msg = self::REQUEST_EXCEPTION;
Expand Down Expand Up @@ -233,7 +233,8 @@ private function prepareData(Quote $quote, string $merchantAccountId): array
"type" => "merchant_account",
"name" => $this->configProvider->getMerchantAccountName(),
"merchant_account_id" => $merchantAccountId
]
],
"retry" => []
],
"user" => [
"name" => trim($quote->getBillingAddress()->getFirstname()) .
Expand All @@ -252,73 +253,4 @@ private function prepareData(Quote $quote, string $merchantAccountId): array

return $data;
}

/**
* Duplicate current quote and set this as active session.
* This prevents quotes to change during checkout process
*
* @param Quote $quote
* @throws NoSuchEntityException
* @throws CouldNotSaveException
*/
private function duplicateCurrentQuote(Quote $quote)
{
$quote->setIsActive(false);
$this->quoteRepository->save($quote);
if ($customerId = $quote->getCustomerId()) {
$cartId = $this->cartManagement->createEmptyCartForCustomer($customerId);
} else {
$cartId = $this->cartManagement->createEmptyCart();
}
$newQuote = $this->quoteRepository->get($cartId);
$newQuote->merge($quote);

$newQuote->removeAllAddresses();
if (!$quote->getIsVirtual()) {
$addressData = $this->dataObjectProcessor->buildOutputDataArray(
$quote->getShippingAddress(),
AddressInterface::class
);
unset($addressData['id']);
$shippingAddress = $this->quoteAddressFactory->create();
$this->dataObjectHelper->populateWithArray(
$shippingAddress,
$addressData,
AddressInterface::class
);
$newQuote->setShippingAddress(
$shippingAddress
);
}

$addressData = $this->dataObjectProcessor->buildOutputDataArray(
$quote->getBillingAddress(),
AddressInterface::class
);
unset($addressData['id']);
$billingAddress = $this->quoteAddressFactory->create();
$this->dataObjectHelper->populateWithArray(
$billingAddress,
$addressData,
AddressInterface::class
);
$newQuote->setBillingAddress(
$billingAddress
);

$newQuote->setTotalsCollectedFlag(false)->collectTotals();
$this->quoteRepository->save($newQuote);

$this->checkoutSession->replaceQuote($newQuote);
}

/**
* Get return url
*
* @return string
*/
private function getReturnUrl(): string
{
return $this->configProvider->getBaseUrl() . 'truelayer/checkout/process/';
}
}
17 changes: 14 additions & 3 deletions Service/Order/ProcessWebhook.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use Exception;
use Magento\Checkout\Model\Session as CheckoutSession;
use Magento\Framework\Exception\LocalizedException;
use Magento\Quote\Api\CartManagementInterface;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Api\Data\CartInterface;
Expand All @@ -29,6 +30,7 @@ class ProcessWebhook
{

public const SUCCESS_MSG = 'Order #%1 successfully captured on TrueLayer';

/**
* @var CheckoutSession
*/
Expand Down Expand Up @@ -127,11 +129,19 @@ public function execute(string $uuid, string $userId)
);

if (!$quoteId = $transaction->getQuoteId()) {
$this->logRepository->addDebugLog('webhook', 'no quote id found in transaction');
return;
$message = 'No quote id found in transaction';
$this->logRepository->addDebugLog('webhook', $message);
throw new LocalizedException(__($message));
}

$quote = $this->quoteRepository->get($quoteId);

if ($transaction->getAmount() != (int)bcmul((string)$quote->getBaseGrandTotal(), '100')) {
$message = 'Quote amount was changed';
$this->logRepository->addDebugLog('webhook', $message);
throw new LocalizedException(__($message));
}

$this->checkoutSession->setQuoteId($quoteId);

if (!$this->transactionRepository->isLocked($transaction)) {
Expand All @@ -150,6 +160,7 @@ public function execute(string $uuid, string $userId)
}
} catch (Exception $e) {
$this->logRepository->addDebugLog('webhook exception', $e->getMessage());
throw new LocalizedException(__($e->getMessage()));
}
}

Expand All @@ -176,7 +187,7 @@ private function placeOrder(CartInterface $quote, $uuid, $userId)
$this->sendInvoiceEmail($order);
} catch (Exception $e) {
$this->logRepository->addDebugLog('place order', $e->getMessage());
return false;
throw new LocalizedException(__($e->getMessage()));
}

return $order->getEntityId();
Expand Down
10 changes: 10 additions & 0 deletions etc/csp_whitelist.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<csp_whitelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Csp:etc/csp_whitelist.xsd">
<policies>
<policy id="script-src">
<values>
<value id="jsdelivr" type="host">https://cdn.jsdelivr.net</value>
</values>
</policy>
</policies>
</csp_whitelist>
1 change: 1 addition & 0 deletions etc/db_schema.xml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<table name="truelayer_transaction" engine="innodb" resource="default" comment="TrueLayer Transaction Table">
<column name="entity_id" xsi:type="int" identity="true" nullable="false" unsigned="true" comment="Entity ID"/>
<column name="quote_id" xsi:type="int" padding="10" nullable="false" unsigned="true" comment="Quote Id"/>
<column name="amount" xsi:type="int" padding="10" nullable="false" default="0" comment="Amount"/>
<column name="order_id" xsi:type="int" nullable="true" unsigned="true" comment="Order Id"/>
<column name="token" xsi:type="varchar" length="128" nullable="false" comment="Token"/>
<column name="uuid" xsi:type="varchar" length="128" nullable="true" default="NULL" comment="Uuid from Response"/>
Expand Down
3 changes: 0 additions & 3 deletions view/frontend/layout/checkout_index_index.xml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
<head>
<css src="TrueLayer_Connect::css/styles.css"/>
</head>
<body>
<referenceBlock name="checkout.root">
<arguments>
Expand Down
8 changes: 8 additions & 0 deletions view/frontend/requirejs-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var config = {
map: {
'*': {
'Magento_SalesRule/js/action/select-payment-method-mixin': 'TrueLayer_Connect/js/action/select-payment-method-mixin'
}
}
};

1 change: 1 addition & 0 deletions view/frontend/web/css/source/_module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import 'component/_widget.less';
63 changes: 63 additions & 0 deletions view/frontend/web/css/source/component/_widget.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// Common
// _____________________________________________

& when (@media-common = true) {

// Modify base payment method styles for truelayer method
.truelayer-payment-method {
.payment-method-title {
label {
position: relative;
padding-left: 32px;

&::before {
content: '';

position: absolute;
top: -6px;
left: 0;

width: 24px;
height: 24px;
background: url("TrueLayer_Connect::images/bank.svg") no-repeat center center;
}
}
}

.payment-method-content {
iframe {
border: 0;
}

.small [name="tl-checkout-widget"],
.small .loader {
height: 60px;
margin-bottom: 18px;
}

.large [name="tl-checkout-widget"],
.large .loader {
min-height: 160px;
margin-bottom: 18px;
}

.widget-button {
position: relative;
z-index: 10;
max-width: 450px;
}

.loader {
display: block;
background: url("@{baseDir}images/loader-1.gif") no-repeat center center;
background-size: 36px;
}
}

.message.success,
.message.info {
margin-bottom: 24px;
}
}
}
17 changes: 0 additions & 17 deletions view/frontend/web/css/styles.css

This file was deleted.

19 changes: 19 additions & 0 deletions view/frontend/web/images/bank.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading