Skip to content
Open
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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ php-unit-utility:

php-unit-infrastructure-integration:
docker exec -i $${MODULE_VERSION}-ps-prestashop-$${PS_VERSION_TAG} bash -c "php modules/ps_checkout/vendor/bin/phpunit --configuration=modules/ps_checkout/vendor/invertus/infrastructure/tests/phpunit-integration.xml --bootstrap=modules/ps_checkout/vendor/invertus/infrastructure/tests/bootstrap-integration.php"
# make php-unit-integration module_version=ps8
# make php-unit-infrastructure-integration module_version=ps8

php-unit-core:
docker exec -i $${MODULE_VERSION}-ps-prestashop-$${PS_VERSION_TAG} bash -c "php modules/ps_checkout/vendor/bin/phpunit --configuration=modules/ps_checkout/vendor/invertus/core/tests/phpunit.xml --bootstrap=modules/ps_checkout/vendor/invertus/core/tests/bootstrap.php"
# make php-unit-core module_version=ps8

php-unit-presentation:
docker exec -i $${MODULE_VERSION}-ps-prestashop-$${PS_VERSION_TAG} bash -c "php modules/ps_checkout/vendor/bin/phpunit --configuration=modules/ps_checkout/vendor/invertus/presentation/tests/phpunit.xml --bootstrap=modules/ps_checkout/vendor/invertus/presentation/tests/bootstrap.php"
# php-unit-presentation module_version=ps8
# make php-unit-presentation module_version=ps8

php-integration-ps8:
docker exec -i $${MODULE_VERSION}-ps-prestashop-$${PS_VERSION_TAG} bash -c "php modules/ps_checkout/vendor/bin/phpunit --configuration=modules/ps_checkout/tests/phpunit-integration.xml --bootstrap=modules/ps_checkout/tests/bootstrap-integration.php"
Expand Down
20 changes: 20 additions & 0 deletions api/src/Http/CheckoutHttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,26 @@ public function getUserIdToken(string $merchantId, $payPalCustomerId = null): Re
);
}

/**
* {@inheritdoc}
*/
public function getClientToken(string $merchantId, string $domain): ResponseInterface
{
$payload = [
'payer_id' => $merchantId,
'domain' => $domain,
];

return $this->sendRequest(
new Request(
'POST',
self::SUFFIX_IDENTITY . '/oauth2/domain-token',
[],
json_encode($payload)
)
);
}

/**
* {@inheritdoc}
*/
Expand Down
8 changes: 8 additions & 0 deletions api/src/Http/CheckoutHttpClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ interface CheckoutHttpClientInterface
*/
public function getUserIdToken(string $merchantId, $payPalCustomerId = null): ResponseInterface;

/**
* @param string $merchantId
* @param string $domain
*
* @return ResponseInterface
*/
public function getClientToken(string $merchantId, string $domain): ResponseInterface;

/**
* @param string $merchantId
* @param string $vaultId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
use PsCheckout\Infrastructure\Repository\PsAccountRepositoryInterface;
use Psr\Log\LoggerInterface;

class OrderShipmentTrackingConfigurationBuilder implements OrderShipmentTrackingConfigurationBuilderInterface
class OrderShipmentTrackingConfigurationBuilder implements HttpClientConfigurationBuilderInterface
{
const TIMEOUT = 10;

Expand Down
4 changes: 2 additions & 2 deletions api/src/Http/OrderShipmentTrackingHttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@

use GuzzleHttp\Psr7\Request;
use Http\Client\Exception\HttpException;
use PsCheckout\Api\Http\Configuration\OrderShipmentTrackingConfigurationBuilderInterface;
use PsCheckout\Api\Http\Configuration\HttpClientConfigurationBuilderInterface;
use PsCheckout\Api\Http\Exception\PayPalError;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

class OrderShipmentTrackingHttpClient extends PsrHttpClientAdapter implements OrderShipmentTrackingHttpClientInterface
{
public function __construct(OrderShipmentTrackingConfigurationBuilderInterface $configurationBuilder)
public function __construct(HttpClientConfigurationBuilderInterface $configurationBuilder)
{
parent::__construct($configurationBuilder->build());
}
Expand Down
39 changes: 32 additions & 7 deletions core/src/Order/Builder/Node/CardPaymentSourceNodeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ class CardPaymentSourceNodeBuilder implements CardPaymentSourceNodeBuilderInterf
*/
private $savePaymentMethod;

/**
* @var string
*/
private $singleUseToken;

/**
* @var PayPalConfiguration
*/
Expand Down Expand Up @@ -82,14 +87,24 @@ public function build(): array
$countryIso = $this->countryRepository->getCountryIsoCodeById($address->id_country);
$stateName = $this->stateRepository->getNameById($address->id_state);

$node = [
'payment_source' => [
'card' => [
'name' => $this->cart['addresses']['invoice']->firstname . ' ' . $this->cart['addresses']['invoice']->lastname,
'billing_address' => OrderPayloadUtility::getAddressPortable($address, $countryIso, $stateName),
if (!empty($this->singleUseToken)) {
$node = [
'payment_source' => [
'card' => [
'single_use_token' => $this->singleUseToken,
],
],
],
];
];
} else {
$node = [
'payment_source' => [
'card' => [
'name' => $this->cart['addresses']['invoice']->firstname . ' ' . $this->cart['addresses']['invoice']->lastname,
'billing_address' => OrderPayloadUtility::getAddressPortable($address, $countryIso, $stateName),
],
],
];
}

if ($this->paypalConfiguration->is3dSecureEnabled()) {
$node['payment_source']['card']['attributes']['verification']['method'] = $this->paypalConfiguration->getCardFieldsContingencies();
Expand Down Expand Up @@ -154,4 +169,14 @@ public function setSavePaymentMethod(bool $savePaymentMethod): self

return $this;
}

/**
* {@inheritDoc}
*/
public function setSingleUseToken(string $singleUseToken): self
{
$this->singleUseToken = $singleUseToken;

return $this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,11 @@ public function setPaypalCustomerId($paypalCustomerId);
* @return self
*/
public function setSavePaymentMethod(bool $savePaymentMethod);

/**
* @param string $singleUseToken
*
* @return self
*/
public function setSingleUseToken(string $singleUseToken);
}
16 changes: 16 additions & 0 deletions core/src/Order/Builder/OrderPayloadBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class OrderPayloadBuilder implements OrderPayloadBuilderInterface
/** @var bool */
private $isCard = false;

/** @var string */
private $singleUseToken = '';

/** @var array */
private $payload = [];

Expand Down Expand Up @@ -185,6 +188,10 @@ private function buildOptionalPayload(bool $isFullPayload): array
$optionalPayload[] = $this->buildSupplementaryData();
}

if ($this->fundingSource === 'fastlane') {
$optionalPayload[] = $this->buildCardPaymentSource();
}

if ($isFullPayload) {
$optionalPayload[] = $this->buildPaymentSource();
}
Expand All @@ -204,6 +211,7 @@ private function buildCardPaymentSource(): array
->setPaypalVaultId($this->paypalVaultId)
->setPaypalCustomerId($this->paypalCustomerId)
->setSavePaymentMethod($this->savePaymentMethod)
->setSingleUseToken($this->singleUseToken)
->build();
}

Expand Down Expand Up @@ -339,6 +347,14 @@ public function setIsVault(bool $isVault): self
return $this;
}

/** {@inheritDoc} */
public function setSingleUseToken(string $singleUseToken): self
{
$this->singleUseToken = $singleUseToken;

return $this;
}

/** {@inheritDoc} */
public function setIsCard(bool $isCard): self
{
Expand Down
5 changes: 5 additions & 0 deletions core/src/Order/Builder/OrderPayloadBuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,9 @@ public function setIsCard(bool $isCard): OrderPayloadBuilder;
* @param bool $isVault
*/
public function setIsVault(bool $isVault): OrderPayloadBuilder;

/**
* @param string $singleUseToken
*/
public function setSingleUseToken(string $singleUseToken): OrderPayloadBuilder;
}
4 changes: 4 additions & 0 deletions core/src/Order/Validator/OrderAuthorizationValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ public function __construct(
public function validate(int $cartId, PayPalOrderResponse $payPalOrder)
{
if ($payPalOrder->getStatus() === 'COMPLETED') {
if (in_array($payPalOrder->getTransactionStatus(), ['FAILED', 'DECLINED'])) {
throw new PsCheckoutException(sprintf('PayPal Order %s capture has failed or been declined', $payPalOrder->getId()), PsCheckoutException::PAYPAL_PAYMENT_CAPTURE_DECLINED);
}

throw new PsCheckoutException(sprintf('PayPal Order %s is already captured', $payPalOrder->getId()), PsCheckoutException::PAYPAL_ORDER_ALREADY_CAPTURED);
}

Expand Down
27 changes: 27 additions & 0 deletions core/src/PayPal/OAuth/OAuthService.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@

class OAuthService implements OAuthServiceInterface
{
/**
* @var CheckoutHttpClientInterface
*/
private $httpClient;

public function __construct(CheckoutHttpClientInterface $httpClient)
Expand All @@ -51,4 +54,28 @@ public function getUserIdToken(string $merchantId, $payPalCustomerId = null): st
throw new Exception('Failed to get PayPal User ID token.', 0, $exception);
}
}

/**
* {@inheritdoc}
*/
public function getClientToken(string $merchantId, string $domain): string
{
try {
$response = $this->httpClient->getClientToken($merchantId, $domain);

if ($response->getStatusCode() !== 200) {
throw new Exception('Unexpected status code: ' . $response->getStatusCode());
}

$data = json_decode($response->getBody(), true);

if (empty($data['access_token'])) {
throw new Exception('Failed to get PayPal client token from response.');
}

return $data['access_token'];
} catch (Exception $exception) {
throw new Exception('Failed to get PayPal client token.', 0, $exception);
}
}
}
10 changes: 10 additions & 0 deletions core/src/PayPal/OAuth/OAuthServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,14 @@ interface OAuthServiceInterface
* @throws Exception
*/
public function getUserIdToken(string $merchantId, $payPalCustomerId = null): string;

/**
* @param string $merchantId
* @param string $domain
*
* @return string
*
* @throws Exception
*/
public function getClientToken(string $merchantId, string $domain): string;
}
3 changes: 1 addition & 2 deletions core/src/PayPal/Order/Action/CancelPayPalOrderAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,8 @@ public function execute(CancelPayPalOrderRequest $cancelOrderRequest)

$paypalOrder
->setIdCart($cancelOrderRequest->getCartId())
->setPaymentTokenId($cancelOrderRequest->getOrderId()) // Assuming PayPal order ID is a payment token
->setFundingSource($cancelOrderRequest->getFundingSource())
->setIsCardFields($cancelOrderRequest->isHostedFields()) // Assuming "isHostedFields" maps to "isCardFields"
->setIsCardFields($cancelOrderRequest->isHostedFields())
->setIsExpressCheckout($cancelOrderRequest->isExpressCheckout())
->setStatus($cancelOrderRequest->getOrderStatus());

Expand Down
7 changes: 6 additions & 1 deletion core/src/PayPal/Order/Action/CreatePayPalOrderAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,18 @@ public function __construct(
*/
public function execute(int $cartId, CreatePayPalOrderRequest $request): bool
{
$isVault = !empty($request->getSingleUseToken())
? true
: ($request->getVaultId() || $request->isVault());

$this->orderPayloadBuilder
->setCart($this->cartPresenter->present())
->setIsCard($this->isCardPayment($request))
->setIsExpressCheckout($request->isExpressCheckout())
->setFundingSource($request->getFundingSource())
->setSavePaymentMethod($request->isVault())
->setIsVault($request->getVaultId() || $request->isVault());
->setIsVault($isVault)
->setSingleUseToken($request->getSingleUseToken());

if ($request->getVaultId()) {
$this->orderPayloadBuilder->setPaypalVaultId($request->getVaultId());
Expand Down
8 changes: 7 additions & 1 deletion core/src/PayPal/Order/Provider/PayPalOrderProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,13 @@ private function fetchOrder(string $id)
'orderId' => $id,
];

if ($payPalOrder && $payPalOrder->checkCustomerIntent(PayPalOrder::CUSTOMER_INTENT_USES_VAULTING)) {
if (
$payPalOrder &&
(
$payPalOrder->checkCustomerIntent(PayPalOrder::CUSTOMER_INTENT_USES_VAULTING) ||
$payPalOrder->getFundingSource() === 'fastlane'
)
) {
$payload['vault'] = true;
$payload['payee'] = [
'merchant_id' => $this->configuration->get(PayPalConfiguration::PS_CHECKOUT_PAYPAL_ID_MERCHANT),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ class CreatePayPalOrderRequest
*/
private $isExpressCheckout;

/**
* @var string
*/
private $singleUseToken;

/**
* CheckoutCreateRequest constructor.
*
Expand All @@ -89,6 +94,7 @@ public function __construct(array $request)
$this->fundingSource = isset($request['fundingSource']) ? (string) $request['fundingSource'] : 'paypal';
$this->isCardFields = isset($request['isCardFields']) && (bool) $request['isCardFields'];
$this->isExpressCheckout = (bool) $request['isExpressCheckout'];
$this->singleUseToken = isset($request['paymentToken']) ? (string) $request['paymentToken'] : '';
}

/**
Expand Down Expand Up @@ -190,4 +196,12 @@ public function isExpressCheckout(): bool
{
return $this->isExpressCheckout;
}

/**
* @return string
*/
public function getSingleUseToken(): string
{
return $this->singleUseToken;
}
}
1 change: 1 addition & 0 deletions core/src/Settings/Configuration/DefaultConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@ class DefaultConfiguration
'PS_CHECKOUT_DISPLAY_LOGO_CART' => '1',
'PS_CHECKOUT_HOSTED_FIELDS_CONTINGENCIES' => 'SCA_WHEN_REQUIRED',
'PS_CHECKOUT_PAYPAL_BUTTON' => '{"shape":"pill","label":"pay","color":"gold"}',
'PS_CHECKOUT_FASTLANE_ENABLED' => 0,
];
}
30 changes: 30 additions & 0 deletions core/src/Settings/Configuration/PayPalFastlaneConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <[email protected]>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/

namespace PsCheckout\Core\Settings\Configuration;

class PayPalFastlaneConfiguration
{
const PS_CHECKOUT_FASTLANE_ENABLED = 'PS_CHECKOUT_FASTLANE_ENABLED';

const PS_CHECKOUT_FASTLANE_SHIPPING_ADDRESS = 'PS_CHECKOUT_FASTLANE_SHIPPING_ADDRESS_';

const PS_CHECKOUT_FASTLANE_SAVED_SHIPPING_ADDRESS = 'PS_CHECKOUT_FASTLANE_SAVED_SHIPPING_ADDRESS_';
}
Loading