coding standards for api client

This commit is contained in:
David Remer 2020-09-01 09:00:45 +03:00
parent f5bb4048cd
commit 804bf35bbe
157 changed files with 8405 additions and 5283 deletions

View file

@ -1,9 +1,12 @@
<?php
/**
* The extensions of the api client module.
*
* @package Inpsyde\PayPalCommerce\ApiClient
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient;
use Dhii\Data\Container\ContainerInterface;
return [
];
return array();

View file

@ -1,4 +1,10 @@
<?php
/**
* The api client module.
*
* @package Inpsyde\PayPalCommerce\ApiClient
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient;
@ -6,5 +12,5 @@ namespace Inpsyde\PayPalCommerce\ApiClient;
use Dhii\Modular\Module\ModuleInterface;
return function (): ModuleInterface {
return new ApiModule();
return new ApiModule();
};

View file

@ -1,4 +1,9 @@
<?php
/**
* The services of the API client.
*
* @package Inpsyde\PayPalCommerce\ApiClient
*/
declare(strict_types=1);
@ -35,236 +40,235 @@ use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PartnerReferralsData;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
use Inpsyde\PayPalCommerce\Onboarding\Environment;
use Inpsyde\PayPalCommerce\Onboarding\State;
use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings;
use WpOop\TransientCache\CachePoolFactory;
return [
'api.host' => function(ContainerInterface $container) : string {
return 'https://api.paypal.com';
},
'api.paypal-host' => function(ContainerInterface $container) : string {
return 'https://api.paypal.com';
},
'api.partner_merchant_id' => static function () : string {
return '';
},
'api.merchant_email' => function () : string {
return '';
},
'api.merchant_id' => function () : string {
return '';
},
'api.key' => static function (): string {
return '';
},
'api.secret' => static function (): string {
return '';
},
'api.prefix' => static function (): string {
return 'WC-';
},
'api.bearer' => static function (ContainerInterface $container): Bearer {
global $wpdb;
$cacheFactory = new CachePoolFactory($wpdb);
$pool = $cacheFactory->createCachePool('ppcp-token');
$key = $container->get('api.key');
$secret = $container->get('api.secret');
return array(
'api.host' => function( ContainerInterface $container ) : string {
return 'https://api.paypal.com';
},
'api.paypal-host' => function( ContainerInterface $container ) : string {
return 'https://api.paypal.com';
},
'api.partner_merchant_id' => static function () : string {
return '';
},
'api.merchant_email' => function () : string {
return '';
},
'api.merchant_id' => function () : string {
return '';
},
'api.key' => static function (): string {
return '';
},
'api.secret' => static function (): string {
return '';
},
'api.prefix' => static function (): string {
return 'WC-';
},
'api.bearer' => static function ( ContainerInterface $container ): Bearer {
global $wpdb;
$cache_pool_factory = new CachePoolFactory( $wpdb );
$pool = $cache_pool_factory->createCachePool( 'ppcp-token' );
$key = $container->get( 'api.key' );
$secret = $container->get( 'api.secret' );
$host = $container->get('api.host');
$logger = $container->get('woocommerce.logger.woocommerce');
return new PayPalBearer(
$pool,
$host,
$key,
$secret,
$logger
);
},
'api.endpoint.payment-token' => static function (ContainerInterface $container) : PaymentTokenEndpoint {
return new PaymentTokenEndpoint(
$container->get('api.host'),
$container->get('api.bearer'),
$container->get('api.factory.payment-token'),
$container->get('woocommerce.logger.woocommerce'),
$container->get('api.prefix')
);
},
'api.endpoint.webhook' => static function (ContainerInterface $container) : WebhookEndpoint {
$host = $container->get( 'api.host' );
$logger = $container->get( 'woocommerce.logger.woocommerce' );
return new PayPalBearer(
$pool,
$host,
$key,
$secret,
$logger
);
},
'api.endpoint.payment-token' => static function ( ContainerInterface $container ) : PaymentTokenEndpoint {
return new PaymentTokenEndpoint(
$container->get( 'api.host' ),
$container->get( 'api.bearer' ),
$container->get( 'api.factory.payment-token' ),
$container->get( 'woocommerce.logger.woocommerce' ),
$container->get( 'api.prefix' )
);
},
'api.endpoint.webhook' => static function ( ContainerInterface $container ) : WebhookEndpoint {
return new WebhookEndpoint(
$container->get('api.host'),
$container->get('api.bearer'),
$container->get('api.factory.webhook'),
$container->get('woocommerce.logger.woocommerce')
);
},
'api.endpoint.partner-referrals' => static function (ContainerInterface $container) : PartnerReferrals {
return new WebhookEndpoint(
$container->get( 'api.host' ),
$container->get( 'api.bearer' ),
$container->get( 'api.factory.webhook' ),
$container->get( 'woocommerce.logger.woocommerce' )
);
},
'api.endpoint.partner-referrals' => static function ( ContainerInterface $container ) : PartnerReferrals {
return new PartnerReferrals(
$container->get('api.host'),
$container->get('api.bearer'),
$container->get('api.repository.partner-referrals-data'),
$container->get('woocommerce.logger.woocommerce')
);
},
'api.endpoint.identity-token' => static function (ContainerInterface $container) : IdentityToken {
return new PartnerReferrals(
$container->get( 'api.host' ),
$container->get( 'api.bearer' ),
$container->get( 'api.repository.partner-referrals-data' ),
$container->get( 'woocommerce.logger.woocommerce' )
);
},
'api.endpoint.identity-token' => static function ( ContainerInterface $container ) : IdentityToken {
$logger = $container->get('woocommerce.logger.woocommerce');
$prefix = $container->get('api.prefix');
return new IdentityToken(
$container->get('api.host'),
$container->get('api.bearer'),
$logger,
$prefix
);
},
'api.endpoint.payments' => static function (ContainerInterface $container): PaymentsEndpoint {
$authorizationFactory = $container->get('api.factory.authorization');
$logger = $container->get('woocommerce.logger.woocommerce');
$logger = $container->get( 'woocommerce.logger.woocommerce' );
$prefix = $container->get( 'api.prefix' );
return new IdentityToken(
$container->get( 'api.host' ),
$container->get( 'api.bearer' ),
$logger,
$prefix
);
},
'api.endpoint.payments' => static function ( ContainerInterface $container ): PaymentsEndpoint {
$authorizations_factory = $container->get( 'api.factory.authorization' );
$logger = $container->get( 'woocommerce.logger.woocommerce' );
return new PaymentsEndpoint(
$container->get('api.host'),
$container->get('api.bearer'),
$authorizationFactory,
$logger
);
},
'api.endpoint.login-seller' => static function (ContainerInterface $container) : LoginSeller {
return new PaymentsEndpoint(
$container->get( 'api.host' ),
$container->get( 'api.bearer' ),
$authorizations_factory,
$logger
);
},
'api.endpoint.login-seller' => static function ( ContainerInterface $container ) : LoginSeller {
$logger = $container->get('woocommerce.logger.woocommerce');
return new LoginSeller(
$logger = $container->get( 'woocommerce.logger.woocommerce' );
return new LoginSeller(
$container->get( 'api.paypal-host' ),
$container->get( 'api.partner_merchant_id' ),
$logger
);
},
'api.endpoint.order' => static function ( ContainerInterface $container ): OrderEndpoint {
$order_factory = $container->get( 'api.factory.order' );
$patch_collection_factory = $container->get( 'api.factory.patch-collection-factory' );
$logger = $container->get( 'woocommerce.logger.woocommerce' );
$container->get('api.paypal-host'),
$container->get('api.partner_merchant_id'),
$logger
);
},
'api.endpoint.order' => static function (ContainerInterface $container): OrderEndpoint {
$orderFactory = $container->get('api.factory.order');
$patchCollectionFactory = $container->get('api.factory.patch-collection-factory');
$logger = $container->get('woocommerce.logger.woocommerce');
/**
* The settings.
*
* @var Settings $settings
*/
$settings = $container->get( 'wcgateway.settings' );
$intent = $settings->has( 'intent' ) && strtoupper( (string) $settings->get( 'intent' ) ) === 'AUTHORIZE' ? 'AUTHORIZE' : 'CAPTURE';
$application_context_repository = $container->get( 'api.repository.application-context' );
$paypal_request_id = $container->get( 'api.repository.paypal-request-id' );
return new OrderEndpoint(
$container->get( 'api.host' ),
$container->get( 'api.bearer' ),
$order_factory,
$patch_collection_factory,
$intent,
$logger,
$application_context_repository,
$paypal_request_id
);
},
'api.repository.paypal-request-id' => static function( ContainerInterface $container ) : PayPalRequestIdRepository {
return new PayPalRequestIdRepository();
},
'api.repository.application-context' => static function( ContainerInterface $container ) : ApplicationContextRepository {
/**
* @var Settings $settings
*/
$settings = $container->get('wcgateway.settings');
$intent = $settings->has('intent') && strtoupper((string) $settings->get('intent')) === 'AUTHORIZE' ? 'AUTHORIZE' : 'CAPTURE';
$applicationContextRepository = $container->get('api.repository.application-context');
$paypalRequestId = $container->get('api.repository.paypal-request-id');
return new OrderEndpoint(
$container->get('api.host'),
$container->get('api.bearer'),
$orderFactory,
$patchCollectionFactory,
$intent,
$logger,
$applicationContextRepository,
$paypalRequestId
);
},
'api.repository.paypal-request-id' => static function(ContainerInterface $container) : PayPalRequestIdRepository {
return new PayPalRequestIdRepository();
},
'api.repository.application-context' => static function(ContainerInterface $container) : ApplicationContextRepository {
$settings = $container->get( 'wcgateway.settings' );
return new ApplicationContextRepository( $settings );
},
'api.repository.partner-referrals-data' => static function ( ContainerInterface $container ) : PartnerReferralsData {
$settings = $container->get('wcgateway.settings');
return new ApplicationContextRepository($settings);
},
'api.repository.partner-referrals-data' => static function (ContainerInterface $container) : PartnerReferralsData {
$merchant_email = $container->get( 'api.merchant_email' );
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
return new PartnerReferralsData( $merchant_email, $dcc_applies );
},
'api.repository.cart' => static function ( ContainerInterface $container ): CartRepository {
$factory = $container->get( 'api.factory.purchase-unit' );
return new CartRepository( $factory );
},
'api.repository.payee' => static function ( ContainerInterface $container ): PayeeRepository {
$merchant_email = $container->get( 'api.merchant_email' );
$merchant_id = $container->get( 'api.merchant_id' );
return new PayeeRepository( $merchant_email, $merchant_id );
},
'api.factory.application-context' => static function ( ContainerInterface $container ) : ApplicationContextFactory {
return new ApplicationContextFactory();
},
'api.factory.payment-token' => static function ( ContainerInterface $container ) : PaymentTokenFactory {
return new PaymentTokenFactory();
},
'api.factory.webhook' => static function ( ContainerInterface $container ): WebhookFactory {
return new WebhookFactory();
},
'api.factory.purchase-unit' => static function ( ContainerInterface $container ): PurchaseUnitFactory {
$merchantEmail = $container->get('api.merchant_email');
$dccApplies = $container->get('api.helpers.dccapplies');
return new PartnerReferralsData($merchantEmail, $dccApplies);
},
'api.repository.cart' => static function (ContainerInterface $container): CartRepository {
$factory = $container->get('api.factory.purchase-unit');
return new CartRepository($factory);
},
'api.repository.payee' => static function (ContainerInterface $container): PayeeRepository {
$merchantEmail = $container->get('api.merchant_email');
$merchantId = $container->get('api.merchant_id');
return new PayeeRepository($merchantEmail, $merchantId);
},
'api.factory.application-context' => static function (ContainerInterface $container) : ApplicationContextFactory {
return new ApplicationContextFactory();
},
'api.factory.payment-token' => static function (ContainerInterface $container) : PaymentTokenFactory {
return new PaymentTokenFactory();
},
'api.factory.webhook' => static function (ContainerInterface $container): WebhookFactory {
return new WebhookFactory();
},
'api.factory.purchase-unit' => static function (ContainerInterface $container): PurchaseUnitFactory {
$amount_factory = $container->get( 'api.factory.amount' );
$payee_repository = $container->get( 'api.repository.payee' );
$payee_factory = $container->get( 'api.factory.payee' );
$item_factory = $container->get( 'api.factory.item' );
$shipping_factory = $container->get( 'api.factory.shipping' );
$payments_factory = $container->get( 'api.factory.payments' );
$prefix = $container->get( 'api.prefix' );
$amountFactory = $container->get('api.factory.amount');
$payeeRepository = $container->get('api.repository.payee');
$payeeFactory = $container->get('api.factory.payee');
$itemFactory = $container->get('api.factory.item');
$shippingFactory = $container->get('api.factory.shipping');
$paymentsFactory = $container->get('api.factory.payments');
$prefix = $container->get('api.prefix');
return new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory,
$paymentsFactory,
$prefix
);
},
'api.factory.patch-collection-factory' => static function (ContainerInterface $container): PatchCollectionFactory {
return new PatchCollectionFactory();
},
'api.factory.payee' => static function (ContainerInterface $container): PayeeFactory {
return new PayeeFactory();
},
'api.factory.item' => static function (ContainerInterface $container): ItemFactory {
return new ItemFactory();
},
'api.factory.shipping' => static function (ContainerInterface $container): ShippingFactory {
$addressFactory = $container->get('api.factory.address');
return new ShippingFactory($addressFactory);
},
'api.factory.amount' => static function (ContainerInterface $container): AmountFactory {
$itemFactory = $container->get('api.factory.item');
return new AmountFactory($itemFactory);
},
'api.factory.payer' => static function (ContainerInterface $container): PayerFactory {
$addressFactory = $container->get('api.factory.address');
return new PayerFactory($addressFactory);
},
'api.factory.address' => static function (ContainerInterface $container): AddressFactory {
return new AddressFactory();
},
'api.factory.payment-source' => static function (ContainerInterface $container): PaymentSourceFactory {
return new PaymentSourceFactory();
},
'api.factory.order' => static function (ContainerInterface $container): OrderFactory {
$purchaseUnitFactory = $container->get('api.factory.purchase-unit');
$payerFactory = $container->get('api.factory.payer');
$applicationContextRepository = $container->get('api.repository.application-context');
$applicationContextFactory = $container->get('api.factory.application-context');
$paymentSourceFactory = $container->get('api.factory.payment-source');
return new OrderFactory(
$purchaseUnitFactory,
$payerFactory,
$applicationContextRepository,
$applicationContextFactory,
$paymentSourceFactory
);
},
'api.factory.payments' => static function (ContainerInterface $container): PaymentsFactory {
$authorizationFactory = $container->get('api.factory.authorization');
return new PaymentsFactory($authorizationFactory);
},
'api.factory.authorization' => static function (ContainerInterface $container): AuthorizationFactory {
return new AuthorizationFactory();
},
'api.helpers.dccapplies' => static function (ContainerInterface $container) : DccApplies {
return new DccApplies();
},
];
return new PurchaseUnitFactory(
$amount_factory,
$payee_repository,
$payee_factory,
$item_factory,
$shipping_factory,
$payments_factory,
$prefix
);
},
'api.factory.patch-collection-factory' => static function ( ContainerInterface $container ): PatchCollectionFactory {
return new PatchCollectionFactory();
},
'api.factory.payee' => static function ( ContainerInterface $container ): PayeeFactory {
return new PayeeFactory();
},
'api.factory.item' => static function ( ContainerInterface $container ): ItemFactory {
return new ItemFactory();
},
'api.factory.shipping' => static function ( ContainerInterface $container ): ShippingFactory {
$address_factory = $container->get( 'api.factory.address' );
return new ShippingFactory( $address_factory );
},
'api.factory.amount' => static function ( ContainerInterface $container ): AmountFactory {
$item_factory = $container->get( 'api.factory.item' );
return new AmountFactory( $item_factory );
},
'api.factory.payer' => static function ( ContainerInterface $container ): PayerFactory {
$address_factory = $container->get( 'api.factory.address' );
return new PayerFactory( $address_factory );
},
'api.factory.address' => static function ( ContainerInterface $container ): AddressFactory {
return new AddressFactory();
},
'api.factory.payment-source' => static function ( ContainerInterface $container ): PaymentSourceFactory {
return new PaymentSourceFactory();
},
'api.factory.order' => static function ( ContainerInterface $container ): OrderFactory {
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
$payer_factory = $container->get( 'api.factory.payer' );
$application_context_repository = $container->get( 'api.repository.application-context' );
$application_context_factory = $container->get( 'api.factory.application-context' );
$payment_source_factory = $container->get( 'api.factory.payment-source' );
return new OrderFactory(
$purchase_unit_factory,
$payer_factory,
$application_context_repository,
$application_context_factory,
$payment_source_factory
);
},
'api.factory.payments' => static function ( ContainerInterface $container ): PaymentsFactory {
$authorizations_factory = $container->get( 'api.factory.authorization' );
return new PaymentsFactory( $authorizations_factory );
},
'api.factory.authorization' => static function ( ContainerInterface $container ): AuthorizationFactory {
return new AuthorizationFactory();
},
'api.helpers.dccapplies' => static function ( ContainerInterface $container ) : DccApplies {
return new DccApplies();
},
);

View file

@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient;
use Dhii\Container\ServiceProvider;
use Dhii\Modular\Module\Exception\ModuleExceptionInterface;
use Dhii\Modular\Module\ModuleInterface;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
class ApiModule implements ModuleInterface
{
public function setup(): ServiceProviderInterface
{
return new ServiceProvider(
require __DIR__ . '/../services.php',
require __DIR__ . '/../extensions.php'
);
}
public function run(ContainerInterface $container)
{
// TODO: Implement run() method.
}
}

View file

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Authentication;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Token;
interface Bearer
{
public function bearer(): Token;
}

View file

@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Authentication;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Token;
class ConnectBearer implements Bearer
{
public function bearer(): Token
{
$data = (object) [
'created' => time(),
'expires_in' => 3600,
'token' => 'token',
];
return new Token($data);
}
}

View file

@ -1,81 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Authentication;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\RequestTrait;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Token;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface;
class PayPalBearer implements Bearer
{
use RequestTrait;
public const CACHE_KEY = 'ppcp-bearer';
private $cache;
private $host;
private $key;
private $secret;
private $logger;
public function __construct(
CacheInterface $cache,
string $host,
string $key,
string $secret,
LoggerInterface $logger
) {
$this->cache = $cache;
$this->host = $host;
$this->key = $key;
$this->secret = $secret;
$this->logger = $logger;
}
public function bearer(): Token
{
try {
$bearer = Token::fromJson((string) $this->cache->get(self::CACHE_KEY));
return ($bearer->isValid()) ? $bearer : $this->newBearer();
} catch (RuntimeException $error) {
return $this->newBearer();
}
}
private function newBearer(): Token
{
$url = trailingslashit($this->host) . 'v1/oauth2/token?grant_type=client_credentials';
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Basic ' . base64_encode($this->key . ':' . $this->secret),
],
];
$response = $this->request(
$url,
$args
);
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
$error = new RuntimeException(
__('Could not create token.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$token = Token::fromJson($response['body']);
$this->cache->set(self::CACHE_KEY, $token->asJson());
return $token;
}
}

View file

@ -0,0 +1,25 @@
<?php
/**
* The bearer interface.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Authentication
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Authentication;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Token;
/**
* Interface Bearer
*/
interface Bearer {
/**
* Returns the bearer.
*
* @return Token
*/
public function bearer(): Token;
}

View file

@ -0,0 +1,32 @@
<?php
/**
* The connect dummy bearer.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Authentication
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Authentication;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Token;
/**
* Class ConnectBearer
*/
class ConnectBearer implements Bearer {
/**
* Returns the bearer.
*
* @return Token
*/
public function bearer(): Token {
$data = (object) array(
'created' => time(),
'expires_in' => 3600,
'token' => 'token',
);
return new Token( $data );
}
}

View file

@ -0,0 +1,142 @@
<?php
/**
* The PayPal bearer.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Authentication
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Authentication;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\RequestTrait;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Token;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface;
/**
* Class PayPalBearer
*/
class PayPalBearer implements Bearer {
use RequestTrait;
public const CACHE_KEY = 'ppcp-bearer';
/**
* The cache.
*
* @var CacheInterface
*/
private $cache;
/**
* The host.
*
* @var string
*/
private $host;
/**
* The client key.
*
* @var string
*/
private $key;
/**
* The client secret.
*
* @var string
*/
private $secret;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* PayPalBearer constructor.
*
* @param CacheInterface $cache The cache.
* @param string $host The host.
* @param string $key The key.
* @param string $secret The secret.
* @param LoggerInterface $logger The logger.
*/
public function __construct(
CacheInterface $cache,
string $host,
string $key,
string $secret,
LoggerInterface $logger
) {
$this->cache = $cache;
$this->host = $host;
$this->key = $key;
$this->secret = $secret;
$this->logger = $logger;
}
/**
* Returns a bearer token.
*
* @return Token
* @throws \Psr\SimpleCache\InvalidArgumentException When cache is invalid.
* @throws RuntimeException When request fails.
*/
public function bearer(): Token {
try {
$bearer = Token::from_json( (string) $this->cache->get( self::CACHE_KEY ) );
return ( $bearer->is_valid() ) ? $bearer : $this->newBearer();
} catch ( RuntimeException $error ) {
return $this->newBearer();
}
}
/**
* Creates a new bearer token.
*
* @return Token
* @throws \Psr\SimpleCache\InvalidArgumentException When cache is invalid.
* @throws RuntimeException When request fails.
*/
private function newBearer(): Token {
$url = trailingslashit( $this->host ) . 'v1/oauth2/token?grant_type=client_credentials';
$args = array(
'method' => 'POST',
'headers' => array(
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
'Authorization' => 'Basic ' . base64_encode( $this->key . ':' . $this->secret ),
),
);
$response = $this->request(
$url,
$args
);
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
$error = new RuntimeException(
__( 'Could not create token.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$token = Token::from_json( $response['body'] );
$this->cache->set( self::CACHE_KEY, $token->as_json() );
return $token;
}
}

View file

@ -1,88 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Token;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Psr\Log\LoggerInterface;
class IdentityToken
{
use RequestTrait;
private $bearer;
private $host;
private $logger;
private $prefix;
public function __construct(string $host, Bearer $bearer, LoggerInterface $logger, string $prefix)
{
$this->host = $host;
$this->bearer = $bearer;
$this->logger = $logger;
$this->prefix = $prefix;
}
public function generateForCustomer(int $customerId): Token
{
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v1/identity/generate-token';
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
],
];
if ($customerId && defined('PPCP_FLAG_SUBSCRIPTION') && PPCP_FLAG_SUBSCRIPTION) {
$args['body'] = json_encode(['customer_id' => $this->prefix . $customerId]);
}
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__(
'Could not create identity token.',
'woocommerce-paypal-commerce-gateway'
)
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 200) {
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$token = Token::fromJson($response['body']);
return $token;
}
}

View file

@ -1,143 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory;
use Psr\Log\LoggerInterface;
class LoginSeller
{
use RequestTrait;
private $host;
private $partnerMerchantId;
private $logger;
public function __construct(
string $host,
string $partnerMerchantId,
LoggerInterface $logger
) {
$this->host = $host;
$this->partnerMerchantId = $partnerMerchantId;
$this->logger = $logger;
}
public function credentialsFor(
string $sharedId,
string $authCode,
string $sellerNonce
): \stdClass {
$token = $this->generateTokenFor($sharedId, $authCode, $sellerNonce);
$url = trailingslashit($this->host) .
'v1/customer/partners/' . $this->partnerMerchantId .
'/merchant-integrations/credentials/';
$args = [
'method' => 'GET',
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
],
];
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not fetch credentials.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if (! isset($json->client_id) || ! isset($json->client_secret)) {
$error = isset($json->details) ?
new PayPalApiException(
$json,
$statusCode
) : new RuntimeException(
__('Credentials not found.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
return $json;
}
private function generateTokenFor(
string $sharedId,
string $authCode,
string $sellerNonce
): string {
$url = trailingslashit($this->host) . 'v1/oauth2/token/';
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Basic ' . base64_encode($sharedId . ':'),
],
'body' => [
'grant_type' => 'authorization_code',
'code' => $authCode,
'code_verifier' => $sellerNonce,
],
];
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not create token.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if (! isset($json->access_token)) {
$error = isset($json->details) ?
new PayPalApiException(
$json,
$statusCode
) : new RuntimeException(
__('No token found.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
return (string) $json->access_token;
}
}

View file

@ -1,418 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\ApplicationContext;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Payer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentMethod;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentToken;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\ApplicationContextFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PatchCollectionFactory;
use Inpsyde\PayPalCommerce\ApiClient\Helper\ErrorResponse;
use Inpsyde\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
use Psr\Log\LoggerInterface;
//phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
class OrderEndpoint
{
use RequestTrait;
private $host;
private $bearer;
private $orderFactory;
private $patchCollectionFactory;
private $intent;
private $logger;
private $applicationContextRepository;
private $bnCode;
private $payPalRequestIdRepository;
public function __construct(
string $host,
Bearer $bearer,
OrderFactory $orderFactory,
PatchCollectionFactory $patchCollectionFactory,
string $intent,
LoggerInterface $logger,
ApplicationContextRepository $applicationContextRepository,
PayPalRequestIdRepository $payPalRequestIdRepository,
string $bnCode = ''
) {
$this->host = $host;
$this->bearer = $bearer;
$this->orderFactory = $orderFactory;
$this->patchCollectionFactory = $patchCollectionFactory;
$this->intent = $intent;
$this->logger = $logger;
$this->applicationContextRepository = $applicationContextRepository;
$this->bnCode = $bnCode;
$this->payPalRequestIdRepository = $payPalRequestIdRepository;
}
public function withBnCode(string $bnCode): OrderEndpoint
{
$this->bnCode = $bnCode;
return $this;
}
/**
* @param PurchaseUnit[] $items
*/
public function createForPurchaseUnits(
array $items,
Payer $payer = null,
PaymentToken $paymentToken = null,
PaymentMethod $paymentMethod = null,
string $paypalRequestId = ''
): Order {
$containsPhysicalGoods = false;
$items = array_filter(
$items,
//phpcs:ignore Inpsyde.CodeQuality.ArgumentTypeDeclaration.NoArgumentType
static function ($item) use (&$containsPhysicalGoods): bool {
$isPurchaseUnit = is_a($item, PurchaseUnit::class);
if ($isPurchaseUnit && $item->containsPhysicalGoodsItems()) {
$containsPhysicalGoods = true;
}
return $isPurchaseUnit;
}
);
$shippingPreference = $containsPhysicalGoods
? ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE
: ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
$bearer = $this->bearer->bearer();
$data = [
'intent' => $this->intent,
'purchase_units' => array_map(
static function (PurchaseUnit $item): array {
return $item->toArray();
},
$items
),
'application_context' => $this->applicationContextRepository
->currentContext($shippingPreference)->toArray(),
];
if ($payer) {
$data['payer'] = $payer->toArray();
}
if ($paymentToken) {
$data['payment_source']['token'] = $paymentToken->toArray();
}
if ($paymentMethod) {
$data['payment_method'] = $paymentMethod->toArray();
}
$url = trailingslashit($this->host) . 'v2/checkout/orders';
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
],
'body' => json_encode($data),
];
$paypalRequestId = $paypalRequestId ? $paypalRequestId : uniqid('ppcp-', true);
$args['headers']['PayPal-Request-Id'] = $paypalRequestId;
if ($this->bnCode) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bnCode;
}
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not create order.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 201) {
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$order = $this->orderFactory->fromPayPalResponse($json);
$this->payPalRequestIdRepository->setForOrder($order, $paypalRequestId);
return $order;
}
public function capture(Order $order): Order
{
if ($order->status()->is(OrderStatus::COMPLETED)) {
return $order;
}
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v2/checkout/orders/' . $order->id() . '/capture';
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
'PayPal-Request-Id' => $this->payPalRequestIdRepository->getForOrder($order),
],
];
if ($this->bnCode) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bnCode;
}
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not capture order.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 201) {
$error = new PayPalApiException(
$json,
$statusCode
);
// If the order has already been captured, we return the updated order.
if (strpos($response['body'], ErrorResponse::ORDER_ALREADY_CAPTURED) !== false) {
return $this->order($order->id());
}
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$order = $this->orderFactory->fromPayPalResponse($json);
return $order;
}
public function authorize(Order $order): Order
{
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v2/checkout/orders/' . $order->id() . '/authorize';
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
'PayPal-Request-Id' => $this->payPalRequestIdRepository->getForOrder($order),
],
];
if ($this->bnCode) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bnCode;
}
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__(
'Could not authorize order.',
'woocommerce-paypal-commerce-gateway'
)
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 201) {
if (strpos($response['body'], ErrorResponse::ORDER_ALREADY_AUTHORIZED) !== false) {
return $this->order($order->id());
}
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$order = $this->orderFactory->fromPayPalResponse($json);
return $order;
}
public function order(string $id): Order
{
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v2/checkout/orders/' . $id;
$args = [
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'PayPal-Request-Id' => $this->payPalRequestIdRepository->getForOrderId($id),
],
];
if ($this->bnCode) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bnCode;
}
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not retrieve order.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode === 404 || empty($response['body'])) {
$error = new RuntimeException(
__('Could not retrieve order.', 'woocommerce-paypal-commerce-gateway'),
404
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
if ($statusCode !== 200) {
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$order = $this->orderFactory->fromPayPalResponse($json);
return $order;
}
public function patchOrderWith(Order $orderToUpdate, Order $orderToCompare): Order
{
$patches = $this->patchCollectionFactory->fromOrders($orderToUpdate, $orderToCompare);
if (! count($patches->patches())) {
return $orderToUpdate;
}
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v2/checkout/orders/' . $orderToUpdate->id();
$args = [
'method' => 'PATCH',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
'PayPal-Request-Id' => $this->payPalRequestIdRepository->getForOrder(
$orderToUpdate
),
],
'body' => json_encode($patches->toArray()),
];
if ($this->bnCode) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bnCode;
}
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not retrieve order.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 204) {
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$newOrder = $this->order($orderToUpdate->id());
return $newOrder;
}
}

View file

@ -1,104 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PartnerReferralsData;
use Psr\Log\LoggerInterface;
//phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
class PartnerReferrals
{
use RequestTrait;
private $host;
private $bearer;
private $data;
private $logger;
public function __construct(
string $host,
Bearer $bearer,
PartnerReferralsData $data,
LoggerInterface $logger
) {
$this->host = $host;
$this->bearer = $bearer;
$this->data = $data;
$this->logger = $logger;
}
public function signupLink(): string
{
$data = $this->data->data();
$bearer = $this->bearer->bearer();
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
],
'body' => json_encode($data),
];
$url = trailingslashit($this->host) . 'v2/customer/partner-referrals';
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not create referral.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 201) {
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
foreach ($json->links as $link) {
if ($link->rel === 'action_url') {
return (string) $link->href;
}
}
$error = new RuntimeException(
__('Action URL not found.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
}

View file

@ -1,149 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentToken;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory;
use Psr\Log\LoggerInterface;
class PaymentTokenEndpoint
{
use RequestTrait;
private $bearer;
private $host;
private $factory;
private $logger;
private $prefix;
public function __construct(
string $host,
Bearer $bearer,
PaymentTokenFactory $factory,
LoggerInterface $logger,
string $prefix
) {
$this->host = $host;
$this->bearer = $bearer;
$this->factory = $factory;
$this->logger = $logger;
$this->prefix = $prefix;
}
// phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
/**
* @param int $id
* @return PaymentToken[]
*/
public function forUser(int $id): array
{
$bearer = $this->bearer->bearer();
$customerId = $this->prefix . $id;
$url = trailingslashit($this->host) . 'v2/vault/payment-tokens/?customer_id=' . $customerId;
$args = [
'method' => 'GET',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
],
];
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not fetch payment token.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 200) {
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$tokens = [];
foreach ($json->payment_tokens as $tokenValue) {
$tokens[] = $this->factory->fromPayPalResponse($tokenValue);
}
if (empty($tokens)) {
$error = new RuntimeException(
sprintf(
// translators: %d is the customer id.
__('No token stored for customer %d.', 'woocommerce-paypal-commerce-gateway'),
$id
)
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
return $tokens;
}
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
public function deleteToken(PaymentToken $token): bool
{
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v2/vault/payment-tokens/' . $token->id();
$args = [
'method' => 'DELETE',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
],
];
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not delete payment token.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
return wp_remote_retrieve_response_code($response) === 204;
}
}

View file

@ -1,140 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory;
use Psr\Log\LoggerInterface;
class PaymentsEndpoint
{
use RequestTrait;
private $host;
private $bearer;
private $authorizationFactory;
private $logger;
public function __construct(
string $host,
Bearer $bearer,
AuthorizationFactory $authorizationsFactory,
LoggerInterface $logger
) {
$this->host = $host;
$this->bearer = $bearer;
$this->authorizationFactory = $authorizationsFactory;
$this->logger = $logger;
}
public function authorization(string $authorizationId): Authorization
{
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v2/payments/authorizations/' . $authorizationId;
$args = [
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
],
];
$response = $this->request($url, $args);
$json = json_decode($response['body']);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not get authorized payment info.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 200) {
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$authorization = $this->authorizationFactory->fromPayPalRequest($json);
return $authorization;
}
public function capture(string $authorizationId): Authorization
{
$bearer = $this->bearer->bearer();
//phpcs:ignore Inpsyde.CodeQuality.LineLength.TooLong
$url = trailingslashit($this->host) . 'v2/payments/authorizations/' . $authorizationId . '/capture';
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
],
];
$response = $this->request($url, $args);
$json = json_decode($response['body']);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Could not capture authorized payment.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 201) {
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$authorization = $this->authorizationFactory->fromPayPalRequest($json);
return $authorization;
}
}

View file

@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
trait RequestTrait
{
//phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration.NoReturnType
private function request(string $url, array $args)
{
/**
* This filter can be used to alter the request args.
* For example, during testing, the PayPal-Mock-Response header could be
* added here.
*/
$args = apply_filters('ppcp-request-args', $args, $url);
if (! isset($args['headers']['PayPal-Partner-Attribution-Id'])) {
$args['headers']['PayPal-Partner-Attribution-Id'] = 'Woo_PPCP';
}
return wp_remote_get($url, $args);
}
}

View file

@ -1,227 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Webhook;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\WebhookFactory;
use Psr\Log\LoggerInterface;
class WebhookEndpoint
{
use RequestTrait;
private $host;
private $bearer;
private $webhookFactory;
private $logger;
public function __construct(
string $host,
Bearer $bearer,
WebhookFactory $webhookFactory,
LoggerInterface $logger
) {
$this->host = $host;
$this->bearer = $bearer;
$this->webhookFactory = $webhookFactory;
$this->logger = $logger;
}
public function create(Webhook $hook): Webhook
{
/**
* An hook, which has an ID has already been created.
*/
if ($hook->id()) {
return $hook;
}
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v1/notifications/webhooks';
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
],
'body' => json_encode($hook->toArray()),
];
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Not able to create a webhook.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$json = json_decode($response['body']);
$statusCode = (int) wp_remote_retrieve_response_code($response);
if ($statusCode !== 201) {
$error = new PayPalApiException(
$json,
$statusCode
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
$hook = $this->webhookFactory->fromPayPalResponse($json);
return $hook;
}
public function delete(Webhook $hook): bool
{
if (! $hook->id()) {
return false;
}
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v1/notifications/webhooks/' . $hook->id();
$args = [
'method' => 'DELETE',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
],
];
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Not able to delete the webhook.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
[
'args' => $args,
'response' => $response,
]
);
throw $error;
}
return wp_remote_retrieve_response_code($response) === 204;
}
public function verifyEvent(
string $authAlgo,
string $certUrl,
string $transmissionId,
string $transmissionSig,
string $transmissionTime,
string $webhookId,
\stdClass $webhookEvent
): bool {
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v1/notifications/verify-webhook-signature';
$args = [
'method' => 'POST',
'headers' => [
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
],
'body' => json_encode(
[
'transmission_id' => $transmissionId,
'transmission_time' => $transmissionTime,
'cert_url' => $certUrl,
'auth_algo' => $authAlgo,
'transmission_sig' => $transmissionSig,
'webhook_id' => $webhookId,
'webhook_event' => $webhookEvent,
]
),
];
$response = $this->request($url, $args);
if (is_wp_error($response)) {
$error = new RuntimeException(
__('Not able to verify webhook event.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log(
'warning',
$error->getMessage(),
['args' => $args, 'response' => $response]
);
throw $error;
}
$json = json_decode($response['body']);
return isset($json->verification_status) && $json->verification_status === "SUCCESS";
}
public function verifyCurrentRequestForWebhook(Webhook $webhook): bool
{
if (! $webhook->id()) {
$error = new RuntimeException(
__('Not a valid webhook to verify.', 'woocommerce-paypal-commerce-gateway')
);
$this->logger->log('warning', $error->getMessage(), ['webhook' => $webhook]);
throw $error;
}
$expectedHeaders = [
'PAYPAL-AUTH-ALGO' => '',
'PAYPAL-CERT-URL' => '',
'PAYPAL-TRANSMISSION-ID' => '',
'PAYPAL-TRANSMISSION-SIG' => '',
'PAYPAL-TRANSMISSION-TIME' => '',
];
$headers = getallheaders();
foreach ($headers as $key => $header) {
$key = strtoupper($key);
if (isset($expectedHeaders[$key])) {
$expectedHeaders[$key] = $header;
}
};
foreach ($expectedHeaders as $key => $value) {
if (! empty($value)) {
continue;
}
$error = new RuntimeException(
sprintf(
// translators: %s is the headers key.
__(
'Not a valid webhook event. Header %s is missing',
'woocommerce-paypal-commerce-gateway'
),
$key
)
);
$this->logger->log('warning', $error->getMessage(), ['webhook' => $webhook]);
throw $error;
}
$requestBody = json_decode(file_get_contents("php://input"));
return $this->verifyEvent(
$expectedHeaders['PAYPAL-AUTH-ALGO'],
$expectedHeaders['PAYPAL-CERT-URL'],
$expectedHeaders['PAYPAL-TRANSMISSION-ID'],
$expectedHeaders['PAYPAL-TRANSMISSION-SIG'],
$expectedHeaders['PAYPAL-TRANSMISSION-TIME'],
$webhook->id(),
$requestBody ? $requestBody : new \stdClass()
);
}
}

View file

@ -0,0 +1,133 @@
<?php
/**
* Fetches identity tokens.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Endpoint
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Token;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Psr\Log\LoggerInterface;
/**
* Class IdentityToken
*/
class IdentityToken {
use RequestTrait;
/**
* The Bearer.
*
* @var Bearer
*/
private $bearer;
/**
* The host.
*
* @var string
*/
private $host;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* The prefix.
*
* @var string
*/
private $prefix;
/**
* IdentityToken constructor.
*
* @param string $host The host.
* @param Bearer $bearer The bearer.
* @param LoggerInterface $logger The logger.
* @param string $prefix The prefix.
*/
public function __construct( string $host, Bearer $bearer, LoggerInterface $logger, string $prefix ) {
$this->host = $host;
$this->bearer = $bearer;
$this->logger = $logger;
$this->prefix = $prefix;
}
/**
* Generates a token for a specific customer.
*
* @param int $customer_id The id of the customer.
*
* @return Token
* @throws RuntimeException If the request fails.
*/
public function generate_for_customer( int $customer_id ): Token {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v1/identity/generate-token';
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
),
);
if ( $customer_id && defined( 'PPCP_FLAG_SUBSCRIPTION' ) && PPCP_FLAG_SUBSCRIPTION ) {
$args['body'] = wp_json_encode( array( 'customer_id' => $this->prefix . $customer_id ) );
}
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__(
'Could not create identity token.',
'woocommerce-paypal-commerce-gateway'
)
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$token = Token::from_json( $response['body'] );
return $token;
}
}

View file

@ -0,0 +1,196 @@
<?php
/**
* Fetches credentials for an instance.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Endpoint
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Psr\Log\LoggerInterface;
/**
* Class LoginSeller
*/
class LoginSeller {
use RequestTrait;
/**
* The host.
*
* @var string
*/
private $host;
/**
* The partner merchant id.
*
* @var string
*/
private $partner_merchant_id;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* LoginSeller constructor.
*
* @param string $host The host.
* @param string $partner_marchant_id The partner merchant id.
* @param LoggerInterface $logger The logger.
*/
public function __construct(
string $host,
string $partner_marchant_id,
LoggerInterface $logger
) {
$this->host = $host;
$this->partner_merchant_id = $partner_marchant_id;
$this->logger = $logger;
}
/**
* Fetches credentials for a shared id, auth code and seller nonce.
*
* @param string $shared_id The shared id.
* @param string $auth_code The auth code.
* @param string $seller_nonce The seller nonce.
*
* @return \stdClass
* @throws RuntimeException If the request fails.
*/
public function credentials_for(
string $shared_id,
string $auth_code,
string $seller_nonce
): \stdClass {
$token = $this->generate_token_for( $shared_id, $auth_code, $seller_nonce );
$url = trailingslashit( $this->host ) .
'v1/customer/partners/' . $this->partner_merchant_id .
'/merchant-integrations/credentials/';
$args = array(
'method' => 'GET',
'headers' => array(
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not fetch credentials.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( ! isset( $json->client_id ) || ! isset( $json->client_secret ) ) {
$error = isset( $json->details ) ?
new PayPalApiException(
$json,
$status_code
) : new RuntimeException(
__( 'Credentials not found.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
return $json;
}
/**
* Generates a token for a shared id and auth token and seller nonce.
*
* @param string $shared_id The shared id.
* @param string $auth_code The auth code.
* @param string $seller_nonce The seller nonce.
*
* @return string
* @throws RuntimeException If the request fails.
*/
private function generate_token_for(
string $shared_id,
string $auth_code,
string $seller_nonce
): string {
$url = trailingslashit( $this->host ) . 'v1/oauth2/token/';
$args = array(
'method' => 'POST',
'headers' => array(
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
'Authorization' => 'Basic ' . base64_encode( $shared_id . ':' ),
),
'body' => array(
'grant_type' => 'authorization_code',
'code' => $auth_code,
'code_verifier' => $seller_nonce,
),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not create token.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( ! isset( $json->access_token ) ) {
$error = isset( $json->details ) ?
new PayPalApiException(
$json,
$status_code
) : new RuntimeException(
__( 'No token found.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
return (string) $json->access_token;
}
}

View file

@ -0,0 +1,538 @@
<?php
/**
* The order endpoint.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Endpoint
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\ApplicationContext;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Payer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentMethod;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentToken;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PatchCollectionFactory;
use Inpsyde\PayPalCommerce\ApiClient\Helper\ErrorResponse;
use Inpsyde\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
use Psr\Log\LoggerInterface;
/**
* Class OrderEndpoint
*/
class OrderEndpoint {
use RequestTrait;
/**
* The host.
*
* @var string
*/
private $host;
/**
* The bearer.
*
* @var Bearer
*/
private $bearer;
/**
* The order factory.
*
* @var OrderFactory
*/
private $order_factory;
/**
* The patch collection factory.
*
* @var PatchCollectionFactory
*/
private $patch_collection_factory;
/**
* The intent.
*
* @var string
*/
private $intent;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* The application context repository.
*
* @var ApplicationContextRepository
*/
private $application_context_repository;
/**
* The BN Code.
*
* @var string
*/
private $bn_code;
/**
* The paypal request id repository.
*
* @var PayPalRequestIdRepository
*/
private $paypal_request_id_repository;
/**
* OrderEndpoint constructor.
*
* @param string $host The host.
* @param Bearer $bearer The bearer.
* @param OrderFactory $order_factory The order factory.
* @param PatchCollectionFactory $patch_collection_factory The patch collection factory.
* @param string $intent The intent.
* @param LoggerInterface $logger The logger.
* @param ApplicationContextRepository $application_context_repository The application context repository.
* @param PayPalRequestIdRepository $paypal_request_id_repository The paypal request id repository.
* @param string $bn_code The BN Code.
*/
public function __construct(
string $host,
Bearer $bearer,
OrderFactory $order_factory,
PatchCollectionFactory $patch_collection_factory,
string $intent,
LoggerInterface $logger,
ApplicationContextRepository $application_context_repository,
PayPalRequestIdRepository $paypal_request_id_repository,
string $bn_code = ''
) {
$this->host = $host;
$this->bearer = $bearer;
$this->order_factory = $order_factory;
$this->patch_collection_factory = $patch_collection_factory;
$this->intent = $intent;
$this->logger = $logger;
$this->application_context_repository = $application_context_repository;
$this->bn_code = $bn_code;
$this->paypal_request_id_repository = $paypal_request_id_repository;
}
/**
* Changes the used BN Code.
*
* @param string $bn_code The new BN Code to use.
*
* @return OrderEndpoint
* @throws RuntimeException If the request fails.
*/
public function with_bn_code( string $bn_code ): OrderEndpoint {
$this->bn_code = $bn_code;
return $this;
}
/**
* Creates an order.
*
* @param PurchaseUnit[] $items The purchase unit items for the order.
* @param Payer|null $payer The payer off the order.
* @param PaymentToken|null $payment_token The payment token.
* @param PaymentMethod|null $payment_method The payment method.
* @param string $paypal_request_id The paypal request id.
*
* @return Order
* @throws RuntimeException If the request fails.
*/
public function create(
array $items,
Payer $payer = null,
PaymentToken $payment_token = null,
PaymentMethod $payment_method = null,
string $paypal_request_id = ''
): Order {
$contains_physical_goods = false;
$items = array_filter(
$items,
static function ( $item ) use ( &$contains_physical_goods ): bool {
$is_purchase_unit = is_a( $item, PurchaseUnit::class );
/**
* A purchase unit.
*
* @var PurchaseUnit $item
*/
if ( $is_purchase_unit && $item->contains_physical_goods() ) {
$contains_physical_goods = true;
}
return $is_purchase_unit;
}
);
$shipping_preferences = $contains_physical_goods
? ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE
: ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
$bearer = $this->bearer->bearer();
$data = array(
'intent' => $this->intent,
'purchase_units' => array_map(
static function ( PurchaseUnit $item ): array {
return $item->to_array();
},
$items
),
'application_context' => $this->application_context_repository
->current_context( $shipping_preferences )->to_array(),
);
if ( $payer ) {
$data['payer'] = $payer->to_array();
}
if ( $payment_token ) {
$data['payment_source']['token'] = $payment_token->to_array();
}
if ( $payment_method ) {
$data['payment_method'] = $payment_method->to_array();
}
$url = trailingslashit( $this->host ) . 'v2/checkout/orders';
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
),
'body' => wp_json_encode( $data ),
);
$paypal_request_id = $paypal_request_id ? $paypal_request_id : uniqid( 'ppcp-', true );
$args['headers']['PayPal-Request-Id'] = $paypal_request_id;
if ( $this->bn_code ) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bn_code;
}
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not create order.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 201 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$order = $this->order_factory->from_paypal_response( $json );
$this->paypal_request_id_repository->set_for_order( $order, $paypal_request_id );
return $order;
}
/**
* Captures an order.
*
* @param Order $order The order.
*
* @return Order
* @throws RuntimeException If the request fails.
*/
public function capture( Order $order ): Order {
if ( $order->status()->is( OrderStatus::COMPLETED ) ) {
return $order;
}
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $order->id() . '/capture';
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
'PayPal-Request-Id' => $this->paypal_request_id_repository->get_for_order( $order ),
),
);
if ( $this->bn_code ) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bn_code;
}
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not capture order.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 201 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
// If the order has already been captured, we return the updated order.
if ( strpos( $response['body'], ErrorResponse::ORDER_ALREADY_CAPTURED ) !== false ) {
return $this->order( $order->id() );
}
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$order = $this->order_factory->from_paypal_response( $json );
return $order;
}
/**
* Authorize an order.
*
* @param Order $order The order.
*
* @return Order
* @throws RuntimeException If the request fails.
*/
public function authorize( Order $order ): Order {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $order->id() . '/authorize';
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
'PayPal-Request-Id' => $this->paypal_request_id_repository->get_for_order( $order ),
),
);
if ( $this->bn_code ) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bn_code;
}
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__(
'Could not authorize order.',
'woocommerce-paypal-commerce-gateway'
)
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 201 !== $status_code ) {
if ( false !== strpos( $response['body'], ErrorResponse::ORDER_ALREADY_AUTHORIZED ) ) {
return $this->order( $order->id() );
}
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$order = $this->order_factory->from_paypal_response( $json );
return $order;
}
/**
* Fetches an order for a given ID.
*
* @param string $id The ID.
*
* @return Order
* @throws RuntimeException If the request fails.
*/
public function order( string $id ): Order {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id;
$args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'PayPal-Request-Id' => $this->paypal_request_id_repository->get_for_order_id( $id ),
),
);
if ( $this->bn_code ) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bn_code;
}
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not retrieve order.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 404 === $status_code || empty( $response['body'] ) ) {
$error = new RuntimeException(
__( 'Could not retrieve order.', 'woocommerce-paypal-commerce-gateway' ),
404
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
if ( 200 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$order = $this->order_factory->from_paypal_response( $json );
return $order;
}
/**
* Patches an order.
*
* @param Order $order_to_update The order to patch.
* @param Order $order_to_compare The target order.
*
* @return Order
* @throws RuntimeException If the request fails.
*/
public function patch_order_with( Order $order_to_update, Order $order_to_compare ): Order {
$patches = $this->patch_collection_factory->from_orders( $order_to_update, $order_to_compare );
if ( ! count( $patches->patches() ) ) {
return $order_to_update;
}
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $order_to_update->id();
$args = array(
'method' => 'PATCH',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
'PayPal-Request-Id' => $this->paypal_request_id_repository->get_for_order(
$order_to_update
),
),
'body' => wp_json_encode( $patches->to_array() ),
);
if ( $this->bn_code ) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bn_code;
}
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not retrieve order.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 204 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$new_order = $this->order( $order_to_update->id() );
return $new_order;
}
}

View file

@ -0,0 +1,146 @@
<?php
/**
* The partner referrals endpoint.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Endpoint
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PartnerReferralsData;
use Psr\Log\LoggerInterface;
/**
* Class PartnerReferrals
*/
class PartnerReferrals {
use RequestTrait;
/**
* The host.
*
* @var string
*/
private $host;
/**
* The bearer.
*
* @var Bearer
*/
private $bearer;
/**
* The PartnerReferralsData.
*
* @var PartnerReferralsData
*/
private $data;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* PartnerReferrals constructor.
*
* @param string $host The host.
* @param Bearer $bearer The bearer.
* @param PartnerReferralsData $data The partner referrals data.
* @param LoggerInterface $logger The logger.
*/
public function __construct(
string $host,
Bearer $bearer,
PartnerReferralsData $data,
LoggerInterface $logger
) {
$this->host = $host;
$this->bearer = $bearer;
$this->data = $data;
$this->logger = $logger;
}
/**
* Fetch the signup link.
*
* @return string
* @throws RuntimeException If the request fails.
*/
public function signup_link(): string {
$data = $this->data->data();
$bearer = $this->bearer->bearer();
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
),
'body' => wp_json_encode( $data ),
);
$url = trailingslashit( $this->host ) . 'v2/customer/partner-referrals';
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not create referral.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 201 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
foreach ( $json->links as $link ) {
if ( 'action_url' === $link->rel ) {
return (string) $link->href;
}
}
$error = new RuntimeException(
__( 'Action URL not found.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
}

View file

@ -0,0 +1,191 @@
<?php
/**
* The payments endpoint.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Endpoint
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
use Psr\Log\LoggerInterface;
/**
* Class PaymentsEndpoint
*/
class PaymentsEndpoint {
use RequestTrait;
/**
* The host.
*
* @var string
*/
private $host;
/**
* The bearer.
*
* @var Bearer
*/
private $bearer;
/**
* The authorization factory.
*
* @var AuthorizationFactory
*/
private $authorizations_factory;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* PaymentsEndpoint constructor.
*
* @param string $host The host.
* @param Bearer $bearer The bearer.
* @param AuthorizationFactory $authorization_factory The authorization factory.
* @param LoggerInterface $logger The logger.
*/
public function __construct(
string $host,
Bearer $bearer,
AuthorizationFactory $authorization_factory,
LoggerInterface $logger
) {
$this->host = $host;
$this->bearer = $bearer;
$this->authorizations_factory = $authorization_factory;
$this->logger = $logger;
}
/**
* Fetch an authorization by a given id.
*
* @param string $authorization_id The id.
*
* @return Authorization
* @throws RuntimeException If the request fails.
*/
public function authorization( string $authorization_id ): Authorization {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/payments/authorizations/' . $authorization_id;
$args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
),
);
$response = $this->request( $url, $args );
$json = json_decode( $response['body'] );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not get authorized payment info.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$authorization = $this->authorizations_factory->from_paypal_response( $json );
return $authorization;
}
/**
* Capture an authorization by a given ID.
*
* @param string $authorization_id The id.
*
* @return Authorization
* @throws RuntimeException If the request fails.
*/
public function capture( string $authorization_id ): Authorization {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/payments/authorizations/' . $authorization_id . '/capture';
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
),
);
$response = $this->request( $url, $args );
$json = json_decode( $response['body'] );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not capture authorized payment.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 201 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$authorization = $this->authorizations_factory->from_paypal_response( $json );
return $authorization;
}
}

View file

@ -0,0 +1,203 @@
<?php
/**
* The payment token endpoint.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Endpoint
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentToken;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory;
use Psr\Log\LoggerInterface;
/**
* Class PaymentTokenEndpoint
*/
class PaymentTokenEndpoint {
use RequestTrait;
/**
* The bearer.
*
* @var Bearer
*/
private $bearer;
/**
* The host.
*
* @var string
*/
private $host;
/**
* The payment token factory.
*
* @var PaymentTokenFactory
*/
private $factory;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* The prefix.
*
* @var string
*/
private $prefix;
/**
* PaymentTokenEndpoint constructor.
*
* @param string $host The host.
* @param Bearer $bearer The bearer.
* @param PaymentTokenFactory $factory The payment token factory.
* @param LoggerInterface $logger The logger.
* @param string $prefix The prefix.
*/
public function __construct(
string $host,
Bearer $bearer,
PaymentTokenFactory $factory,
LoggerInterface $logger,
string $prefix
) {
$this->host = $host;
$this->bearer = $bearer;
$this->factory = $factory;
$this->logger = $logger;
$this->prefix = $prefix;
}
/**
* Returns the payment tokens for a user.
*
* @param int $id The user id.
*
* @return PaymentToken[]
* @throws RuntimeException If the request fails.
*/
public function for_user( int $id ): array {
$bearer = $this->bearer->bearer();
$customer_id = $this->prefix . $id;
$url = trailingslashit( $this->host ) . 'v2/vault/payment-tokens/?customer_id=' . $customer_id;
$args = array(
'method' => 'GET',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not fetch payment token.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$tokens = array();
foreach ( $json->payment_tokens as $token_value ) {
$tokens[] = $this->factory->from_paypal_response( $token_value );
}
if ( empty( $tokens ) ) {
$error = new RuntimeException(
sprintf(
// translators: %d is the customer id.
__( 'No token stored for customer %d.', 'woocommerce-paypal-commerce-gateway' ),
$id
)
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
return $tokens;
}
/**
* Deletes a payment token.
*
* @param PaymentToken $token The token to delete.
*
* @return bool
* @throws RuntimeException If the request fails.
*/
public function delete_token( PaymentToken $token ): bool {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/vault/payment-tokens/' . $token->id();
$args = array(
'method' => 'DELETE',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not delete payment token.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
return wp_remote_retrieve_response_code( $response ) === 204;
}
}

View file

@ -0,0 +1,39 @@
<?php
/**
* The RequestTrait wraps the wp_remote_get functionality for the API client.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Endpoint
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
/**
* Trait RequestTrait
*/
trait RequestTrait {
/**
* Performs a request
*
* @param string $url The URL to request.
* @param array $args The arguments by which to request.
*
* @return array|\WP_Error
*/
private function request( string $url, array $args ) {
/**
* This filter can be used to alter the request args.
* For example, during testing, the PayPal-Mock-Response header could be
* added here.
*/
$args = apply_filters( 'ppcp_request_args', $args, $url );
if ( ! isset( $args['headers']['PayPal-Partner-Attribution-Id'] ) ) {
$args['headers']['PayPal-Partner-Attribution-Id'] = 'Woo_PPCP';
}
return wp_remote_get( $url, $args );
}
}

View file

@ -0,0 +1,305 @@
<?php
/**
* The webhook endpoint.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Endpoint
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Webhook;
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\WebhookFactory;
use Psr\Log\LoggerInterface;
/**
* Class WebhookEndpoint
*/
class WebhookEndpoint {
use RequestTrait;
/**
* The host.
*
* @var string
*/
private $host;
/**
* The bearer.
*
* @var Bearer
*/
private $bearer;
/**
* The webhook factory.
*
* @var WebhookFactory
*/
private $webhook_factory;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* WebhookEndpoint constructor.
*
* @param string $host The host.
* @param Bearer $bearer The bearer.
* @param WebhookFactory $webhook_factory The webhook factory.
* @param LoggerInterface $logger The logger.
*/
public function __construct(
string $host,
Bearer $bearer,
WebhookFactory $webhook_factory,
LoggerInterface $logger
) {
$this->host = $host;
$this->bearer = $bearer;
$this->webhook_factory = $webhook_factory;
$this->logger = $logger;
}
/**
* Creates a webhook with PayPal.
*
* @param Webhook $hook The webhook to create.
*
* @return Webhook
* @throws RuntimeException If the request fails.
*/
public function create( Webhook $hook ): Webhook {
/**
* An hook, which has an ID has already been created.
*/
if ( $hook->id() ) {
return $hook;
}
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v1/notifications/webhooks';
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
),
'body' => wp_json_encode( $hook->to_array() ),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Not able to create a webhook.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 201 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$hook = $this->webhook_factory->from_paypal_response( $json );
return $hook;
}
/**
* Deletes a webhook.
*
* @param Webhook $hook The webhook to delete.
*
* @return bool
* @throws RuntimeException If the request fails.
*/
public function delete( Webhook $hook ): bool {
if ( ! $hook->id() ) {
return false;
}
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v1/notifications/webhooks/' . $hook->id();
$args = array(
'method' => 'DELETE',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Not able to delete the webhook.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
return wp_remote_retrieve_response_code( $response ) === 204;
}
/**
* Verifies if a webhook event is legitimate.
*
* @param string $auth_algo The auth algo.
* @param string $cert_url The cert URL.
* @param string $transmission_id The transmission id.
* @param string $transmission_sig The transmission signature.
* @param string $transmission_time The transmission time.
* @param string $webhook_id The webhook id.
* @param \stdClass $webhook_event The webhook event.
*
* @return bool
* @throws RuntimeException If the request fails.
*/
public function verify_event(
string $auth_algo,
string $cert_url,
string $transmission_id,
string $transmission_sig,
string $transmission_time,
string $webhook_id,
\stdClass $webhook_event
): bool {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v1/notifications/verify-webhook-signature';
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
),
'body' => wp_json_encode(
array(
'transmission_id' => $transmission_id,
'transmission_time' => $transmission_time,
'cert_url' => $cert_url,
'auth_algo' => $auth_algo,
'transmission_sig' => $transmission_sig,
'webhook_id' => $webhook_id,
'webhook_event' => $webhook_event,
)
),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Not able to verify webhook event.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
return isset( $json->verification_status ) && 'SUCCESS' === $json->verification_status;
}
/**
* Verifies if the current request is a legit webhook event.
*
* @param Webhook $webhook The webhook.
*
* @return bool
* @throws RuntimeException If the request fails.
*/
public function verify_current_request_for_webhook( Webhook $webhook ): bool {
if ( ! $webhook->id() ) {
$error = new RuntimeException(
__( 'Not a valid webhook to verify.', 'woocommerce-paypal-commerce-gateway' )
);
$this->logger->log( 'warning', $error->getMessage(), array( 'webhook' => $webhook ) );
throw $error;
}
$expected_headers = array(
'PAYPAL-AUTH-ALGO' => '',
'PAYPAL-CERT-URL' => '',
'PAYPAL-TRANSMISSION-ID' => '',
'PAYPAL-TRANSMISSION-SIG' => '',
'PAYPAL-TRANSMISSION-TIME' => '',
);
$headers = getallheaders();
foreach ( $headers as $key => $header ) {
$key = strtoupper( $key );
if ( isset( $expected_headers[ $key ] ) ) {
$expected_headers[ $key ] = $header;
}
};
foreach ( $expected_headers as $key => $value ) {
if ( ! empty( $value ) ) {
continue;
}
$error = new RuntimeException(
sprintf(
// translators: %s is the headers key.
__(
'Not a valid webhook event. Header %s is missing',
'woocommerce-paypal-commerce-gateway'
),
$key
)
);
$this->logger->log( 'warning', $error->getMessage(), array( 'webhook' => $webhook ) );
throw $error;
}
$request_body = json_decode( file_get_contents( 'php://input' ) );
return $this->verify_event(
$expected_headers['PAYPAL-AUTH-ALGO'],
$expected_headers['PAYPAL-CERT-URL'],
$expected_headers['PAYPAL-TRANSMISSION-ID'],
$expected_headers['PAYPAL-TRANSMISSION-SIG'],
$expected_headers['PAYPAL-TRANSMISSION-TIME'],
$webhook->id(),
$request_body ? $request_body : new \stdClass()
);
}
}

View file

@ -1,73 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Address
{
private $countryCode;
private $addressLine1;
private $addressLine2;
private $adminArea1;
private $adminArea2;
private $postalCode;
public function __construct(
string $countryCode,
string $addressLine1 = '',
string $addressLine2 = '',
string $adminArea1 = '',
string $adminArea2 = '',
string $postalCode = ''
) {
$this->countryCode = $countryCode;
$this->addressLine1 = $addressLine1;
$this->addressLine2 = $addressLine2;
$this->adminArea1 = $adminArea1;
$this->adminArea2 = $adminArea2;
$this->postalCode = $postalCode;
}
public function countryCode(): string
{
return $this->countryCode;
}
public function addressLine1(): string
{
return $this->addressLine1;
}
public function addressLine2(): string
{
return $this->addressLine2;
}
public function adminArea1(): string
{
return $this->adminArea1;
}
public function adminArea2(): string
{
return $this->adminArea2;
}
public function postalCode(): string
{
return $this->postalCode;
}
public function toArray(): array
{
return [
'country_code' => $this->countryCode(),
'address_line_1' => $this->addressLine1(),
'address_line_2' => $this->addressLine2(),
'admin_area_1' => $this->adminArea1(),
'admin_area_2' => $this->adminArea2(),
'postal_code' => $this->postalCode(),
];
}
}

View file

@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Amount
{
private $money;
private $breakdown;
public function __construct(Money $money, AmountBreakdown $breakdown = null)
{
$this->money = $money;
$this->breakdown = $breakdown;
}
public function currencyCode(): string
{
return $this->money->currencyCode();
}
public function value(): float
{
return $this->money->value();
}
public function breakdown(): ?AmountBreakdown
{
return $this->breakdown;
}
public function toArray(): array
{
$amount = [
'currency_code' => $this->currencyCode(),
'value' => $this->value(),
];
if ($this->breakdown() && count($this->breakdown()->toArray())) {
$amount['breakdown'] = $this->breakdown()->toArray();
}
return $amount;
}
}

View file

@ -1,98 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class AmountBreakdown
{
private $itemTotal;
private $shipping;
private $taxTotal;
private $handling;
private $insurance;
private $shippingDiscount;
private $discount;
public function __construct(
Money $itemTotal = null,
Money $shipping = null,
Money $taxTotal = null,
Money $handling = null,
Money $insurance = null,
Money $shippingDiscount = null,
Money $discount = null
) {
$this->itemTotal = $itemTotal;
$this->shipping = $shipping;
$this->taxTotal = $taxTotal;
$this->handling = $handling;
$this->insurance = $insurance;
$this->shippingDiscount = $shippingDiscount;
$this->discount = $discount;
}
public function itemTotal(): ?Money
{
return $this->itemTotal;
}
public function shipping(): ?Money
{
return $this->shipping;
}
public function taxTotal(): ?Money
{
return $this->taxTotal;
}
public function handling(): ?Money
{
return $this->handling;
}
public function insurance(): ?Money
{
return $this->insurance;
}
public function shippingDiscount(): ?Money
{
return $this->shippingDiscount;
}
public function discount(): ?Money
{
return $this->discount;
}
public function toArray(): array
{
$breakdown = [];
if ($this->itemTotal) {
$breakdown['item_total'] = $this->itemTotal->toArray();
}
if ($this->shipping) {
$breakdown['shipping'] = $this->shipping->toArray();
}
if ($this->taxTotal) {
$breakdown['tax_total'] = $this->taxTotal->toArray();
}
if ($this->handling) {
$breakdown['handling'] = $this->handling->toArray();
}
if ($this->insurance) {
$breakdown['insurance'] = $this->insurance->toArray();
}
if ($this->shippingDiscount) {
$breakdown['shipping_discount'] = $this->shippingDiscount->toArray();
}
if ($this->discount) {
$breakdown['discount'] = $this->discount->toArray();
}
return $breakdown;
}
}

View file

@ -1,154 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class ApplicationContext
{
public const LANDING_PAGE_LOGIN = 'LOGIN';
public const LANDING_PAGE_BILLING = 'BILLING';
public const LANDING_PAGE_NO_PREFERENCE = 'NO_PREFERENCE';
private const VALID_LANDING_PAGE_VALUES = [
self::LANDING_PAGE_LOGIN,
self::LANDING_PAGE_BILLING,
self::LANDING_PAGE_NO_PREFERENCE,
];
public const SHIPPING_PREFERENCE_GET_FROM_FILE = 'GET_FROM_FILE';
public const SHIPPING_PREFERENCE_NO_SHIPPING = 'NO_SHIPPING';
public const SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS = 'SET_PROVIDED_ADDRESS';
private const VALID_SHIPPING_PREFERENCE_VALUES = [
self::SHIPPING_PREFERENCE_GET_FROM_FILE,
self::SHIPPING_PREFERENCE_NO_SHIPPING,
self::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
];
public const USER_ACTION_CONTINUE = 'CONTINUE';
public const USER_ACTION_PAY_NOW = 'PAY_NOW';
private const VALID_USER_ACTION_VALUES = [
self::USER_ACTION_CONTINUE,
self::USER_ACTION_PAY_NOW,
];
private $brandName;
private $locale;
private $landingPage;
private $shippingPreference;
private $userAction;
private $returnUrl;
private $cancelUrl;
private $paymentMethod;
public function __construct(
string $returnUrl = '',
string $cancelUrl = '',
string $brandName = '',
string $locale = '',
string $landingPage = self::LANDING_PAGE_NO_PREFERENCE,
string $shippingPreference = self::SHIPPING_PREFERENCE_NO_SHIPPING,
string $userAction = self::USER_ACTION_CONTINUE
) {
if (! in_array($landingPage, self::VALID_LANDING_PAGE_VALUES, true)) {
throw new RuntimeException("Landingpage not correct");
}
if (! in_array($shippingPreference, self::VALID_SHIPPING_PREFERENCE_VALUES, true)) {
throw new RuntimeException("Shipping preference not correct");
}
if (! in_array($userAction, self::VALID_USER_ACTION_VALUES, true)) {
throw new RuntimeException("User action preference not correct");
}
$this->returnUrl = $returnUrl;
$this->cancelUrl = $cancelUrl;
$this->brandName = $brandName;
$this->locale = $locale;
$this->landingPage = $landingPage;
$this->shippingPreference = $shippingPreference;
$this->userAction = $userAction;
//Currently we have not implemented the payment method.
$this->paymentMethod = null;
}
public function brandName(): string
{
return $this->brandName;
}
public function locale(): string
{
return $this->locale;
}
public function landingPage(): string
{
return $this->landingPage;
}
public function shippingPreference(): string
{
return $this->shippingPreference;
}
public function userAction(): string
{
return $this->userAction;
}
public function returnUrl(): string
{
return $this->returnUrl;
}
public function cancelUrl(): string
{
return $this->cancelUrl;
}
/**
* Currently, we have not implemented this.
*
* If we would follow our schema, we would create a paymentMethod entity which could
* get returned here.
*/
public function paymentMethod(): ?\stdClass
{
return $this->paymentMethod;
}
public function toArray(): array
{
$data = [];
if ($this->userAction()) {
$data['user_action'] = $this->userAction();
}
if ($this->paymentMethod()) {
$data['payment_method'] = $this->paymentMethod();
}
if ($this->shippingPreference()) {
$data['shipping_preference'] = $this->shippingPreference();
}
if ($this->landingPage()) {
$data['landing_page'] = $this->landingPage();
}
if ($this->locale()) {
$data['locale'] = $this->locale();
}
if ($this->brandName()) {
$data['brand_name'] = $this->brandName();
}
if ($this->returnUrl()) {
$data['return_url'] = $this->returnUrl();
}
if ($this->cancelUrl()) {
$data['cancel_url'] = $this->cancelUrl();
}
if ($this->paymentMethod()) {
$data['payment_method'] = $this->paymentMethod();
}
return $data;
}
}

View file

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Authorization
{
private $id;
private $authorizationStatus;
public function __construct(
string $id,
AuthorizationStatus $authorizationStatus
) {
$this->id = $id;
$this->authorizationStatus = $authorizationStatus;
}
public function id(): string
{
return $this->id;
}
public function status(): AuthorizationStatus
{
return $this->authorizationStatus;
}
public function toArray(): array
{
return [
'id' => $this->id,
'status' => $this->authorizationStatus->name(),
];
}
}

View file

@ -1,61 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class AuthorizationStatus
{
public const INTERNAL = 'INTERNAL';
public const CREATED = 'CREATED';
public const CAPTURED = 'CAPTURED';
public const COMPLETED = 'COMPLETED';
public const DENIED = 'DENIED';
public const EXPIRED = 'EXPIRED';
public const PARTIALLY_CAPTURED = 'PARTIALLY_CAPTURED';
public const VOIDED = 'VOIDED';
public const PENDING = 'PENDING';
public const VALID_STATUS = [
self::INTERNAL,
self::CREATED,
self::CAPTURED,
self::COMPLETED,
self::DENIED,
self::EXPIRED,
self::PARTIALLY_CAPTURED,
self::VOIDED,
self::PENDING,
];
private $status;
public function __construct(string $status)
{
if (!in_array($status, self::VALID_STATUS, true)) {
throw new RuntimeException(
sprintf(
// translators: %s is the current status.
__("%s is not a valid status", 'woocmmerce-paypal-commerce-gateway'),
$status
)
);
}
$this->status = $status;
}
public static function asInternal(): AuthorizationStatus
{
return new self(self::INTERNAL);
}
public function is(string $status): bool
{
return $this->status === $status;
}
public function name(): string
{
return $this->status;
}
}

View file

@ -1,71 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class CardAuthenticationResult
{
public const LIABILITY_SHIFT_POSSIBLE = 'POSSIBLE';
public const LIABILITY_SHIFT_NO = 'NO';
public const LIABILITY_SHIFT_UNKNOWN = 'UNKNOWN';
public const ENROLLMENT_STATUS_YES = 'Y';
public const ENROLLMENT_STATUS_NO = 'N';
public const ENROLLMENT_STATUS_UNAVAILABLE = 'U';
public const ENROLLMENT_STATUS_BYPASS = 'B';
public const AUTHENTICATION_RESULT_YES = 'Y';
public const AUTHENTICATION_RESULT_NO = 'N';
public const AUTHENTICATION_RESULT_REJECTED = 'R';
public const AUTHENTICATION_RESULT_ATTEMPTED = 'A';
public const AUTHENTICATION_RESULT_UNABLE = 'U';
public const AUTHENTICATION_RESULT_CHALLENGE_REQUIRED = 'C';
public const AUTHENTICATION_RESULT_INFO = 'I';
public const AUTHENTICATION_RESULT_DECOUPLED = 'D';
private $liabilityShift;
private $enrollmentStatus;
private $authenticationResult;
public function __construct(
string $liabilityShift,
string $enrollmentStatus,
string $authenticationResult
) {
$this->liabilityShift = strtoupper($liabilityShift);
$this->enrollmentStatus = strtoupper($enrollmentStatus);
$this->authenticationResult = strtoupper($authenticationResult);
}
public function liabilityShift(): string
{
return $this->liabilityShift;
}
public function enrollmentStatus(): string
{
return $this->enrollmentStatus;
}
public function authenticationResult(): string
{
return $this->authenticationResult;
}
public function toArray(): array
{
$data = [];
$data['liability_shift'] = $this->liabilityShift();
$data['three_d_secure'] = [
'enrollment_status' => $this->enrollmentStatus(),
'authentication_result' => $this->authenticationResult(),
];
return $data;
}
}

View file

@ -1,93 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Item
{
public const PHYSICAL_GOODS = 'PHYSICAL_GOODS';
public const DIGITAL_GOODS = 'DIGITAL_GOODS';
private $name;
private $unitAmount;
private $quantity;
private $description;
private $tax;
private $sku;
private $category;
public function __construct(
string $name,
Money $unitAmount,
int $quantity,
string $description = '',
Money $tax = null,
string $sku = '',
string $category = 'PHYSICAL_GOODS'
) {
$this->name = $name;
$this->unitAmount = $unitAmount;
$this->quantity = $quantity;
$this->description = $description;
$this->tax = $tax;
$this->sku = $sku;
$this->category = ($category === self::DIGITAL_GOODS) ?
self::DIGITAL_GOODS : self::PHYSICAL_GOODS;
}
public function name(): string
{
return $this->name;
}
public function unitAmount(): Money
{
return $this->unitAmount;
}
public function quantity(): int
{
return $this->quantity;
}
public function description(): string
{
return $this->description;
}
public function tax(): ?Money
{
return $this->tax;
}
public function sku(): string
{
return $this->sku;
}
public function category(): string
{
return $this->category;
}
public function toArray(): array
{
$item = [
'name' => $this->name(),
'unit_amount' => $this->unitAmount()->toArray(),
'quantity' => $this->quantity(),
'description' => $this->description(),
'sku' => $this->sku(),
'category' => $this->category(),
];
if ($this->tax()) {
$item['tax'] = $this->tax()->toArray();
}
return $item;
}
}

View file

@ -1,35 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Money
{
private $currencyCode;
private $value;
public function __construct(float $value, string $currencyCode)
{
$this->value = $value;
$this->currencyCode = $currencyCode;
}
public function value(): float
{
return $this->value;
}
public function currencyCode(): string
{
return $this->currencyCode;
}
public function toArray(): array
{
return [
'currency_code' => $this->currencyCode(),
'value' => number_format($this->value(), 2),
];
}
}

View file

@ -1,137 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Order
{
private $id;
private $createTime;
private $purchaseUnits;
private $payer;
private $orderStatus;
private $intent;
private $updateTime;
private $applicationContext;
private $paymentSource;
/**
* Order constructor.
*
* @see https://developer.paypal.com/docs/api/orders/v2/#orders-create-response
*/
public function __construct(
string $id,
array $purchaseUnits,
OrderStatus $orderStatus,
ApplicationContext $applicationContext = null,
PaymentSource $paymentSource = null,
Payer $payer = null,
string $intent = 'CAPTURE',
\DateTime $createTime = null,
\DateTime $updateTime = null
) {
$this->id = $id;
$this->applicationContext = $applicationContext;
//phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration.NoArgumentType
$this->purchaseUnits = array_values(array_filter(
$purchaseUnits,
static function ($unit): bool {
return is_a($unit, PurchaseUnit::class);
}
));
//phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration.NoArgumentType
$this->payer = $payer;
$this->orderStatus = $orderStatus;
$this->intent = ($intent === 'CAPTURE') ? 'CAPTURE' : 'AUTHORIZE';
$this->purchaseUnits = $purchaseUnits;
$this->createTime = $createTime;
$this->updateTime = $updateTime;
$this->paymentSource = $paymentSource;
}
public function id(): string
{
return $this->id;
}
public function createTime(): ?\DateTime
{
return $this->createTime;
}
public function updateTime(): ?\DateTime
{
return $this->updateTime;
}
public function intent(): string
{
return $this->intent;
}
public function payer(): ?Payer
{
return $this->payer;
}
/**
* @return PurchaseUnit[]
*/
public function purchaseUnits(): array
{
return $this->purchaseUnits;
}
public function status(): OrderStatus
{
return $this->orderStatus;
}
public function applicationContext(): ?ApplicationContext
{
return $this->applicationContext;
}
public function paymentSource(): ?PaymentSource
{
return $this->paymentSource;
}
public function toArray(): array
{
$order = [
'id' => $this->id(),
'intent' => $this->intent(),
'status' => $this->status()->name(),
'purchase_units' => array_map(
static function (PurchaseUnit $unit): array {
return $unit->toArray();
},
$this->purchaseUnits()
),
];
if ($this->createTime()) {
$order['create_time'] = $this->createTime()->format(\DateTimeInterface::ISO8601);
}
if ($this->payer()) {
$order['payer'] = $this->payer()->toArray();
}
if ($this->updateTime()) {
$order['update_time'] = $this->updateTime()->format(\DateTimeInterface::ISO8601);
}
if ($this->applicationContext()) {
$order['application_context'] = $this->applicationContext()->toArray();
}
if ($this->paymentSource()) {
$order['payment_source'] = $this->paymentSource()->toArray();
}
return $order;
}
}

View file

@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class OrderStatus
{
public const INTERNAL = 'INTERNAL';
public const CREATED = 'CREATED';
public const SAVED = 'SAVED';
public const APPROVED = 'APPROVED';
public const VOIDED = 'VOIDED';
public const COMPLETED = 'COMPLETED';
public const VALID_STATI = [
self::INTERNAL,
self::CREATED,
self::SAVED,
self::APPROVED,
self::VOIDED,
self::COMPLETED,
];
private $status;
public function __construct(string $status)
{
if (! in_array($status, self::VALID_STATI, true)) {
throw new RuntimeException(sprintf(
// translators: %s is the current status.
__("%s is not a valid status", "woocmmerce-paypal-commerce-gateway"),
$status
));
}
$this->status = $status;
}
public static function asInternal(): OrderStatus
{
return new self(self::INTERNAL);
}
public function is(string $status): bool
{
return $this->status === $status;
}
public function name(): string
{
return $this->status;
}
}

View file

@ -1,57 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
//phpcs:disable Inpsyde.CodeQuality.ElementNameMinimalLength.TooShort
class Patch
{
private $op;
private $path;
private $value;
public function __construct(string $op, string $path, array $value)
{
$this->op = $op;
$this->path = $path;
$this->value = $value;
}
public function op(): string
{
return $this->op;
}
public function path(): string
{
return $this->path;
}
// phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration.NoReturnType
public function value()
{
return $this->value;
}
// phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration.NoReturnType
public function toArray(): array
{
return [
'op' => $this->op(),
'value' => $this->value(),
'path' => $this->path(),
];
}
/**
* Needed for the move operation. We currently do not
* support the move operation.
*
* @return string
*/
public function from(): string
{
return '';
}
}

View file

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class PatchCollection
{
private $patches;
public function __construct(Patch ...$patches)
{
$this->patches = $patches;
}
/**
* @return Patch[]
*/
public function patches(): array
{
return $this->patches;
}
public function toArray(): array
{
return array_map(
static function (Patch $patch): array {
return $patch->toArray();
},
$this->patches()
);
}
}

View file

@ -1,48 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Payee
* The entity, which receives the money.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
class Payee
{
private $email;
private $merchantId;
public function __construct(
string $email,
string $merchantId
) {
$this->email = $email;
$this->merchantId = $merchantId;
}
public function email(): string
{
return $this->email;
}
public function merchantId(): string
{
return $this->merchantId;
}
public function toArray(): array
{
$data = [
'email_address' => $this->email(),
];
if ($this->merchantId) {
$data['merchant_id'] = $this->merchantId();
}
return $data;
}
}

View file

@ -1,100 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Payer
* The customer who sends the money.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
class Payer
{
private $name;
private $emailAddress;
private $payerId;
private $birthDate;
private $address;
private $phone;
private $taxInfo;
public function __construct(
PayerName $name,
string $emailAddress,
string $payerId,
Address $address,
\DateTime $birthDate = null,
PhoneWithType $phone = null,
PayerTaxInfo $taxInfo = null
) {
$this->name = $name;
$this->emailAddress = $emailAddress;
$this->payerId = $payerId;
$this->birthDate = $birthDate;
$this->address = $address;
$this->phone = $phone;
$this->taxInfo = $taxInfo;
}
public function name(): PayerName
{
return $this->name;
}
public function emailAddress(): string
{
return $this->emailAddress;
}
public function payerId(): string
{
return $this->payerId;
}
public function birthDate(): ?\DateTime
{
return $this->birthDate;
}
public function address(): Address
{
return $this->address;
}
public function phone(): ?PhoneWithType
{
return $this->phone;
}
public function taxInfo(): ?PayerTaxInfo
{
return $this->taxInfo;
}
public function toArray(): array
{
$payer = [
'name' => $this->name()->toArray(),
'email_address' => $this->emailAddress(),
'address' => $this->address()->toArray(),
];
if ($this->payerId()) {
$payer['payer_id'] = $this->payerId();
}
if ($this->phone()) {
$payer['phone'] = $this->phone()->toArray();
}
if ($this->taxInfo()) {
$payer['tax_info'] = $this->taxInfo()->toArray();
}
if ($this->birthDate()) {
$payer['birth_date'] = $this->birthDate()->format('Y-m-d');
}
return $payer;
}
}

View file

@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class PayerName
{
private $givenName;
private $surname;
public function __construct(
string $givenName,
string $surname
) {
$this->givenName = $givenName;
$this->surname = $surname;
}
public function givenName(): string
{
return $this->givenName;
}
public function surname(): string
{
return $this->surname;
}
public function toArray(): array
{
return [
'given_name' => $this->givenName(),
'surname' => $this->surname(),
];
}
}

View file

@ -1,51 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class PayerTaxInfo
{
public const VALID_TYPES = [
'BR_CPF',
'BR_CNPJ',
];
private $taxId;
private $type;
public function __construct(
string $taxId,
string $type
) {
if (! in_array($type, self::VALID_TYPES, true)) {
throw new RuntimeException(sprintf(
// translators: %s is the current type.
__("%s is not a valid tax type.", "woocommerce-paypal-commerce-gateway"),
$type
));
}
$this->taxId = $taxId;
$this->type = $type;
}
public function type(): string
{
return $this->type;
}
public function taxId(): string
{
return $this->taxId;
}
public function toArray(): array
{
return [
'tax_id' => $this->taxId(),
'tax_id_type' => $this->type(),
];
}
}

View file

@ -1,43 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class PaymentMethod
{
public const PAYER_SELECTED_DEFAULT = 'PAYPAL';
public const PAYEE_PREFERRED_UNRESTRICTED = 'UNRESTRICTED';
public const PAYEE_PREFERRED_IMMEDIATE_PAYMENT_REQUIRED = 'IMMEDIATE_PAYMENT_REQUIRED';
private $preferred;
private $selected;
public function __construct(
string $preferred = self::PAYEE_PREFERRED_UNRESTRICTED,
string $selected = self::PAYER_SELECTED_DEFAULT
) {
$this->preferred = $preferred;
$this->selected = $selected;
}
public function payeePreferred(): string
{
return $this->preferred;
}
public function payerSelected(): string
{
return $this->selected;
}
public function toArray(): array
{
return [
'payee_preferred' => $this->payeePreferred(),
'payer_selected' => $this->payerSelected(),
];
}
}

View file

@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class PaymentSource
{
private $card;
private $wallet;
public function __construct(
PaymentSourceCard $card = null,
PaymentSourceWallet $wallet = null
) {
$this->card = $card;
$this->wallet = $wallet;
}
public function card(): ?PaymentSourceCard
{
return $this->card;
}
public function wallet(): ?PaymentSourceWallet
{
return $this->wallet;
}
public function toArray(): array
{
$data = [];
if ($this->card()) {
$data['card'] = $this->card()->toArray();
}
if ($this->wallet()) {
$data['wallet'] = $this->wallet()->toArray();
}
return $data;
}
}

View file

@ -1,64 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class PaymentSourceCard
{
private $lastDigits;
private $brand;
private $type;
private $authenticationResult;
public function __construct(
string $lastDigits,
string $brand,
string $type,
CardAuthenticationResult $authenticationResult = null
) {
$this->lastDigits = $lastDigits;
$this->brand = $brand;
$this->type = $type;
$this->authenticationResult = $authenticationResult;
}
public function lastDigits(): string
{
return $this->lastDigits;
}
public function brand(): string
{
return $this->brand;
}
public function type(): string
{
return $this->type;
}
public function authenticationResult(): ?CardAuthenticationResult
{
return $this->authenticationResult;
}
public function toArray(): array
{
$data = [
'last_digits' => $this->lastDigits(),
'brand' => $this->brand(),
'type' => $this->type(),
];
if ($this->authenticationResult()) {
$data['authentication_result'] = $this->authenticationResult()->toArray();
}
return $data;
}
}

View file

@ -1,14 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class PaymentSourceWallet
{
public function toArray(): array
{
return [];
}
}

View file

@ -1,47 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class PaymentToken
{
public const TYPE_PAYMENT_METHOD_TOKEN = 'PAYMENT_METHOD_TOKEN';
public const VALID_TYPES = [
self::TYPE_PAYMENT_METHOD_TOKEN,
];
private $id;
private $type;
public function __construct(string $id, string $type = self::TYPE_PAYMENT_METHOD_TOKEN)
{
if (! in_array($type, self::VALID_TYPES, true)) {
throw new RuntimeException(
__("Not a valid payment source type.", "woocommerce-paypal-commerce-gateway")
);
}
$this->id = $id;
$this->type = $type;
}
public function id(): string
{
return $this->id;
}
public function type(): string
{
return $this->type;
}
public function toArray(): array
{
return [
'id' => $this->id(),
'type' => $this->type(),
];
}
}

View file

@ -1,35 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Payments
{
private $authorizations;
public function __construct(Authorization ...$authorizations)
{
$this->authorizations = $authorizations;
}
public function toArray(): array
{
return [
'authorizations' => array_map(
static function (Authorization $authorization): array {
return $authorization->toArray();
},
$this->authorizations()
),
];
}
/**
* @return Authorization[]
**/
public function authorizations(): array
{
return $this->authorizations;
}
}

View file

@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Phone
{
private $nationalNumber;
public function __construct(string $nationalNumber)
{
$this->nationalNumber = $nationalNumber;
}
public function nationalNumber(): string
{
return $this->nationalNumber;
}
public function toArray(): array
{
return [
'national_number' => $this->nationalNumber(),
];
}
}

View file

@ -1,42 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class PhoneWithType
{
public const VALLID_TYPES = [
'FAX',
'HOME',
'MOBILE',
'OTHER',
'PAGER',
];
private $type;
private $phone;
public function __construct(string $type, Phone $phone)
{
$this->type = in_array($type, self::VALLID_TYPES, true) ? $type : 'OTHER';
$this->phone = $phone;
}
public function type(): string
{
return $this->type;
}
public function phone(): Phone
{
return $this->phone;
}
public function toArray(): array
{
return [
'phone_type' => $this->type(),
'phone_number' => $this->phone()->toArray(),
];
}
}

View file

@ -1,231 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
//phpcs:disable Inpsyde.CodeQuality.PropertyPerClassLimit.TooManyProperties
class PurchaseUnit
{
private $amount;
private $items;
private $shipping;
private $referenceId;
private $description;
private $payee;
private $customId;
private $invoiceId;
private $softDescriptor;
private $payments;
/**
* @var bool
*/
private $containsPhysicalGoodsItems = false;
public function __construct(
Amount $amount,
array $items = [],
Shipping $shipping = null,
string $referenceId = 'default',
string $description = '',
Payee $payee = null,
string $customId = '',
string $invoiceId = '',
string $softDescriptor = '',
Payments $payments = null
) {
$this->amount = $amount;
$this->shipping = $shipping;
$this->referenceId = $referenceId;
$this->description = $description;
//phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration.NoArgumentType
$this->items = array_values(array_filter(
$items,
function ($item): bool {
$isItem = is_a($item, Item::class);
/**
* @var Item $item
*/
if ($isItem && Item::PHYSICAL_GOODS === $item->category()) {
$this->containsPhysicalGoodsItems = true;
}
return $isItem;
}
));
//phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration.NoArgumentType
$this->payee = $payee;
$this->customId = $customId;
$this->invoiceId = $invoiceId;
$this->softDescriptor = $softDescriptor;
$this->payments = $payments;
}
public function amount(): Amount
{
return $this->amount;
}
public function shipping(): ?Shipping
{
return $this->shipping;
}
public function referenceId(): string
{
return $this->referenceId;
}
public function description(): string
{
return $this->description;
}
public function customId(): string
{
return $this->customId;
}
public function invoiceId(): string
{
return $this->invoiceId;
}
public function softDescriptor(): string
{
return $this->softDescriptor;
}
public function payee(): ?Payee
{
return $this->payee;
}
public function payments(): ?Payments
{
return $this->payments;
}
/**
* @return Item[]
*/
public function items(): array
{
return $this->items;
}
public function containsPhysicalGoodsItems(): bool
{
return $this->containsPhysicalGoodsItems;
}
public function toArray(): array
{
$purchaseUnit = [
'reference_id' => $this->referenceId(),
'amount' => $this->amount()->toArray(),
'description' => $this->description(),
'items' => array_map(
static function (Item $item): array {
return $item->toArray();
},
$this->items()
),
];
if ($this->ditchItemsWhenMismatch($this->amount(), ...$this->items())) {
unset($purchaseUnit['items']);
unset($purchaseUnit['amount']['breakdown']);
}
if ($this->payee()) {
$purchaseUnit['payee'] = $this->payee()->toArray();
}
if ($this->payments()) {
$purchaseUnit['payments'] = $this->payments()->toArray();
}
if ($this->shipping()) {
$purchaseUnit['shipping'] = $this->shipping()->toArray();
}
if ($this->customId()) {
$purchaseUnit['custom_id'] = $this->customId();
}
if ($this->invoiceId()) {
$purchaseUnit['invoice_id'] = $this->invoiceId();
}
if ($this->softDescriptor()) {
$purchaseUnit['soft_descriptor'] = $this->softDescriptor();
}
return $purchaseUnit;
}
/**
* All money values send to PayPal can only have 2 decimal points. Woocommerce internally does
* not have this restriction. Therefore the totals of the cart in Woocommerce and the totals
* of the rounded money values of the items, we send to PayPal, can differ. In those cases,
* we can not send the line items.
*
* @param Amount $amount
* @param Item ...$items
* @return bool
*/
//phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
private function ditchItemsWhenMismatch(Amount $amount, Item ...$items): bool
{
$feeItemsTotal = ($amount->breakdown() && $amount->breakdown()->itemTotal()) ?
$amount->breakdown()->itemTotal()->value() : null;
$feeTaxTotal = ($amount->breakdown() && $amount->breakdown()->taxTotal()) ?
$amount->breakdown()->taxTotal()->value() : null;
foreach ($items as $item) {
if (null !== $feeItemsTotal) {
$feeItemsTotal -= $item->unitAmount()->value() * $item->quantity();
}
if (null !== $feeTaxTotal) {
$feeTaxTotal -= $item->tax()->value() * $item->quantity();
}
}
$feeItemsTotal = round($feeItemsTotal, 2);
$feeTaxTotal = round($feeTaxTotal, 2);
if ($feeItemsTotal !== 0.0 || $feeTaxTotal !== 0.0) {
return true;
}
$breakdown = $this->amount()->breakdown();
if (! $breakdown) {
return false;
}
$amountTotal = 0;
if ($breakdown->shipping()) {
$amountTotal += $breakdown->shipping()->value();
}
if ($breakdown->itemTotal()) {
$amountTotal += $breakdown->itemTotal()->value();
}
if ($breakdown->discount()) {
$amountTotal -= $breakdown->discount()->value();
}
if ($breakdown->taxTotal()) {
$amountTotal += $breakdown->taxTotal()->value();
}
if ($breakdown->shippingDiscount()) {
$amountTotal -= $breakdown->shippingDiscount()->value();
}
if ($breakdown->handling()) {
$amountTotal += $breakdown->handling()->value();
}
if ($breakdown->insurance()) {
$amountTotal += $breakdown->insurance()->value();
}
$amountValue = $this->amount()->value();
$needsToDitch = (string) $amountTotal !== (string) $amountValue;
return $needsToDitch;
}
}

View file

@ -1,37 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Shipping
{
private $name;
private $address;
public function __construct(string $name, Address $address)
{
$this->name = $name;
$this->address = $address;
}
public function name(): string
{
return $this->name;
}
public function address(): Address
{
return $this->address;
}
public function toArray(): array
{
return [
'name' => [
'full_name' => $this->name(),
],
'address' => $this->address()->toArray(),
];
}
}

View file

@ -1,72 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class Token
{
private $json;
private $created;
public function __construct(\stdClass $json)
{
if (! isset($json->created)) {
$json->created = time();
}
if (! $this->validate($json)) {
throw new RuntimeException("Token not valid");
}
$this->json = $json;
}
public function expirationTimestamp(): int
{
return $this->json->created + $this->json->expires_in;
}
public function token(): string
{
return (string) $this->json->token;
}
public function isValid(): bool
{
return time() < $this->json->created + $this->json->expires_in;
}
public function asJson(): string
{
return json_encode($this->json);
}
public static function fromJson(string $json): self
{
$json = (object) json_decode($json);
if (isset($json->access_token) || isset($json->client_token)) {
$json->token = isset($json->access_token) ? $json->access_token : $json->client_token;
}
return new Token($json);
}
private function validate(\stdClass $json): bool
{
$propertyMap = [
'created' => 'is_int',
'expires_in' => 'is_int',
'token' => 'is_string',
];
foreach ($propertyMap as $property => $validator) {
if (! isset($json->{$property}) || ! $validator($json->{$property})) {
return false;
}
}
return true;
}
}

View file

@ -1,50 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Webhook
{
private $id;
private $url;
private $eventTypes;
public function __construct(string $url, array $eventTypes, string $id = '')
{
$this->url = $url;
$this->eventTypes = $eventTypes;
$this->id = $id;
}
public function id(): string
{
return $this->id;
}
public function url(): string
{
return $this->url;
}
public function eventTypes(): array
{
return $this->eventTypes;
}
public function toArray(): array
{
$data = [
'url' => $this->url(),
'event_types' => $this->eventTypes(),
];
if ($this->id()) {
$data['id'] = $this->id();
}
return $data;
}
}

View file

@ -0,0 +1,155 @@
<?php
/**
* The address object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Address
*/
class Address {
/**
* The country code.
*
* @var string
*/
private $country_code;
/**
* The 1st address line.
*
* @var string
*/
private $address_line_1;
/**
* The 2nd address line.
*
* @var string
*/
private $address_line_2;
/**
* The admin area 1.
*
* @var string
*/
private $admin_area_1;
/**
* The admin area 2.
*
* @var string
*/
private $admin_area_2;
/**
* The postal code.
*
* @var string
*/
private $postal_code;
/**
* Address constructor.
*
* @param string $country_code The country code.
* @param string $address_line_1 The 1st address line.
* @param string $address_line_2 The 2nd address line.
* @param string $admin_area_1 The admin area 1.
* @param string $admin_area_2 The admin area 2.
* @param string $postal_code The postal code.
*/
public function __construct(
string $country_code,
string $address_line_1 = '',
string $address_line_2 = '',
string $admin_area_1 = '',
string $admin_area_2 = '',
string $postal_code = ''
) {
$this->country_code = $country_code;
$this->address_line_1 = $address_line_1;
$this->address_line_2 = $address_line_2;
$this->admin_area_1 = $admin_area_1;
$this->admin_area_2 = $admin_area_2;
$this->postal_code = $postal_code;
}
/**
* Returns the country code.
*
* @return string
*/
public function country_code(): string {
return $this->country_code;
}
/**
* Returns the 1st address line.
*
* @return string
*/
public function address_line_1(): string {
return $this->address_line_1;
}
/**
* Returns the 2nd address line.
*
* @return string
*/
public function address_line_2(): string {
return $this->address_line_2;
}
/**
* Returns the admin area 1.
*
* @return string
*/
public function admin_area_1(): string {
return $this->admin_area_1;
}
/**
* Returns the admin area 2.
*
* @return string
*/
public function admin_area_2(): string {
return $this->admin_area_2;
}
/**
* Returns the postal code.
*
* @return string
*/
public function postal_code(): string {
return $this->postal_code;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'country_code' => $this->country_code(),
'address_line_1' => $this->address_line_1(),
'address_line_2' => $this->address_line_2(),
'admin_area_1' => $this->admin_area_1(),
'admin_area_2' => $this->admin_area_2(),
'postal_code' => $this->postal_code(),
);
}
}

View file

@ -0,0 +1,84 @@
<?php
/**
* The amount object
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Amount
*/
class Amount {
/**
* The money.
*
* @var Money
*/
private $money;
/**
* The breakdown.
*
* @var AmountBreakdown
*/
private $breakdown;
/**
* Amount constructor.
*
* @param Money $money The money.
* @param AmountBreakdown|null $breakdown The breakdown.
*/
public function __construct( Money $money, AmountBreakdown $breakdown = null ) {
$this->money = $money;
$this->breakdown = $breakdown;
}
/**
* Returns the currency code.
*
* @return string
*/
public function currency_code(): string {
return $this->money->currency_code();
}
/**
* Returns the value.
*
* @return float
*/
public function value(): float {
return $this->money->value();
}
/**
* Returns the breakdown.
*
* @return AmountBreakdown|null
*/
public function breakdown(): ?AmountBreakdown {
return $this->breakdown;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$amount = array(
'currency_code' => $this->currency_code(),
'value' => $this->value(),
);
if ( $this->breakdown() && count( $this->breakdown()->to_array() ) ) {
$amount['breakdown'] = $this->breakdown()->to_array();
}
return $amount;
}
}

View file

@ -0,0 +1,190 @@
<?php
/**
* The Amount Breakdown object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class AmountBreakdown
*/
class AmountBreakdown {
/**
* The item total.
*
* @var Money
*/
private $item_total;
/**
* The shipping.
*
* @var Money
*/
private $shipping;
/**
* The tax total.
*
* @var Money
*/
private $tax_total;
/**
* The handling.
*
* @var Money
*/
private $handling;
/**
* The insurance.
*
* @var Money
*/
private $insurance;
/**
* The shipping discount.
*
* @var Money
*/
private $shipping_discount;
/**
* The discount.
*
* @var Money
*/
private $discount;
/**
* AmountBreakdown constructor.
*
* @param Money|null $item_total The item total.
* @param Money|null $shipping The shipping.
* @param Money|null $tax_total The tax total.
* @param Money|null $handling The handling.
* @param Money|null $insurance The insurance.
* @param Money|null $shipping_discount The shipping discount.
* @param Money|null $discount The discount.
*/
public function __construct(
Money $item_total = null,
Money $shipping = null,
Money $tax_total = null,
Money $handling = null,
Money $insurance = null,
Money $shipping_discount = null,
Money $discount = null
) {
$this->item_total = $item_total;
$this->shipping = $shipping;
$this->tax_total = $tax_total;
$this->handling = $handling;
$this->insurance = $insurance;
$this->shipping_discount = $shipping_discount;
$this->discount = $discount;
}
/**
* Returns the item total.
*
* @return Money|null
*/
public function item_total(): ?Money {
return $this->item_total;
}
/**
* Returns the shipping.
*
* @return Money|null
*/
public function shipping(): ?Money {
return $this->shipping;
}
/**
* Returns the tax total.
*
* @return Money|null
*/
public function tax_total(): ?Money {
return $this->tax_total;
}
/**
* Returns the handling.
*
* @return Money|null
*/
public function handling(): ?Money {
return $this->handling;
}
/**
* Returns the insurance.
*
* @return Money|null
*/
public function insurance(): ?Money {
return $this->insurance;
}
/**
* Returns the shipping discount.
*
* @return Money|null
*/
public function shipping_discount(): ?Money {
return $this->shipping_discount;
}
/**
* Returns the discount.
*
* @return Money|null
*/
public function discount(): ?Money {
return $this->discount;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$breakdown = array();
if ( $this->item_total ) {
$breakdown['item_total'] = $this->item_total->to_array();
}
if ( $this->shipping ) {
$breakdown['shipping'] = $this->shipping->to_array();
}
if ( $this->tax_total ) {
$breakdown['tax_total'] = $this->tax_total->to_array();
}
if ( $this->handling ) {
$breakdown['handling'] = $this->handling->to_array();
}
if ( $this->insurance ) {
$breakdown['insurance'] = $this->insurance->to_array();
}
if ( $this->shipping_discount ) {
$breakdown['shipping_discount'] = $this->shipping_discount->to_array();
}
if ( $this->discount ) {
$breakdown['discount'] = $this->discount->to_array();
}
return $breakdown;
}
}

View file

@ -0,0 +1,249 @@
<?php
/**
* The application context object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
/**
* Class ApplicationContext
*/
class ApplicationContext {
public const LANDING_PAGE_LOGIN = 'LOGIN';
public const LANDING_PAGE_BILLING = 'BILLING';
public const LANDING_PAGE_NO_PREFERENCE = 'NO_PREFERENCE';
private const VALID_LANDING_PAGE_VALUES = array(
self::LANDING_PAGE_LOGIN,
self::LANDING_PAGE_BILLING,
self::LANDING_PAGE_NO_PREFERENCE,
);
public const SHIPPING_PREFERENCE_GET_FROM_FILE = 'GET_FROM_FILE';
public const SHIPPING_PREFERENCE_NO_SHIPPING = 'NO_SHIPPING';
public const SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS = 'SET_PROVIDED_ADDRESS';
private const VALID_SHIPPING_PREFERENCE_VALUES = array(
self::SHIPPING_PREFERENCE_GET_FROM_FILE,
self::SHIPPING_PREFERENCE_NO_SHIPPING,
self::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
);
public const USER_ACTION_CONTINUE = 'CONTINUE';
public const USER_ACTION_PAY_NOW = 'PAY_NOW';
private const VALID_USER_ACTION_VALUES = array(
self::USER_ACTION_CONTINUE,
self::USER_ACTION_PAY_NOW,
);
/**
* The brand name.
*
* @var string
*/
private $brand_name;
/**
* The locale.
*
* @var string
*/
private $locale;
/**
* The landing page.
*
* @var string
*/
private $landing_page;
/**
* The shipping preference.
*
* @var string
*/
private $shipping_preference;
/**
* The user action.
*
* @var string
*/
private $user_action;
/**
* The return url.
*
* @var string
*/
private $return_url;
/**
* The cancel url.
*
* @var string
*/
private $cancel_url;
/**
* The payment method.
*
* @var null
*/
private $payment_method;
/**
* ApplicationContext constructor.
*
* @param string $return_url The return URL.
* @param string $cancel_url The cancel URL.
* @param string $brand_name The brand name.
* @param string $locale The locale.
* @param string $landing_page The landing page.
* @param string $shipping_preference The shipping preference.
* @param string $user_action The user action.
*
* @throws RuntimeException When values are not valid.
*/
public function __construct(
string $return_url = '',
string $cancel_url = '',
string $brand_name = '',
string $locale = '',
string $landing_page = self::LANDING_PAGE_NO_PREFERENCE,
string $shipping_preference = self::SHIPPING_PREFERENCE_NO_SHIPPING,
string $user_action = self::USER_ACTION_CONTINUE
) {
if ( ! in_array( $landing_page, self::VALID_LANDING_PAGE_VALUES, true ) ) {
throw new RuntimeException( 'Landingpage not correct' );
}
if ( ! in_array( $shipping_preference, self::VALID_SHIPPING_PREFERENCE_VALUES, true ) ) {
throw new RuntimeException( 'Shipping preference not correct' );
}
if ( ! in_array( $user_action, self::VALID_USER_ACTION_VALUES, true ) ) {
throw new RuntimeException( 'User action preference not correct' );
}
$this->return_url = $return_url;
$this->cancel_url = $cancel_url;
$this->brand_name = $brand_name;
$this->locale = $locale;
$this->landing_page = $landing_page;
$this->shipping_preference = $shipping_preference;
$this->user_action = $user_action;
// Currently we have not implemented the payment method.
$this->payment_method = null;
}
/**
* Returns the brand name.
*
* @return string
*/
public function brand_name(): string {
return $this->brand_name;
}
/**
* Returns the locale.
*
* @return string
*/
public function locale(): string {
return $this->locale;
}
/**
* Returns the landing page.
*
* @return string
*/
public function landing_page(): string {
return $this->landing_page;
}
/**
* Returns the shipping preference.
*
* @return string
*/
public function shipping_preference(): string {
return $this->shipping_preference;
}
/**
* Returns the user action.
*
* @return string
*/
public function user_action(): string {
return $this->user_action;
}
/**
* Returns the return URL.
*
* @return string
*/
public function return_url(): string {
return $this->return_url;
}
/**
* Returns the cancel URL.
*
* @return string
*/
public function cancel_url(): string {
return $this->cancel_url;
}
/**
* Returns the payment method.
*
* @return PaymentMethod|null
*/
public function payment_method(): ?PaymentMethod {
return $this->payment_method;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$data = array();
if ( $this->user_action() ) {
$data['user_action'] = $this->user_action();
}
if ( $this->payment_method() ) {
$data['payment_method'] = $this->payment_method();
}
if ( $this->shipping_preference() ) {
$data['shipping_preference'] = $this->shipping_preference();
}
if ( $this->landing_page() ) {
$data['landing_page'] = $this->landing_page();
}
if ( $this->locale() ) {
$data['locale'] = $this->locale();
}
if ( $this->brand_name() ) {
$data['brand_name'] = $this->brand_name();
}
if ( $this->return_url() ) {
$data['return_url'] = $this->return_url();
}
if ( $this->cancel_url() ) {
$data['cancel_url'] = $this->cancel_url();
}
return $data;
}
}

View file

@ -0,0 +1,75 @@
<?php
/**
* The Authorization object
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Authorization
*/
class Authorization {
/**
* The Id.
*
* @var string
*/
private $id;
/**
* The status.
*
* @var AuthorizationStatus
*/
private $authorization_status;
/**
* Authorization constructor.
*
* @param string $id The id.
* @param AuthorizationStatus $authorization_status The status.
*/
public function __construct(
string $id,
AuthorizationStatus $authorization_status
) {
$this->id = $id;
$this->authorization_status = $authorization_status;
}
/**
* Returns the Id.
*
* @return string
*/
public function id(): string {
return $this->id;
}
/**
* Returns the status.
*
* @return AuthorizationStatus
*/
public function status(): AuthorizationStatus {
return $this->authorization_status;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'id' => $this->id,
'status' => $this->authorization_status->name(),
);
}
}

View file

@ -0,0 +1,94 @@
<?php
/**
* The AuthorizationStatus object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
/**
* Class AuthorizationStatus
*/
class AuthorizationStatus {
public const INTERNAL = 'INTERNAL';
public const CREATED = 'CREATED';
public const CAPTURED = 'CAPTURED';
public const COMPLETED = 'COMPLETED';
public const DENIED = 'DENIED';
public const EXPIRED = 'EXPIRED';
public const PARTIALLY_CAPTURED = 'PARTIALLY_CAPTURED';
public const VOIDED = 'VOIDED';
public const PENDING = 'PENDING';
public const VALID_STATUS = array(
self::INTERNAL,
self::CREATED,
self::CAPTURED,
self::COMPLETED,
self::DENIED,
self::EXPIRED,
self::PARTIALLY_CAPTURED,
self::VOIDED,
self::PENDING,
);
/**
* The status.
*
* @var string
*/
private $status;
/**
* AuthorizationStatus constructor.
*
* @param string $status The status.
* @throws RuntimeException When the status is not valid.
*/
public function __construct( string $status ) {
if ( ! in_array( $status, self::VALID_STATUS, true ) ) {
throw new RuntimeException(
sprintf(
// translators: %s is the current status.
__( '%s is not a valid status', 'woocommerce-paypal-commerce-gateway' ),
$status
)
);
}
$this->status = $status;
}
/**
* Returns an AuthorizationStatus as Internal.
*
* @return AuthorizationStatus
*/
public static function as_internal(): AuthorizationStatus {
return new self( self::INTERNAL );
}
/**
* Compares the current status with a given one.
*
* @param string $status The status to compare with.
*
* @return bool
*/
public function is( string $status ): bool {
return $this->status === $status;
}
/**
* Returns the status.
*
* @return string
*/
public function name(): string {
return $this->status;
}
}

View file

@ -0,0 +1,119 @@
<?php
/**
* The CardauthenticationResult object
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class CardAuthenticationResult
*/
class CardAuthenticationResult {
public const LIABILITY_SHIFT_POSSIBLE = 'POSSIBLE';
public const LIABILITY_SHIFT_NO = 'NO';
public const LIABILITY_SHIFT_UNKNOWN = 'UNKNOWN';
public const ENROLLMENT_STATUS_YES = 'Y';
public const ENROLLMENT_STATUS_NO = 'N';
public const ENROLLMENT_STATUS_UNAVAILABLE = 'U';
public const ENROLLMENT_STATUS_BYPASS = 'B';
public const AUTHENTICATION_RESULT_YES = 'Y';
public const AUTHENTICATION_RESULT_NO = 'N';
public const AUTHENTICATION_RESULT_REJECTED = 'R';
public const AUTHENTICATION_RESULT_ATTEMPTED = 'A';
public const AUTHENTICATION_RESULT_UNABLE = 'U';
public const AUTHENTICATION_RESULT_CHALLENGE_REQUIRED = 'C';
public const AUTHENTICATION_RESULT_INFO = 'I';
public const AUTHENTICATION_RESULT_DECOUPLED = 'D';
/**
* The liability shift.
*
* @var string
*/
private $liability_shift;
/**
* The enrollment status.
*
* @var string
*/
private $enrollment_status;
/**
* The authentication result.
*
* @var string
*/
private $authentication_result;
/**
* CardAuthenticationResult constructor.
*
* @param string $liability_shift The liability shift.
* @param string $enrollment_status The enrollment status.
* @param string $authentication_result The authentication result.
*/
public function __construct(
string $liability_shift,
string $enrollment_status,
string $authentication_result
) {
$this->liability_shift = strtoupper( $liability_shift );
$this->enrollment_status = strtoupper( $enrollment_status );
$this->authentication_result = strtoupper( $authentication_result );
}
/**
* Returns the liability shift.
*
* @return string
*/
public function liability_shift(): string {
return $this->liability_shift;
}
/**
* Returns the enrollment status.
*
* @return string
*/
public function enrollment_status(): string {
return $this->enrollment_status;
}
/**
* Returns the authentication result.
*
* @return string
*/
public function authentication_result(): string {
return $this->authentication_result;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$data = array();
$data['liability_shift'] = $this->liability_shift();
$data['three_d_secure'] = array(
'enrollment_status' => $this->enrollment_status(),
'authentication_result' => $this->authentication_result(),
);
return $data;
}
}

View file

@ -0,0 +1,185 @@
<?php
/**
* The item object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Item
*/
class Item {
public const PHYSICAL_GOODS = 'PHYSICAL_GOODS';
public const DIGITAL_GOODS = 'DIGITAL_GOODS';
/**
* The name.
*
* @var string
*/
private $name;
/**
* The unit amount.
*
* @var Money
*/
private $unit_amount;
/**
* The quantity.
*
* @var int
*/
private $quantity;
/**
* The description.
*
* @var string
*/
private $description;
/**
* The tax.
*
* @var Money|null
*/
private $tax;
/**
* The SKU.
*
* @var string
*/
private $sku;
/**
* The category.
*
* @var string
*/
private $category;
/**
* Item constructor.
*
* @param string $name The name.
* @param Money $unit_amount The unit amount.
* @param int $quantity The quantity.
* @param string $description The description.
* @param Money|null $tax The tax.
* @param string $sku The SKU.
* @param string $category The category.
*/
public function __construct(
string $name,
Money $unit_amount,
int $quantity,
string $description = '',
Money $tax = null,
string $sku = '',
string $category = 'PHYSICAL_GOODS'
) {
$this->name = $name;
$this->unit_amount = $unit_amount;
$this->quantity = $quantity;
$this->description = $description;
$this->tax = $tax;
$this->sku = $sku;
$this->category = ( self::DIGITAL_GOODS === $category ) ?
self::DIGITAL_GOODS : self::PHYSICAL_GOODS;
}
/**
* Returns the name of the item.
*
* @return string
*/
public function name(): string {
return $this->name;
}
/**
* Returns the unit amount.
*
* @return Money
*/
public function unit_amount(): Money {
return $this->unit_amount;
}
/**
* Returns the quantity.
*
* @return int
*/
public function quantity(): int {
return $this->quantity;
}
/**
* Returns the description.
*
* @return string
*/
public function description(): string {
return $this->description;
}
/**
* Returns the tax.
*
* @return Money|null
*/
public function tax(): ?Money {
return $this->tax;
}
/**
* Returns the SKU.
*
* @return string
*/
public function sku(): string {
return $this->sku;
}
/**
* Returns the category.
*
* @return string
*/
public function category(): string {
return $this->category;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$item = array(
'name' => $this->name(),
'unit_amount' => $this->unit_amount()->to_array(),
'quantity' => $this->quantity(),
'description' => $this->description(),
'sku' => $this->sku(),
'category' => $this->category(),
);
if ( $this->tax() ) {
$item['tax'] = $this->tax()->to_array();
}
return $item;
}
}

View file

@ -0,0 +1,71 @@
<?php
/**
* The money object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Money
*/
class Money {
/**
* The currency code.
*
* @var string
*/
private $currency_code;
/**
* The value.
*
* @var float
*/
private $value;
/**
* Money constructor.
*
* @param float $value The value.
* @param string $currency_code The currency code.
*/
public function __construct( float $value, string $currency_code ) {
$this->value = $value;
$this->currency_code = $currency_code;
}
/**
* The value.
*
* @return float
*/
public function value(): float {
return $this->value;
}
/**
* The currency code.
*
* @return string
*/
public function currency_code(): string {
return $this->currency_code;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'currency_code' => $this->currency_code(),
'value' => number_format( $this->value(), 2 ),
);
}
}

View file

@ -0,0 +1,245 @@
<?php
/**
* The order object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Order
*/
class Order {
/**
* The ID.
*
* @var string
*/
private $id;
/**
* The create time.
*
* @var \DateTime|null
*/
private $create_time;
/**
* The purchase units.
*
* @var PurchaseUnit[]
*/
private $purchase_units;
/**
* The payer.
*
* @var Payer|null
*/
private $payer;
/**
* The order status.
*
* @var OrderStatus
*/
private $order_status;
/**
* The intent.
*
* @var string
*/
private $intent;
/**
* The update time.
*
* @var \DateTime|null
*/
private $update_time;
/**
* The application context.
*
* @var ApplicationContext|null
*/
private $application_context;
/**
* The payment source.
*
* @var PaymentSource|null
*/
private $payment_source;
/**
* Order constructor.
*
* @see https://developer.paypal.com/docs/api/orders/v2/#orders-create-response
*
* @param string $id The ID.
* @param PurchaseUnit[] $purchase_units The purchase units.
* @param OrderStatus $order_status The order status.
* @param ApplicationContext|null $application_context The application context.
* @param PaymentSource|null $payment_source The payment source.
* @param Payer|null $payer The payer.
* @param string $intent The intent.
* @param \DateTime|null $create_time The create time.
* @param \DateTime|null $update_time The update time.
*/
public function __construct(
string $id,
array $purchase_units,
OrderStatus $order_status,
ApplicationContext $application_context = null,
PaymentSource $payment_source = null,
Payer $payer = null,
string $intent = 'CAPTURE',
\DateTime $create_time = null,
\DateTime $update_time = null
) {
$this->id = $id;
$this->application_context = $application_context;
$this->purchase_units = array_values(
array_filter(
$purchase_units,
static function ( $unit ): bool {
return is_a( $unit, PurchaseUnit::class );
}
)
);
$this->payer = $payer;
$this->order_status = $order_status;
$this->intent = ( 'CAPTURE' === $intent ) ? 'CAPTURE' : 'AUTHORIZE';
$this->purchase_units = $purchase_units;
$this->create_time = $create_time;
$this->update_time = $update_time;
$this->payment_source = $payment_source;
}
/**
* Returns the ID.
*
* @return string
*/
public function id(): string {
return $this->id;
}
/**
* Returns the create time.
*
* @return \DateTime|null
*/
public function create_time(): ?\DateTime {
return $this->create_time;
}
/**
* Returns the update time.
*
* @return \DateTime|null
*/
public function udpate_time(): ?\DateTime {
return $this->update_time;
}
/**
* Returns the intent.
*
* @return string
*/
public function intent(): string {
return $this->intent;
}
/**
* Returns the payer.
*
* @return Payer|null
*/
public function payer(): ?Payer {
return $this->payer;
}
/**
* Returns the purchase units.
*
* @return PurchaseUnit[]
*/
public function purchase_units(): array {
return $this->purchase_units;
}
/**
* Returns the order status.
*
* @return OrderStatus
*/
public function status(): OrderStatus {
return $this->order_status;
}
/**
* Returns the application context.
*
* @return ApplicationContext|null
*/
public function application_context(): ?ApplicationContext {
return $this->application_context;
}
/**
* Returns the payment source.
*
* @return PaymentSource|null
*/
public function payment_source(): ?PaymentSource {
return $this->payment_source;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$order = array(
'id' => $this->id(),
'intent' => $this->intent(),
'status' => $this->status()->name(),
'purchase_units' => array_map(
static function ( PurchaseUnit $unit ): array {
return $unit->to_array();
},
$this->purchase_units()
),
);
if ( $this->create_time() ) {
$order['create_time'] = $this->create_time()->format( \DateTimeInterface::ISO8601 );
}
if ( $this->payer() ) {
$order['payer'] = $this->payer()->to_array();
}
if ( $this->udpate_time() ) {
$order['update_time'] = $this->udpate_time()->format( \DateTimeInterface::ISO8601 );
}
if ( $this->application_context() ) {
$order['application_context'] = $this->application_context()->to_array();
}
if ( $this->payment_source() ) {
$order['payment_source'] = $this->payment_source()->to_array();
}
return $order;
}
}

View file

@ -0,0 +1,89 @@
<?php
/**
* The OrderStatus object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
/**
* Class OrderStatus
*/
class OrderStatus {
public const INTERNAL = 'INTERNAL';
public const CREATED = 'CREATED';
public const SAVED = 'SAVED';
public const APPROVED = 'APPROVED';
public const VOIDED = 'VOIDED';
public const COMPLETED = 'COMPLETED';
public const VALID_STATI = array(
self::INTERNAL,
self::CREATED,
self::SAVED,
self::APPROVED,
self::VOIDED,
self::COMPLETED,
);
/**
* The status.
*
* @var string
*/
private $status;
/**
* OrderStatus constructor.
*
* @param string $status The status.
* @throws RuntimeException When the status is not valid.
*/
public function __construct( string $status ) {
if ( ! in_array( $status, self::VALID_STATI, true ) ) {
throw new RuntimeException(
sprintf(
// translators: %s is the current status.
__( '%s is not a valid status', 'woocommerce-paypal-commerce-gateway' ),
$status
)
);
}
$this->status = $status;
}
/**
* Creates an OrderStatus "Internal"
*
* @return OrderStatus
*/
public static function as_internal(): OrderStatus {
return new self( self::INTERNAL );
}
/**
* Compares the current status with a given one.
*
* @param string $status The status to compare with.
*
* @return bool
*/
public function is( string $status ): bool {
return $this->status === $status;
}
/**
* Returns the status.
*
* @return string
*/
public function name(): string {
return $this->status;
}
}

View file

@ -0,0 +1,100 @@
<?php
/**
* The Patch object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Patch
*/
class Patch {
/**
* The operation.
*
* @var string
*/
private $op;
/**
* The path to the change.
*
* @var string
*/
private $path;
/**
* The new value.
*
* @var array
*/
private $value;
/**
* Patch constructor.
*
* @param string $op The operation.
* @param string $path The path.
* @param array $value The new value.
*/
public function __construct( string $op, string $path, array $value ) {
$this->op = $op;
$this->path = $path;
$this->value = $value;
}
/**
* Returns the operation.
*
* @return string
*/
public function op(): string {
return $this->op;
}
/**
* Returns the path.
*
* @return string
*/
public function path(): string {
return $this->path;
}
/**
* Returns the value.
*
* @return array
*/
public function value() {
return $this->value;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'op' => $this->op(),
'value' => $this->value(),
'path' => $this->path(),
);
}
/**
* Needed for the move operation. We currently do not
* support the move operation.
*
* @return string
*/
public function from(): string {
return '';
}
}

View file

@ -0,0 +1,55 @@
<?php
/**
* The Patch collection object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class PatchCollection
*/
class PatchCollection {
/**
* The patches.
*
* @var Patch[]
*/
private $patches;
/**
* PatchCollection constructor.
*
* @param Patch ...$patches The patches.
*/
public function __construct( Patch ...$patches ) {
$this->patches = $patches;
}
/**
* Returns the patches.
*
* @return Patch[]
*/
public function patches(): array {
return $this->patches;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array_map(
static function ( Patch $patch ): array {
return $patch->to_array();
},
$this->patches()
);
}
}

View file

@ -0,0 +1,79 @@
<?php
/**
* The payee object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Payee
* The entity, which receives the money.
*/
class Payee {
/**
* The email address.
*
* @var string
*/
private $email;
/**
* The merchant id.
*
* @var string
*/
private $merchant_id;
/**
* Payee constructor.
*
* @param string $email The email.
* @param string $merchant_id The merchant id.
*/
public function __construct(
string $email,
string $merchant_id
) {
$this->email = $email;
$this->merchant_id = $merchant_id;
}
/**
* Returns the email.
*
* @return string
*/
public function email(): string {
return $this->email;
}
/**
* Returns the merchant id.
*
* @return string
*/
public function merchant_id(): string {
return $this->merchant_id;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$data = array(
'email_address' => $this->email(),
);
if ( $this->merchant_id ) {
$data['merchant_id'] = $this->merchant_id();
}
return $data;
}
}

View file

@ -0,0 +1,186 @@
<?php
/**
* The payer object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Payer
* The customer who sends the money.
*/
class Payer {
/**
* The name.
*
* @var PayerName
*/
private $name;
/**
* The email address.
*
* @var string
*/
private $email_address;
/**
* The payer id.
*
* @var string
*/
private $payer_id;
/**
* The birth date.
*
* @var \DateTime|null
*/
private $birthdate;
/**
* The address.
*
* @var Address
*/
private $address;
/**
* The phone.
*
* @var PhoneWithType|null
*/
private $phone;
/**
* The tax info.
*
* @var PayerTaxInfo|null
*/
private $tax_info;
/**
* Payer constructor.
*
* @param PayerName $name The name.
* @param string $email_address The email.
* @param string $payer_id The payer id.
* @param Address $address The address.
* @param \DateTime|null $birthdate The birth date.
* @param PhoneWithType|null $phone The phone.
* @param PayerTaxInfo|null $tax_info The tax info.
*/
public function __construct(
PayerName $name,
string $email_address,
string $payer_id,
Address $address,
\DateTime $birthdate = null,
PhoneWithType $phone = null,
PayerTaxInfo $tax_info = null
) {
$this->name = $name;
$this->email_address = $email_address;
$this->payer_id = $payer_id;
$this->birthdate = $birthdate;
$this->address = $address;
$this->phone = $phone;
$this->tax_info = $tax_info;
}
/**
* Returns the name.
*
* @return PayerName
*/
public function name(): PayerName {
return $this->name;
}
/**
* Returns the email address.
*
* @return string
*/
public function email_address(): string {
return $this->email_address;
}
/**
* Returns the payer id.
*
* @return string
*/
public function payer_id(): string {
return $this->payer_id;
}
/**
* Returns the birth date.
*
* @return \DateTime|null
*/
public function birthdate(): ?\DateTime {
return $this->birthdate;
}
/**
* Returns the address.
*
* @return Address
*/
public function address(): Address {
return $this->address;
}
/**
* Returns the phone.
*
* @return PhoneWithType|null
*/
public function phone(): ?PhoneWithType {
return $this->phone;
}
/**
* Returns the tax info.
*
* @return PayerTaxInfo|null
*/
public function tax_info(): ?PayerTaxInfo {
return $this->tax_info;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$payer = array(
'name' => $this->name()->to_array(),
'email_address' => $this->email_address(),
'address' => $this->address()->to_array(),
);
if ( $this->payer_id() ) {
$payer['payer_id'] = $this->payer_id();
}
if ( $this->phone() ) {
$payer['phone'] = $this->phone()->to_array();
}
if ( $this->tax_info() ) {
$payer['tax_info'] = $this->tax_info()->to_array();
}
if ( $this->birthdate() ) {
$payer['birth_date'] = $this->birthdate()->format( 'Y-m-d' );
}
return $payer;
}
}

View file

@ -0,0 +1,75 @@
<?php
/**
* The PayerName object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class PayerName
*/
class PayerName {
/**
* The given name.
*
* @var string
*/
private $given_name;
/**
* The surname.
*
* @var string
*/
private $surname;
/**
* PayerName constructor.
*
* @param string $given_name The given name.
* @param string $surname The surname.
*/
public function __construct(
string $given_name,
string $surname
) {
$this->given_name = $given_name;
$this->surname = $surname;
}
/**
* Returns the given name.
*
* @return string
*/
public function given_name(): string {
return $this->given_name;
}
/**
* Returns the surname.
*
* @return string
*/
public function surname(): string {
return $this->surname;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'given_name' => $this->given_name(),
'surname' => $this->surname(),
);
}
}

View file

@ -0,0 +1,93 @@
<?php
/**
* The PayerTaxInfo object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
/**
* Class PayerTaxInfo
*/
class PayerTaxInfo {
public const VALID_TYPES = array(
'BR_CPF',
'BR_CNPJ',
);
/**
* The tax id.
*
* @var string
*/
private $tax_id;
/**
* The type.
*
* @var string
*/
private $type;
/**
* PayerTaxInfo constructor.
*
* @param string $tax_id The tax id.
* @param string $type The type.
* @throws RuntimeException When the type is not valid.
*/
public function __construct(
string $tax_id,
string $type
) {
if ( ! in_array( $type, self::VALID_TYPES, true ) ) {
throw new RuntimeException(
sprintf(
// translators: %s is the current type.
__( '%s is not a valid tax type.', 'woocommerce-paypal-commerce-gateway' ),
$type
)
);
}
$this->tax_id = $tax_id;
$this->type = $type;
}
/**
* Returns the type.
*
* @return string
*/
public function type(): string {
return $this->type;
}
/**
* Returns the tax id
*
* @return string
*/
public function tax_id(): string {
return $this->tax_id;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'tax_id' => $this->tax_id(),
'tax_id_type' => $this->type(),
);
}
}

View file

@ -0,0 +1,81 @@
<?php
/**
* The PaymentMethod object
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class PaymentMethod
*/
class PaymentMethod {
public const PAYER_SELECTED_DEFAULT = 'PAYPAL';
public const PAYEE_PREFERRED_UNRESTRICTED = 'UNRESTRICTED';
public const PAYEE_PREFERRED_IMMEDIATE_PAYMENT_REQUIRED = 'IMMEDIATE_PAYMENT_REQUIRED';
/**
* The preferred value.
*
* @var string
*/
private $preferred;
/**
* The selected value.
*
* @var string
*/
private $selected;
/**
* PaymentMethod constructor.
*
* @param string $preferred The preferred value.
* @param string $selected The selected value.
*/
public function __construct(
string $preferred = self::PAYEE_PREFERRED_UNRESTRICTED,
string $selected = self::PAYER_SELECTED_DEFAULT
) {
$this->preferred = $preferred;
$this->selected = $selected;
}
/**
* Returns the payer preferred value.
*
* @return string
*/
public function payee_preferred(): string {
return $this->preferred;
}
/**
* Returns the payer selected value.
*
* @return string
*/
public function payer_selected(): string {
return $this->selected;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'payee_preferred' => $this->payee_preferred(),
'payer_selected' => $this->payer_selected(),
);
}
}

View file

@ -0,0 +1,57 @@
<?php
/**
* The Payments object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Payments
*/
class Payments {
/**
* The Authorizations.
*
* @var Authorization[]
*/
private $authorizations;
/**
* Payments constructor.
*
* @param Authorization ...$authorizations The Authorizations.
*/
public function __construct( Authorization ...$authorizations ) {
$this->authorizations = $authorizations;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'authorizations' => array_map(
static function ( Authorization $authorization ): array {
return $authorization->to_array();
},
$this->authorizations()
),
);
}
/**
* Returns the Authoriatzions.
*
* @return Authorization[]
**/
public function authorizations(): array {
return $this->authorizations;
}
}

View file

@ -0,0 +1,82 @@
<?php
/**
* The PaymentSource object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class PaymentSource
*/
class PaymentSource {
/**
* The card.
*
* @var PaymentSourceCard|null
*/
private $card;
/**
* The wallet.
*
* @var PaymentSourceWallet|null
*/
private $wallet;
/**
* PaymentSource constructor.
*
* @param PaymentSourceCard|null $card The card.
* @param PaymentSourceWallet|null $wallet The wallet.
*/
public function __construct(
PaymentSourceCard $card = null,
PaymentSourceWallet $wallet = null
) {
$this->card = $card;
$this->wallet = $wallet;
}
/**
* Returns the card.
*
* @return PaymentSourceCard|null
*/
public function card(): ?PaymentSourceCard {
return $this->card;
}
/**
* Returns the wallet.
*
* @return PaymentSourceWallet|null
*/
public function wallet(): ?PaymentSourceWallet {
return $this->wallet;
}
/**
* Returns the array of the object.
*
* @return array
*/
public function to_array(): array {
$data = array();
if ( $this->card() ) {
$data['card'] = $this->card()->to_array();
}
if ( $this->wallet() ) {
$data['wallet'] = $this->wallet()->to_array();
}
return $data;
}
}

View file

@ -0,0 +1,123 @@
<?php
/**
* The PaymentSourceCard object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class PaymentSourceCard
*/
class PaymentSourceCard {
/**
* The last digits of the card.
*
* @var string
*/
private $last_digits;
/**
* The brand.
*
* @var string
*/
private $brand;
/**
* The type.
*
* @var string
*/
private $type;
/**
* The authentication result.
*
* @var CardAuthenticationResult|null
*/
private $authentication_result;
/**
* PaymentSourceCard constructor.
*
* @param string $last_digits The last digits of the card.
* @param string $brand The brand of the card.
* @param string $type The type of the card.
* @param CardAuthenticationResult|null $authentication_result The authentication result.
*/
public function __construct(
string $last_digits,
string $brand,
string $type,
CardAuthenticationResult $authentication_result = null
) {
$this->last_digits = $last_digits;
$this->brand = $brand;
$this->type = $type;
$this->authentication_result = $authentication_result;
}
/**
* Returns the last digits.
*
* @return string
*/
public function last_digits(): string {
return $this->last_digits;
}
/**
* Returns the brand.
*
* @return string
*/
public function brand(): string {
return $this->brand;
}
/**
* Returns the type.
*
* @return string
*/
public function type(): string {
return $this->type;
}
/**
* Returns the authentication result.
*
* @return CardAuthenticationResult|null
*/
public function authentication_result(): ?CardAuthenticationResult {
return $this->authentication_result;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$data = array(
'last_digits' => $this->last_digits(),
'brand' => $this->brand(),
'type' => $this->type(),
);
if ( $this->authentication_result() ) {
$data['authentication_result'] = $this->authentication_result()->to_array();
}
return $data;
}
}

View file

@ -0,0 +1,25 @@
<?php
/**
* The PaymentSourcewallet.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class PaymentSourceWallet
*/
class PaymentSourceWallet {
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array();
}
}

View file

@ -0,0 +1,85 @@
<?php
/**
* The PaymentToken object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
/**
* Class PaymentToken
*/
class PaymentToken {
public const TYPE_PAYMENT_METHOD_TOKEN = 'PAYMENT_METHOD_TOKEN';
public const VALID_TYPES = array(
self::TYPE_PAYMENT_METHOD_TOKEN,
);
/**
* The Id.
*
* @var string
*/
private $id;
/**
* The type.
*
* @var string
*/
private $type;
/**
* PaymentToken constructor.
*
* @param string $id The Id.
* @param string $type The type.
* @throws RuntimeException When the type is not valid.
*/
public function __construct( string $id, string $type = self::TYPE_PAYMENT_METHOD_TOKEN ) {
if ( ! in_array( $type, self::VALID_TYPES, true ) ) {
throw new RuntimeException(
__( 'Not a valid payment source type.', 'woocommerce-paypal-commerce-gateway' )
);
}
$this->id = $id;
$this->type = $type;
}
/**
* Returns the ID.
*
* @return string
*/
public function id(): string {
return $this->id;
}
/**
* Returns the type.
*
* @return string
*/
public function type(): string {
return $this->type;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'id' => $this->id(),
'type' => $this->type(),
);
}
}

View file

@ -0,0 +1,52 @@
<?php
/**
* The Phone object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Phone
*/
class Phone {
/**
* The number.
*
* @var string
*/
private $national_number;
/**
* Phone constructor.
*
* @param string $national_number The number.
*/
public function __construct( string $national_number ) {
$this->national_number = $national_number;
}
/**
* Returns the number.
*
* @return string
*/
public function national_number(): string {
return $this->national_number;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'national_number' => $this->national_number(),
);
}
}

View file

@ -0,0 +1,79 @@
<?php
/**
* The PhoneWithType object
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class PhoneWithType
*/
class PhoneWithType {
public const VALLID_TYPES = array(
'FAX',
'HOME',
'MOBILE',
'OTHER',
'PAGER',
);
/**
* The type.
*
* @var string
*/
private $type;
/**
* The phone.
*
* @var Phone
*/
private $phone;
/**
* PhoneWithType constructor.
*
* @param string $type The type.
* @param Phone $phone The phone.
*/
public function __construct( string $type, Phone $phone ) {
$this->type = in_array( $type, self::VALLID_TYPES, true ) ? $type : 'OTHER';
$this->phone = $phone;
}
/**
* Returns the type.
*
* @return string
*/
public function type(): string {
return $this->type;
}
/**
* Returns the phone.
*
* @return Phone
*/
public function phone(): Phone {
return $this->phone;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'phone_type' => $this->type(),
'phone_number' => $this->phone()->to_array(),
);
}
}

View file

@ -0,0 +1,358 @@
<?php
/**
* The purchase unit object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class PurchaseUnit
*/
class PurchaseUnit {
/**
* The amount.
*
* @var Amount
*/
private $amount;
/**
* The Items.
*
* @var Item[]
*/
private $items;
/**
* The shipping.
*
* @var Shipping|null
*/
private $shipping;
/**
* The reference id.
*
* @var string
*/
private $reference_id;
/**
* The description.
*
* @var string
*/
private $description;
/**
* The Payee.
*
* @var Payee|null
*/
private $payee;
/**
* The custom id.
*
* @var string
*/
private $custom_id;
/**
* The invoice id.
*
* @var string
*/
private $invoice_id;
/**
* The soft descriptor.
*
* @var string
*/
private $soft_descriptor;
/**
* The Payments.
*
* @var Payments|null
*/
private $payments;
/**
* Whether the unit contains physical goods.
*
* @var bool
*/
private $contains_physical_goods = false;
/**
* PurchaseUnit constructor.
*
* @param Amount $amount The Amount.
* @param Item[] $items The Items.
* @param Shipping|null $shipping The Shipping.
* @param string $reference_id The reference ID.
* @param string $description The description.
* @param Payee|null $payee The Payee.
* @param string $custom_id The custom ID.
* @param string $invoice_id The invoice ID.
* @param string $soft_descriptor The soft descriptor.
* @param Payments|null $payments The Payments.
*/
public function __construct(
Amount $amount,
array $items = array(),
Shipping $shipping = null,
string $reference_id = 'default',
string $description = '',
Payee $payee = null,
string $custom_id = '',
string $invoice_id = '',
string $soft_descriptor = '',
Payments $payments = null
) {
$this->amount = $amount;
$this->shipping = $shipping;
$this->reference_id = $reference_id;
$this->description = $description;
//phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration.NoArgumentType
$this->items = array_values(
array_filter(
$items,
function ( $item ): bool {
$is_item = is_a( $item, Item::class );
/**
* The item.
*
* @var Item $item
*/
if ( $is_item && Item::PHYSICAL_GOODS === $item->category() ) {
$this->contains_physical_goods = true;
}
return $is_item;
}
)
);
$this->payee = $payee;
$this->custom_id = $custom_id;
$this->invoice_id = $invoice_id;
$this->soft_descriptor = $soft_descriptor;
$this->payments = $payments;
}
/**
* Returns the amount.
*
* @return Amount
*/
public function amount(): Amount {
return $this->amount;
}
/**
* Returns the shipping.
*
* @return Shipping|null
*/
public function shipping(): ?Shipping {
return $this->shipping;
}
/**
* Returns the reference id.
*
* @return string
*/
public function reference_id(): string {
return $this->reference_id;
}
/**
* Returns the description.
*
* @return string
*/
public function description(): string {
return $this->description;
}
/**
* Returns the custom id.
*
* @return string
*/
public function custom_id(): string {
return $this->custom_id;
}
/**
* Returns the invoice id.
*
* @return string
*/
public function invoice_id(): string {
return $this->invoice_id;
}
/**
* Returns the soft descriptor.
*
* @return string
*/
public function soft_descriptor(): string {
return $this->soft_descriptor;
}
/**
* Returns the Payee.
*
* @return Payee|null
*/
public function payee(): ?Payee {
return $this->payee;
}
/**
* Returns the Payments.
*
* @return Payments|null
*/
public function payments(): ?Payments {
return $this->payments;
}
/**
* Returns the Items.
*
* @return Item[]
*/
public function items(): array {
return $this->items;
}
/**
* Whether the unit contains physical goods.
*
* @return bool
*/
public function contains_physical_goods(): bool {
return $this->contains_physical_goods;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$purchase_unit = array(
'reference_id' => $this->reference_id(),
'amount' => $this->amount()->to_array(),
'description' => $this->description(),
'items' => array_map(
static function ( Item $item ): array {
return $item->to_array();
},
$this->items()
),
);
if ( $this->ditch_items_when_mismatch( $this->amount(), ...$this->items() ) ) {
unset( $purchase_unit['items'] );
unset( $purchase_unit['amount']['breakdown'] );
}
if ( $this->payee() ) {
$purchase_unit['payee'] = $this->payee()->to_array();
}
if ( $this->payments() ) {
$purchase_unit['payments'] = $this->payments()->to_array();
}
if ( $this->shipping() ) {
$purchase_unit['shipping'] = $this->shipping()->to_array();
}
if ( $this->custom_id() ) {
$purchase_unit['custom_id'] = $this->custom_id();
}
if ( $this->invoice_id() ) {
$purchase_unit['invoice_id'] = $this->invoice_id();
}
if ( $this->soft_descriptor() ) {
$purchase_unit['soft_descriptor'] = $this->soft_descriptor();
}
return $purchase_unit;
}
/**
* All money values send to PayPal can only have 2 decimal points. Woocommerce internally does
* not have this restriction. Therefore the totals of the cart in Woocommerce and the totals
* of the rounded money values of the items, we send to PayPal, can differ. In those cases,
* we can not send the line items.
*
* @param Amount $amount The amount.
* @param Item ...$items The items.
* @return bool
*/
private function ditch_items_when_mismatch( Amount $amount, Item ...$items ): bool {
$fee_items_total = ( $amount->breakdown() && $amount->breakdown()->item_total() ) ?
$amount->breakdown()->item_total()->value() : null;
$fee_tax_total = ( $amount->breakdown() && $amount->breakdown()->tax_total() ) ?
$amount->breakdown()->tax_total()->value() : null;
foreach ( $items as $item ) {
if ( null !== $fee_items_total ) {
$fee_items_total -= $item->unit_amount()->value() * $item->quantity();
}
if ( null !== $fee_tax_total ) {
$fee_tax_total -= $item->tax()->value() * $item->quantity();
}
}
$fee_items_total = round( $fee_items_total, 2 );
$fee_tax_total = round( $fee_tax_total, 2 );
if ( 0.0 !== $fee_items_total || 0.0 !== $fee_tax_total ) {
return true;
}
$breakdown = $this->amount()->breakdown();
if ( ! $breakdown ) {
return false;
}
$amount_total = 0;
if ( $breakdown->shipping() ) {
$amount_total += $breakdown->shipping()->value();
}
if ( $breakdown->item_total() ) {
$amount_total += $breakdown->item_total()->value();
}
if ( $breakdown->discount() ) {
$amount_total -= $breakdown->discount()->value();
}
if ( $breakdown->tax_total() ) {
$amount_total += $breakdown->tax_total()->value();
}
if ( $breakdown->shipping_discount() ) {
$amount_total -= $breakdown->shipping_discount()->value();
}
if ( $breakdown->handling() ) {
$amount_total += $breakdown->handling()->value();
}
if ( $breakdown->insurance() ) {
$amount_total += $breakdown->insurance()->value();
}
$amount_value = $this->amount()->value();
$needs_to_ditch = (string) $amount_total !== (string) $amount_value;
return $needs_to_ditch;
}
}

View file

@ -0,0 +1,73 @@
<?php
/**
* The Shipping object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Shipping
*/
class Shipping {
/**
* The name.
*
* @var string
*/
private $name;
/**
* The address.
*
* @var Address
*/
private $address;
/**
* Shipping constructor.
*
* @param string $name The name.
* @param Address $address The address.
*/
public function __construct( string $name, Address $address ) {
$this->name = $name;
$this->address = $address;
}
/**
* Returns the name.
*
* @return string
*/
public function name(): string {
return $this->name;
}
/**
* Returns the shipping address.
*
* @return Address
*/
public function address(): Address {
return $this->address;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
return array(
'name' => array(
'full_name' => $this->name(),
),
'address' => $this->address()->to_array(),
);
}
}

View file

@ -0,0 +1,123 @@
<?php
/**
* The Token object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
/**
* Class Token
*/
class Token {
/**
* The Token data.
*
* @var \stdClass
*/
private $json;
/**
* The timestamp when the Token was created.
*
* @var int
*/
private $created;
/**
* Token constructor.
*
* @param \stdClass $json The JSON object.
* @throws RuntimeException When The JSON object is not valid.
*/
public function __construct( \stdClass $json ) {
if ( ! isset( $json->created ) ) {
$json->created = time();
}
if ( ! $this->validate( $json ) ) {
throw new RuntimeException( 'Token not valid' );
}
$this->json = $json;
}
/**
* Returns the timestamp when the Token is expired.
*
* @return int
*/
public function expiration_timestamp(): int {
return $this->json->created + $this->json->expires_in;
}
/**
* Returns the token.
*
* @return string
*/
public function token(): string {
return (string) $this->json->token;
}
/**
* Returns whether the Token is still valid.
*
* @return bool
*/
public function is_valid(): bool {
return time() < $this->json->created + $this->json->expires_in;
}
/**
* Returns the Token as JSON string.
*
* @return string
*/
public function as_json(): string {
return wp_json_encode( $this->json );
}
/**
* Returns a Token based off a JSON string.
*
* @param string $json The JSON string.
*
* @return static
*/
public static function from_json( string $json ): self {
$json = (object) json_decode( $json );
if ( isset( $json->access_token ) || isset( $json->client_token ) ) {
$json->token = isset( $json->access_token ) ? $json->access_token : $json->client_token;
}
return new Token( $json );
}
/**
* Validates whether a JSON object can be transformed to a Token object.
*
* @param \stdClass $json The JSON object.
*
* @return bool
*/
private function validate( \stdClass $json ): bool {
$property_map = array(
'created' => 'is_int',
'expires_in' => 'is_int',
'token' => 'is_string',
);
foreach ( $property_map as $property => $validator ) {
if ( ! isset( $json->{$property} ) || ! $validator( $json->{$property} ) ) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,97 @@
<?php
/**
* The Webhook object.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Entity
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
/**
* Class Webhook
*/
class Webhook {
/**
* The ID of the webhook.
*
* @var string
*/
private $id;
/**
* The URL of the webhook.
*
* @var string
*/
private $url;
/**
* The event types.
*
* @var string[]
*/
private $event_types;
/**
* Webhook constructor.
*
* @param string $url The URL of the webhook.
* @param string[] $event_types The associated event types.
* @param string $id The id of the webhook.
*/
public function __construct( string $url, array $event_types, string $id = '' ) {
$this->url = $url;
$this->event_types = $event_types;
$this->id = $id;
}
/**
* Returns the id of the webhook.
*
* @return string
*/
public function id(): string {
return $this->id;
}
/**
* Returns the URL listening to the hook.
*
* @return string
*/
public function url(): string {
return $this->url;
}
/**
* Returns the event types.
*
* @return array
*/
public function event_types(): array {
return $this->event_types;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array(): array {
$data = array(
'url' => $this->url(),
'event_types' => $this->event_types(),
);
if ( $this->id() ) {
$data['id'] = $this->id();
}
return $data;
}
}

View file

@ -1,66 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Exception;
class PayPalApiException extends RuntimeException
{
private $response;
private $statusCode;
public function __construct(\stdClass $response = null, int $statusCode = 0)
{
if (is_null($response)) {
$response = new \stdClass();
}
if (! isset($response->message)) {
$response->message = __(
'Unknown error while connecting to PayPal.',
'woocommerce-paypal-commerce-gateway'
);
}
if (! isset($response->name)) {
$response->name = __('Error', 'woocommerce-paypal-commerce-gateway');
}
if (! isset($response->details)) {
$response->details = [];
}
if (! isset($response->links) || ! is_array($response->links)) {
$response->links = [];
}
$this->response = $response;
$this->statusCode = $statusCode;
$message = $response->message;
if ($response->name) {
$message = '[' . $response->name . '] ' . $message;
}
foreach ($response->links as $link) {
if (isset($link->rel) && $link->rel === 'information_link') {
$message .= ' ' . $link->href;
}
}
parent::__construct($message, $statusCode);
}
public function name(): string
{
return $this->response->name;
}
public function details(): array
{
return $this->response->details;
}
public function hasDetail(string $issue): bool
{
foreach ($this->details() as $detail) {
if (isset($detail->issue) && $detail->issue === $issue) {
return true;
}
}
return false;
}
}

View file

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Exception;
class RuntimeException extends \RuntimeException
{
}

View file

@ -1,4 +1,9 @@
<?php
/**
* The modules Not Found exception.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Exception
*/
declare(strict_types=1);
@ -7,7 +12,10 @@ namespace Inpsyde\PayPalCommerce\ApiClient\Exception;
use Psr\Container\NotFoundExceptionInterface;
use Exception;
class NotFoundException extends Exception implements NotFoundExceptionInterface
{
/**
* Class NotFoundException
*/
class NotFoundException extends Exception implements NotFoundExceptionInterface {
}

View file

@ -0,0 +1,109 @@
<?php
/**
* The PayPal API Exception.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Exception
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Exception;
/**
* Class PayPalApiException
*/
class PayPalApiException extends RuntimeException {
/**
* The JSON response object of PayPal.
*
* @var \stdClass
*/
private $response;
/**
* The HTTP status code of the PayPal response.
*
* @var int
*/
private $status_code;
/**
* PayPalApiException constructor.
*
* @param \stdClass|null $response The JSON object.
* @param int $status_code The HTTP status code.
*/
public function __construct( \stdClass $response = null, int $status_code = 0 ) {
if ( is_null( $response ) ) {
$response = new \stdClass();
}
if ( ! isset( $response->message ) ) {
$response->message = __(
'Unknown error while connecting to PayPal.',
'woocommerce-paypal-commerce-gateway'
);
}
if ( ! isset( $response->name ) ) {
$response->name = __( 'Error', 'woocommerce-paypal-commerce-gateway' );
}
if ( ! isset( $response->details ) ) {
$response->details = array();
}
if ( ! isset( $response->links ) || ! is_array( $response->links ) ) {
$response->links = array();
}
/**
* The JSON response object.
*
* @var \stdClass $response
*/
$this->response = $response;
$this->status_code = $status_code;
$message = $response->message;
if ( $response->name ) {
$message = '[' . $response->name . '] ' . $message;
}
foreach ( $response->links as $link ) {
if ( isset( $link->rel ) && 'information_link' === $link->rel ) {
$message .= ' ' . $link->href;
}
}
parent::__construct( $message, $status_code );
}
/**
* The name of the exception.
*
* @return string
*/
public function name(): string {
return $this->response->name;
}
/**
* The details of the Exception.
*
* @return array
*/
public function details(): array {
return $this->response->details;
}
/**
* Whether a certain detail is part of the exception reason.
*
* @param string $issue The issue.
*
* @return bool
*/
public function has_detail( string $issue ): bool {
foreach ( $this->details() as $detail ) {
if ( isset( $detail->issue ) && $detail->issue === $issue ) {
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,18 @@
<?php
/**
* The modules runtime exception.
*
* @package Inpsyde\PayPalCommerce\ApiClient\Exception
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Exception;
/**
* Class RuntimeException
*/
class RuntimeException extends \RuntimeException {
}

View file

@ -1,63 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Address;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class AddressFactory
{
public function __construct()
{
}
public function fromWcCustomer(\WC_Customer $customer, string $type = 'shipping'): Address
{
return new Address(
($type === 'shipping') ?
$customer->get_shipping_country() : $customer->get_billing_country(),
($type === 'shipping') ?
$customer->get_shipping_address_1() : $customer->get_billing_address_1(),
($type === 'shipping') ?
$customer->get_shipping_address_2() : $customer->get_billing_address_2(),
($type === 'shipping') ?
$customer->get_shipping_state() : $customer->get_billing_state(),
($type === 'shipping') ?
$customer->get_shipping_city() : $customer->get_billing_city(),
($type === 'shipping') ?
$customer->get_shipping_postcode() : $customer->get_billing_postcode(),
);
}
public function fromWcOrder(\WC_Order $order): Address
{
return new Address(
$order->get_shipping_country(),
$order->get_shipping_address_1(),
$order->get_shipping_address_2(),
$order->get_shipping_state(),
$order->get_shipping_city(),
$order->get_shipping_postcode()
);
}
public function fromPayPalRequest(\stdClass $data): Address
{
if (! isset($data->country_code)) {
throw new RuntimeException(
__('No country given for address.', 'woocommerce-paypal-commerce-gateway')
);
}
return new Address(
$data->country_code,
(isset($data->address_line_1)) ? $data->address_line_1 : '',
(isset($data->address_line_2)) ? $data->address_line_2 : '',
(isset($data->admin_area_1)) ? $data->admin_area_1 : '',
(isset($data->admin_area_2)) ? $data->admin_area_2 : '',
(isset($data->postal_code)) ? $data->postal_code : ''
);
}
}

View file

@ -1,169 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Amount;
use Inpsyde\PayPalCommerce\ApiClient\Entity\AmountBreakdown;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Item;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Money;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class AmountFactory
{
private $itemFactory;
public function __construct(ItemFactory $itemFactory)
{
$this->itemFactory = $itemFactory;
}
public function fromWcCart(\WC_Cart $cart): Amount
{
$currency = get_woocommerce_currency();
$total = new Money((float) $cart->get_total('numeric'), $currency);
$itemsTotal = $cart->get_cart_contents_total() + $cart->get_discount_total();
$itemsTotal = new Money((float) $itemsTotal, $currency);
$shipping = new Money(
(float) $cart->get_shipping_total() + $cart->get_shipping_tax(),
$currency
);
$taxes = new Money(
(float) $cart->get_cart_contents_tax() + (float) $cart->get_discount_tax(),
$currency
);
$discount = null;
if ($cart->get_discount_total()) {
$discount = new Money(
(float) $cart->get_discount_total() + $cart->get_discount_tax(),
$currency
);
}
//ToDo: Evaluate if more is needed? Fees?
$breakdown = new AmountBreakdown(
$itemsTotal,
$shipping,
$taxes,
null, // insurance?
null, // handling?
null, //shipping discounts?
$discount
);
$amount = new Amount(
$total,
$breakdown
);
return $amount;
}
public function fromWcOrder(\WC_Order $order): Amount
{
$currency = $order->get_currency();
$items = $this->itemFactory->fromWcOrder($order);
$total = new Money((float) $order->get_total(), $currency);
$itemsTotal = new Money((float)array_reduce(
$items,
static function (float $total, Item $item): float {
return $total + $item->quantity() * $item->unitAmount()->value();
},
0
), $currency);
$shipping = new Money(
(float) $order->get_shipping_total() + (float) $order->get_shipping_tax(),
$currency
);
$taxes = new Money((float)array_reduce(
$items,
static function (float $total, Item $item): float {
return $total + $item->quantity() * $item->tax()->value();
},
0
), $currency);
$discount = null;
if ((float) $order->get_total_discount(false)) {
$discount = new Money(
(float) $order->get_total_discount(false),
$currency
);
}
//ToDo: Evaluate if more is needed? Fees?
$breakdown = new AmountBreakdown(
$itemsTotal,
$shipping,
$taxes,
null, // insurance?
null, // handling?
null, //shipping discounts?
$discount
);
$amount = new Amount(
$total,
$breakdown
);
return $amount;
}
public function fromPayPalResponse(\stdClass $data): Amount
{
if (! isset($data->value) || ! is_numeric($data->value)) {
throw new RuntimeException(__("No value given", "woocommerce-paypal-commerce-gateway"));
}
if (! isset($data->currency_code)) {
throw new RuntimeException(
__("No currency given", "woocommerce-paypal-commerce-gateway")
);
}
$money = new Money((float) $data->value, $data->currency_code);
$breakdown = (isset($data->breakdown)) ? $this->breakdown($data->breakdown) : null;
return new Amount($money, $breakdown);
}
private function breakDown(\stdClass $data): AmountBreakdown
{
/**
* The order of the keys equals the necessary order of the constructor arguments.
*/
$orderedConstructorKeys = [
'item_total',
'shipping',
'tax_total',
'handling',
'insurance',
'shipping_discount',
'discount',
];
$money = [];
foreach ($orderedConstructorKeys as $key) {
if (! isset($data->{$key})) {
$money[] = null;
continue;
}
$item = $data->{$key};
if (! isset($item->value) || ! is_numeric($item->value)) {
throw new RuntimeException(sprintf(
// translators: %s is the current breakdown key.
__("No value given for breakdown %s", "woocommerce-paypal-commerce-gateway"),
$key
));
}
if (! isset($item->currency_code)) {
throw new RuntimeException(sprintf(
// translators: %s is the current breakdown key.
__("No currency given for breakdown %s", "woocommerce-paypal-commerce-gateway"),
$key
));
}
$money[] = new Money((float) $item->value, $item->currency_code);
}
return new AmountBreakdown(...$money);
}
}

View file

@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\ApplicationContext;
class ApplicationContextFactory
{
public function fromPayPalResponse(\stdClass $data): ApplicationContext
{
return new ApplicationContext(
isset($data->return_url) ?
$data->return_url : '',
isset($data->cancel_url) ?
$data->cancel_url : '',
isset($data->brand_name) ?
$data->brand_name : '',
isset($data->locale) ?
$data->locale : '',
isset($data->landing_page) ?
$data->landing_page : ApplicationContext::LANDING_PAGE_NO_PREFERENCE,
isset($data->shipping_preference) ?
$data->shipping_preference : ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
isset($data->user_action) ?
$data->user_action : ApplicationContext::USER_ACTION_CONTINUE,
);
}
}

View file

@ -1,32 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class AuthorizationFactory
{
public function fromPayPalRequest(\stdClass $data): Authorization
{
if (!isset($data->id)) {
throw new RuntimeException(
__('Does not contain an id.', 'woocommerce-paypal-commerce-gateway')
);
}
if (!isset($data->status)) {
throw new RuntimeException(
__('Does not contain status.', 'woocommerce-paypal-commerce-gateway')
);
}
return new Authorization(
$data->id,
new AuthorizationStatus($data->status)
);
}
}

View file

@ -1,124 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Item;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Money;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class ItemFactory
{
public function __construct()
{
}
public function fromWcCart(\WC_Cart $cart): array
{
$currency = get_woocommerce_currency();
$items = array_map(
static function (array $item) use ($currency): Item {
$product = $item['data'];
/**
* @var \WC_Product $product
*/
$quantity = (int) $item['quantity'];
$price = (float) wc_get_price_including_tax($product);
$priceWithoutTax = (float) wc_get_price_excluding_tax($product);
$priceWithoutTaxRounded = round($priceWithoutTax, 2);
$tax = round($price - $priceWithoutTaxRounded, 2);
$tax = new Money($tax, $currency);
return new Item(
mb_substr($product->get_name(), 0, 127),
new Money($priceWithoutTaxRounded, $currency),
$quantity,
mb_substr($product->get_description(), 0, 127),
$tax,
$product->get_sku(),
($product->is_virtual()) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
);
},
$cart->get_cart_contents()
);
return $items;
}
/**
* @param \WC_Order $order
* @return Item[]
*/
public function fromWcOrder(\WC_Order $order): array
{
return array_map(
function (\WC_Order_Item_Product $item) use ($order): Item {
return $this->fromWcOrderLineItem($item, $order);
},
$order->get_items('line_item')
);
}
private function fromWcOrderLineItem(\WC_Order_Item_Product $item, \WC_Order $order): Item
{
$currency = $order->get_currency();
$product = $item->get_product();
/**
* @var \WC_Product $product
*/
$quantity = $item->get_quantity();
$price = (float) $order->get_item_subtotal($item, true);
$priceWithoutTax = (float) $order->get_item_subtotal($item, false);
$priceWithoutTaxRounded = round($priceWithoutTax, 2);
$tax = round($price - $priceWithoutTaxRounded, 2);
$tax = new Money($tax, $currency);
return new Item(
mb_substr($product->get_name(), 0, 127),
new Money($priceWithoutTaxRounded, $currency),
$quantity,
mb_substr($product->get_description(), 0, 127),
$tax,
$product->get_sku(),
($product->is_virtual()) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
);
}
public function fromPayPalResponse(\stdClass $data): Item
{
if (! isset($data->name)) {
throw new RuntimeException(
__("No name for item given", "woocommerce-paypal-commerce-gateway")
);
}
if (! isset($data->quantity) || ! is_numeric($data->quantity)) {
throw new RuntimeException(
__("No quantity for item given", "woocommerce-paypal-commerce-gateway")
);
}
if (! isset($data->unit_amount->value) || ! isset($data->unit_amount->currency_code)) {
throw new RuntimeException(
__("No money values for item given", "woocommerce-paypal-commerce-gateway")
);
}
$unitAmount = new Money((float) $data->unit_amount->value, $data->unit_amount->currency_code);
$description = (isset($data->description)) ? $data->description : '';
$tax = (isset($data->tax)) ?
new Money((float) $data->tax->value, $data->tax->currency_code)
: null;
$sku = (isset($data->sku)) ? $data->sku : '';
$category = (isset($data->category)) ? $data->category : 'PHYSICAL_GOODS';
return new Item(
$data->name,
$unitAmount,
(int) $data->quantity,
$description,
$tax,
$sku,
$category
);
}
}

View file

@ -1,113 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
class OrderFactory
{
private $purchaseUnitFactory;
private $payerFactory;
private $applicationContextRepository;
private $applicationContextFactory;
private $paymentSourceFactory;
public function __construct(
PurchaseUnitFactory $purchaseUnitFactory,
PayerFactory $payerFactory,
ApplicationContextRepository $applicationContextRepository,
ApplicationContextFactory $applicationContextFactory,
PaymentSourceFactory $paymentSourceFactory
) {
$this->purchaseUnitFactory = $purchaseUnitFactory;
$this->payerFactory = $payerFactory;
$this->applicationContextRepository = $applicationContextRepository;
$this->applicationContextFactory = $applicationContextFactory;
$this->paymentSourceFactory = $paymentSourceFactory;
}
public function fromWcOrder(\WC_Order $wcOrder, Order $order): Order
{
$purchaseUnits = [$this->purchaseUnitFactory->fromWcOrder($wcOrder)];
return new Order(
$order->id(),
$purchaseUnits,
$order->status(),
$order->applicationContext(),
$order->paymentSource(),
$order->payer(),
$order->intent(),
$order->createTime(),
$order->updateTime()
);
}
// phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
public function fromPayPalResponse(\stdClass $orderData): Order
{
if (! isset($orderData->id)) {
throw new RuntimeException(
__('Order does not contain an id.', 'woocommerce-paypal-commerce-gateway')
);
}
if (! isset($orderData->purchase_units) || !is_array($orderData->purchase_units)) {
throw new RuntimeException(
__('Order does not contain items.', 'woocommerce-paypal-commerce-gateway')
);
}
if (! isset($orderData->status)) {
throw new RuntimeException(
__('Order does not contain status.', 'woocommerce-paypal-commerce-gateway')
);
}
if (! isset($orderData->intent)) {
throw new RuntimeException(
__('Order does not contain intent.', 'woocommerce-paypal-commerce-gateway')
);
}
$purchaseUnits = array_map(
function (\stdClass $data): PurchaseUnit {
return $this->purchaseUnitFactory->fromPayPalResponse($data);
},
$orderData->purchase_units
);
$createTime = (isset($orderData->create_time)) ?
\DateTime::createFromFormat(\DateTime::ISO8601, $orderData->create_time)
: null;
$updateTime = (isset($orderData->update_time)) ?
\DateTime::createFromFormat(\DateTime::ISO8601, $orderData->update_time)
: null;
$payer = (isset($orderData->payer)) ?
$this->payerFactory->fromPayPalResponse($orderData->payer)
: null;
$applicationContext = (isset($orderData->application_context)) ?
$this->applicationContextFactory->fromPayPalResponse($orderData->application_context)
: null;
$paymentSource = (isset($orderData->payment_source)) ?
$this->paymentSourceFactory->fromPayPalResponse($orderData->payment_source) :
null;
return new Order(
$orderData->id,
$purchaseUnits,
new OrderStatus($orderData->status),
$applicationContext,
$paymentSource,
$payer,
$orderData->intent,
$createTime,
$updateTime
);
}
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
}

View file

@ -1,66 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Patch;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PatchCollection;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
class PatchCollectionFactory
{
public function fromOrders(Order $from, Order $to): PatchCollection
{
$allPatches = [];
$allPatches += $this->purchaseUnits($from->purchaseUnits(), $to->purchaseUnits());
return new PatchCollection(...$allPatches);
}
/**
* @param PurchaseUnit[] $from
* @param PurchaseUnit[] $to
* @return Patch[]
*/
private function purchaseUnits(array $from, array $to): array
{
$patches = [];
$path = '/purchase_units';
foreach ($to as $purchaseUnitTo) {
$needsUpdate = ! count(
array_filter(
$from,
static function (PurchaseUnit $unit) use ($purchaseUnitTo): bool {
//phpcs:disable WordPress.PHP.StrictComparisons.LooseComparison
// Loose comparison needed to compare two objects.
return $unit == $purchaseUnitTo;
//phpcs:enable WordPress.PHP.StrictComparisons.LooseComparison
}
)
);
$needsUpdate = true;
if (!$needsUpdate) {
continue;
}
$purchaseUnitFrom = current(array_filter(
$from,
static function (PurchaseUnit $unit) use ($purchaseUnitTo): bool {
return $purchaseUnitTo->referenceId() === $unit->referenceId();
}
));
$operation = $purchaseUnitFrom ? 'replace' : 'add';
$value = $purchaseUnitTo->toArray();
$patches[] = new Patch(
$operation,
$path . "/@reference_id=='" . $purchaseUnitTo->referenceId() . "'",
$value
);
}
return $patches;
}
}

View file

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Payee;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class PayeeFactory
{
public function fromPayPalResponse(\stdClass $data): ?Payee
{
if (! isset($data->email_address)) {
throw new RuntimeException(
__("No email for payee given.", "woocommerce-paypal-commerce-gateway")
);
}
$merchantId = (isset($data->merchant_id)) ? $data->merchant_id : '';
return new Payee($data->email_address, $merchantId);
}
}

View file

@ -1,82 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Payer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PayerName;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PayerTaxInfo;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Phone;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PhoneWithType;
class PayerFactory
{
private $addressFactory;
public function __construct(AddressFactory $addressFactory)
{
$this->addressFactory = $addressFactory;
}
public function fromCustomer(\WC_Customer $customer): Payer
{
$payerId = '';
$birthdate = null;
$phone = null;
if ($customer->get_billing_phone()) {
// make sure the phone number contains only numbers and is max 14. chars long.
$nationalNumber = $customer->get_billing_phone();
$nationalNumber = preg_replace("/[^0-9]/", "", $nationalNumber);
$nationalNumber = substr($nationalNumber, 0, 14);
$phone = new PhoneWithType(
'HOME',
new Phone($nationalNumber)
);
}
return new Payer(
new PayerName(
$customer->get_billing_first_name(),
$customer->get_billing_last_name()
),
$customer->get_billing_email(),
$payerId,
$this->addressFactory->fromWcCustomer($customer, 'billing'),
$birthdate,
$phone
);
}
public function fromPayPalResponse(\stdClass $data): Payer
{
$address = $this->addressFactory->fromPayPalRequest($data->address);
$payerName = new PayerName(
isset($data->name->given_name) ? (string) $data->name->given_name : '',
isset($data->name->surname) ? (string) $data->name->surname : ''
);
// TODO deal with phones without type instead of passing a invalid type
$phone = (isset($data->phone)) ? new PhoneWithType(
(isset($data->phone->phone_type)) ? $data->phone->phone_type : 'undefined',
new Phone(
$data->phone->phone_number->national_number
)
) : null;
$taxInfo = (isset($data->tax_info)) ?
new PayerTaxInfo($data->tax_info->tax_id, $data->tax_info->tax_id_type)
: null;
$birthDate = (isset($data->birth_date)) ?
\DateTime::createFromFormat('Y-m-d', $data->birth_date)
: null;
return new Payer(
$payerName,
isset($data->email_address) ? $data->email_address : '',
(isset($data->payer_id)) ? $data->payer_id : '',
$address,
$birthDate,
$phone,
$taxInfo
);
}
}

View file

@ -1,40 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\CardAuthenticationResult;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentSource;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentSourceCard;
class PaymentSourceFactory
{
public function fromPayPalResponse(\stdClass $data): PaymentSource
{
$card = null;
$wallet = null;
if (isset($data->card)) {
$authenticationResult = null;
if (isset($data->card->authentication_result)) {
$authenticationResult = new CardAuthenticationResult(
isset($data->card->authentication_result->liability_shift) ?
(string) $data->card->authentication_result->liability_shift : '',
isset($data->card->authentication_result->three_d_secure->enrollment_status) ?
(string) $data->card->authentication_result->three_d_secure->enrollment_status : '',
isset($data->card->authentication_result->three_d_secure->authentication_result) ?
(string) $data->card->authentication_result->three_d_secure->authentication_result : ''
);
}
$card = new PaymentSourceCard(
isset($data->card->last_digits) ? (string) $data->card->last_digits : '',
isset($data->card->brand) ? (string) $data->card->brand : '',
isset($data->card->type) ? (string) $data->card->type : '',
$authenticationResult
);
}
return new PaymentSource($card, $wallet);
}
}

View file

@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentToken;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class PaymentTokenFactory
{
public function fromPayPalResponse(\stdClass $data): PaymentToken
{
if (! isset($data->id)) {
throw new RuntimeException(
__("No id for payment token given", "woocommerce-paypal-commerce-gateway")
);
}
return new PaymentToken(
$data->id,
(isset($data->type)) ? $data->type : PaymentToken::TYPE_PAYMENT_METHOD_TOKEN
);
}
public function fromArray(array $data): PaymentToken
{
return $this->fromPayPalResponse((object) $data);
}
}

Some files were not shown because too many files have changed in this diff Show more