mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 10:55:00 +08:00
codingstandards for subscription module
This commit is contained in:
parent
cfbd3ae428
commit
7af7ace569
11 changed files with 470 additions and 294 deletions
|
@ -400,13 +400,13 @@ class SmartButton implements SmartButtonInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function hasSubscription(): bool {
|
private function hasSubscription(): bool {
|
||||||
if ( ! $this->subscriptionHelper->acceptOnlyAutomaticPaymentGateways() ) {
|
if ( ! $this->subscriptionHelper->accept_only_automatic_payment_gateways() ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( is_product() ) {
|
if ( is_product() ) {
|
||||||
return $this->subscriptionHelper->currentProductIsSubscription();
|
return $this->subscriptionHelper->current_product_is_subscription();
|
||||||
}
|
}
|
||||||
return $this->subscriptionHelper->cartContainsSubscription();
|
return $this->subscriptionHelper->cart_contains_subscription();
|
||||||
}
|
}
|
||||||
|
|
||||||
//phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
|
//phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* The extensions.
|
||||||
|
*
|
||||||
|
* @package Inpsyde\PayPalCommerce\Subscription
|
||||||
|
*/
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
return [
|
return array();
|
||||||
|
|
||||||
];
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* The module.
|
||||||
|
*
|
||||||
|
* @package Inpsyde\PayPalCommerce\Subscription
|
||||||
|
*/
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
@ -7,5 +12,5 @@ namespace Inpsyde\PayPalCommerce\Subscription;
|
||||||
use Dhii\Modular\Module\ModuleInterface;
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
|
||||||
return static function (): ModuleInterface {
|
return static function (): ModuleInterface {
|
||||||
return new SubscriptionModule();
|
return new SubscriptionModule();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* The services
|
||||||
|
*
|
||||||
|
* @package Inpsyde\PayPalCommerce\Subscription
|
||||||
|
*/
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
@ -8,27 +13,27 @@ use Inpsyde\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||||
use Inpsyde\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
use Inpsyde\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
return [
|
return array(
|
||||||
'subscription.helper' => static function (ContainerInterface $container): SubscriptionHelper {
|
'subscription.helper' => static function ( ContainerInterface $container ): SubscriptionHelper {
|
||||||
return new SubscriptionHelper();
|
return new SubscriptionHelper();
|
||||||
},
|
},
|
||||||
'subscription.renewal-handler' => static function (ContainerInterface $container): RenewalHandler {
|
'subscription.renewal-handler' => static function ( ContainerInterface $container ): RenewalHandler {
|
||||||
$logger = $container->get('woocommerce.logger.woocommerce');
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
$repository = $container->get('subscription.repository.payment-token');
|
$repository = $container->get( 'subscription.repository.payment-token' );
|
||||||
$endpoint = $container->get('api.endpoint.order');
|
$endpoint = $container->get( 'api.endpoint.order' );
|
||||||
$purchaseFactory = $container->get('api.factory.purchase-unit');
|
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
||||||
$payerFactory = $container->get('api.factory.payer');
|
$payer_factory = $container->get( 'api.factory.payer' );
|
||||||
return new RenewalHandler(
|
return new RenewalHandler(
|
||||||
$logger,
|
$logger,
|
||||||
$repository,
|
$repository,
|
||||||
$endpoint,
|
$endpoint,
|
||||||
$purchaseFactory,
|
$purchase_unit_factory,
|
||||||
$payerFactory
|
$payer_factory
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'subscription.repository.payment-token' => static function (ContainerInterface $container): PaymentTokenRepository {
|
'subscription.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository {
|
||||||
$factory = $container->get('api.factory.payment-token');
|
$factory = $container->get( 'api.factory.payment-token' );
|
||||||
$endpoint = $container->get('api.endpoint.payment-token');
|
$endpoint = $container->get( 'api.endpoint.payment-token' );
|
||||||
return new PaymentTokenRepository($factory, $endpoint);
|
return new PaymentTokenRepository( $factory, $endpoint );
|
||||||
},
|
},
|
||||||
];
|
);
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Inpsyde\PayPalCommerce\Subscription\Helper;
|
|
||||||
|
|
||||||
class SubscriptionHelper {
|
|
||||||
|
|
||||||
|
|
||||||
public function currentProductIsSubscription(): bool {
|
|
||||||
if ( ! $this->pluginIsActive() ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$product = wc_get_product();
|
|
||||||
return is_a( $product, \WC_Product::class ) && $product->is_type( 'subscription' );
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cartContainsSubscription(): bool {
|
|
||||||
if ( ! $this->pluginIsActive() ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$cart = WC()->cart;
|
|
||||||
if ( ! $cart || $cart->is_empty() ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ( $cart->get_cart() as $item ) {
|
|
||||||
if ( ! isset( $item['data'] ) || ! is_a( $item['data'], \WC_Product::class ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ( $item['data']->is_type( 'subscription' ) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function acceptOnlyAutomaticPaymentGateways(): bool {
|
|
||||||
|
|
||||||
if ( ! $this->pluginIsActive() ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$acceptManualRenewals = ( 'no' !== get_option(
|
|
||||||
//phpcs:disable Inpsyde.CodeQuality.VariablesName.SnakeCaseVar
|
|
||||||
\WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals',
|
|
||||||
//phpcs:enable Inpsyde.CodeQuality.VariablesName.SnakeCaseVar
|
|
||||||
'no'
|
|
||||||
) ) ? true : false;
|
|
||||||
return ! $acceptManualRenewals;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function pluginIsActive(): bool {
|
|
||||||
|
|
||||||
return class_exists( \WC_Subscriptions::class );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Helper class for the subscriptions. Contains methods to determine
|
||||||
|
* whether the cart contains a subscription, the current product is
|
||||||
|
* a subscription or the subscription plugin is activated in the first place.
|
||||||
|
*
|
||||||
|
* @package Inpsyde\PayPalCommerce\Subscription\Helper
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Subscription\Helper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SubscriptionHelper
|
||||||
|
*/
|
||||||
|
class SubscriptionHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the current product is a subscription.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function current_product_is_subscription(): bool {
|
||||||
|
if ( ! $this->plugin_is_active() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$product = wc_get_product();
|
||||||
|
return is_a( $product, \WC_Product::class ) && $product->is_type( 'subscription' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the current cart contains subscriptions.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function cart_contains_subscription(): bool {
|
||||||
|
if ( ! $this->plugin_is_active() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$cart = WC()->cart;
|
||||||
|
if ( ! $cart || $cart->is_empty() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $cart->get_cart() as $item ) {
|
||||||
|
if ( ! isset( $item['data'] ) || ! is_a( $item['data'], \WC_Product::class ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( $item['data']->is_type( 'subscription' ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether only automatic payment gateways are accepted.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function accept_only_automatic_payment_gateways(): bool {
|
||||||
|
|
||||||
|
if ( ! $this->plugin_is_active() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$accept_manual_renewals = ( 'no' !== get_option(
|
||||||
|
//phpcs:disable Inpsyde.CodeQuality.VariablesName.SnakeCaseVar
|
||||||
|
\WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals',
|
||||||
|
//phpcs:enable Inpsyde.CodeQuality.VariablesName.SnakeCaseVar
|
||||||
|
'no'
|
||||||
|
) ) ? true : false;
|
||||||
|
return ! $accept_manual_renewals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the subscription plugin is active or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function plugin_is_active(): bool {
|
||||||
|
|
||||||
|
return class_exists( \WC_Subscriptions::class );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,150 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Inpsyde\PayPalCommerce\Subscription;
|
|
||||||
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
|
||||||
use Inpsyde\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
|
||||||
use Inpsyde\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
|
|
||||||
class RenewalHandler {
|
|
||||||
|
|
||||||
|
|
||||||
private $logger;
|
|
||||||
private $repository;
|
|
||||||
private $orderEndpoint;
|
|
||||||
private $purchaseUnitFactory;
|
|
||||||
private $payerFactory;
|
|
||||||
public function __construct(
|
|
||||||
LoggerInterface $logger,
|
|
||||||
PaymentTokenRepository $repository,
|
|
||||||
OrderEndpoint $orderEndpoint,
|
|
||||||
PurchaseUnitFactory $purchaseUnitFactory,
|
|
||||||
PayerFactory $payerFactory
|
|
||||||
) {
|
|
||||||
|
|
||||||
$this->logger = $logger;
|
|
||||||
$this->repository = $repository;
|
|
||||||
$this->orderEndpoint = $orderEndpoint;
|
|
||||||
$this->purchaseUnitFactory = $purchaseUnitFactory;
|
|
||||||
$this->payerFactory = $payerFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renew( \WC_Order $wcOrder ) {
|
|
||||||
|
|
||||||
$this->logger->log(
|
|
||||||
'info',
|
|
||||||
sprintf(
|
|
||||||
// translators: %d is the id of the order
|
|
||||||
__( 'Start moneytransfer for order %d', 'woocommerce-paypal-commerce-gateway' ),
|
|
||||||
(int) $wcOrder->get_id()
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'order' => $wcOrder,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->processOrder( $wcOrder );
|
|
||||||
} catch ( \Exception $error ) {
|
|
||||||
$this->logger->log(
|
|
||||||
'error',
|
|
||||||
sprintf(
|
|
||||||
// translators: %1$d is the order number, %2$s the error message
|
|
||||||
__(
|
|
||||||
'An error occured while trying to renew the subscription for order %1$d: %2$s',
|
|
||||||
'woocommerce-paypal-commerce-gateway'
|
|
||||||
),
|
|
||||||
(int) $wcOrder->get_id(),
|
|
||||||
$error->getMessage()
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'order' => $wcOrder,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
\WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $wcOrder );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->logger->log(
|
|
||||||
'info',
|
|
||||||
sprintf(
|
|
||||||
// translators: %d is the order number
|
|
||||||
__(
|
|
||||||
'Moneytransfer for order %d is completed.',
|
|
||||||
'woocommerce-paypal-commerce-gateway'
|
|
||||||
),
|
|
||||||
(int) $wcOrder->get_id()
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'order' => $wcOrder,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function processOrder( \WC_Order $wcOrder ) {
|
|
||||||
|
|
||||||
$userId = (int) $wcOrder->get_customer_id();
|
|
||||||
$customer = new \WC_Customer( $userId );
|
|
||||||
$token = $this->getTokenForCustomer( $customer, $wcOrder );
|
|
||||||
if ( ! $token ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$purchaseUnits = $this->purchaseUnitFactory->fromWcOrder( $wcOrder );
|
|
||||||
$payer = $this->payerFactory->fromCustomer( $customer );
|
|
||||||
$order = $this->orderEndpoint->createForPurchaseUnits(
|
|
||||||
array( $purchaseUnits ),
|
|
||||||
$payer,
|
|
||||||
$token,
|
|
||||||
(string) $wcOrder->get_id()
|
|
||||||
);
|
|
||||||
$this->captureOrder( $order, $wcOrder );
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getTokenForCustomer( \WC_Customer $customer, \WC_Order $wcOrder ): ?PaymentToken {
|
|
||||||
|
|
||||||
$token = $this->repository->forUserId( (int) $customer->get_id() );
|
|
||||||
if ( ! $token ) {
|
|
||||||
$this->logger->log(
|
|
||||||
'error',
|
|
||||||
sprintf(
|
|
||||||
// translators: %d is the customer id
|
|
||||||
__(
|
|
||||||
'No payment token found for customer %d',
|
|
||||||
'woocommerce-paypal-commerce-gateway'
|
|
||||||
),
|
|
||||||
(int) $customer->get_id()
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'customer' => $customer,
|
|
||||||
'order' => $wcOrder,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
\WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $wcOrder );
|
|
||||||
}
|
|
||||||
return $token;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function captureOrder( Order $order, \WC_Order $wcOrder ) {
|
|
||||||
|
|
||||||
if ( $order->intent() === 'CAPTURE' && $order->status()->is( OrderStatus::COMPLETED ) ) {
|
|
||||||
$wcOrder->update_status(
|
|
||||||
'processing',
|
|
||||||
__( 'Payment received.', 'woocommerce-paypal-commerce-gateway' )
|
|
||||||
);
|
|
||||||
\WC_Subscriptions_Manager::process_subscription_payments_on_order( $wcOrder );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $order->intent() === 'AUTHORIZE' ) {
|
|
||||||
$this->orderEndpoint->authorize( $order );
|
|
||||||
$wcOrder->update_meta_data( PayPalGateway::CAPTURED_META_KEY, 'false' );
|
|
||||||
\WC_Subscriptions_Manager::process_subscription_payments_on_order( $wcOrder );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Inpsyde\PayPalCommerce\Subscription\Repository;
|
|
||||||
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\PaymentTokenEndpoint;
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
|
||||||
use Inpsyde\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory;
|
|
||||||
|
|
||||||
class PaymentTokenRepository {
|
|
||||||
|
|
||||||
|
|
||||||
public const USER_META = 'ppcp-vault-token';
|
|
||||||
private $factory;
|
|
||||||
private $endpoint;
|
|
||||||
public function __construct(
|
|
||||||
PaymentTokenFactory $factory,
|
|
||||||
PaymentTokenEndpoint $endpoint
|
|
||||||
) {
|
|
||||||
|
|
||||||
$this->factory = $factory;
|
|
||||||
$this->endpoint = $endpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function forUserId( int $id ): ?PaymentToken {
|
|
||||||
try {
|
|
||||||
$token = (array) get_user_meta( $id, self::USER_META, true );
|
|
||||||
if ( ! $token || ! isset( $token['id'] ) ) {
|
|
||||||
return $this->fetchForUserId( $id );
|
|
||||||
}
|
|
||||||
|
|
||||||
$token = $this->factory->fromArray( $token );
|
|
||||||
return $token;
|
|
||||||
} catch ( RuntimeException $error ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deleteToken( int $userId, PaymentToken $token ): bool {
|
|
||||||
delete_user_meta( $userId, self::USER_META );
|
|
||||||
return $this->endpoint->deleteToken( $token );
|
|
||||||
}
|
|
||||||
|
|
||||||
private function fetchForUserId( int $id ): PaymentToken {
|
|
||||||
|
|
||||||
$tokens = $this->endpoint->forUser( $id );
|
|
||||||
$token = current( $tokens );
|
|
||||||
$tokenArray = $token->toArray();
|
|
||||||
update_user_meta( $id, self::USER_META, $tokenArray );
|
|
||||||
return $token;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The payment token repository returns or deletes payment tokens for users.
|
||||||
|
*
|
||||||
|
* @package Inpsyde\PayPalCommerce\Subscription\Repository
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Subscription\Repository;
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\PaymentTokenEndpoint;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PaymentTokenRepository
|
||||||
|
*/
|
||||||
|
class PaymentTokenRepository {
|
||||||
|
|
||||||
|
|
||||||
|
public const USER_META = 'ppcp-vault-token';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The payment token factory.
|
||||||
|
*
|
||||||
|
* @var PaymentTokenFactory
|
||||||
|
*/
|
||||||
|
private $factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The payment token endpoint.
|
||||||
|
*
|
||||||
|
* @var PaymentTokenEndpoint
|
||||||
|
*/
|
||||||
|
private $endpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PaymentTokenRepository constructor.
|
||||||
|
*
|
||||||
|
* @param PaymentTokenFactory $factory The payment token factory.
|
||||||
|
* @param PaymentTokenEndpoint $endpoint The payment token endpoint.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
PaymentTokenFactory $factory,
|
||||||
|
PaymentTokenEndpoint $endpoint
|
||||||
|
) {
|
||||||
|
|
||||||
|
$this->factory = $factory;
|
||||||
|
$this->endpoint = $endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a token for a user.
|
||||||
|
*
|
||||||
|
* @param int $id The user id.
|
||||||
|
*
|
||||||
|
* @return PaymentToken|null
|
||||||
|
*/
|
||||||
|
public function for_user_id( int $id ): ?PaymentToken {
|
||||||
|
try {
|
||||||
|
$token = (array) get_user_meta( $id, self::USER_META, true );
|
||||||
|
if ( ! $token || ! isset( $token['id'] ) ) {
|
||||||
|
return $this->fetch_for_user_id( $id );
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $this->factory->fromArray( $token );
|
||||||
|
return $token;
|
||||||
|
} catch ( RuntimeException $error ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a token for a user.
|
||||||
|
*
|
||||||
|
* @param int $user_id The user id.
|
||||||
|
* @param PaymentToken $token The token.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function delete_token( int $user_id, PaymentToken $token ): bool {
|
||||||
|
delete_user_meta( $user_id, self::USER_META );
|
||||||
|
return $this->endpoint->deleteToken( $token );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch PaymentToken from PayPal for a user.
|
||||||
|
*
|
||||||
|
* @param int $id The user id.
|
||||||
|
* @return PaymentToken
|
||||||
|
*/
|
||||||
|
private function fetch_for_user_id( int $id ): PaymentToken {
|
||||||
|
|
||||||
|
$tokens = $this->endpoint->forUser( $id );
|
||||||
|
$token = current( $tokens );
|
||||||
|
$token_array = $token->toArray();
|
||||||
|
update_user_meta( $id, self::USER_META, $token_array );
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
}
|
222
modules.local/ppcp-subscription/src/class-renewalhandler.php
Normal file
222
modules.local/ppcp-subscription/src/class-renewalhandler.php
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles subscription renewals.
|
||||||
|
*
|
||||||
|
* @package Inpsyde\PayPalCommerce\Subscription
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Subscription;
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||||
|
use Inpsyde\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
||||||
|
use Inpsyde\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class RenewalHandler
|
||||||
|
*/
|
||||||
|
class RenewalHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The payment token repository.
|
||||||
|
*
|
||||||
|
* @var PaymentTokenRepository
|
||||||
|
*/
|
||||||
|
private $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order endpoint.
|
||||||
|
*
|
||||||
|
* @var OrderEndpoint
|
||||||
|
*/
|
||||||
|
private $order_endpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The purchase unit factory.
|
||||||
|
*
|
||||||
|
* @var PurchaseUnitFactory
|
||||||
|
*/
|
||||||
|
private $purchase_unit_factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The payer factory.
|
||||||
|
*
|
||||||
|
* @var PayerFactory
|
||||||
|
*/
|
||||||
|
private $payer_factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RenewalHandler constructor.
|
||||||
|
*
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
|
* @param PaymentTokenRepository $repository The payment token repository.
|
||||||
|
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||||
|
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||||
|
* @param PayerFactory $payer_factory The payer factory.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
LoggerInterface $logger,
|
||||||
|
PaymentTokenRepository $repository,
|
||||||
|
OrderEndpoint $order_endpoint,
|
||||||
|
PurchaseUnitFactory $purchase_unit_factory,
|
||||||
|
PayerFactory $payer_factory
|
||||||
|
) {
|
||||||
|
|
||||||
|
$this->logger = $logger;
|
||||||
|
$this->repository = $repository;
|
||||||
|
$this->order_endpoint = $order_endpoint;
|
||||||
|
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||||
|
$this->payer_factory = $payer_factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renew an order.
|
||||||
|
*
|
||||||
|
* @param \WC_Order $wc_order The Woocommerce order.
|
||||||
|
*/
|
||||||
|
public function renew( \WC_Order $wc_order ) {
|
||||||
|
|
||||||
|
$this->logger->log(
|
||||||
|
'info',
|
||||||
|
sprintf(
|
||||||
|
// translators: %d is the id of the order.
|
||||||
|
__( 'Start moneytransfer for order %d', 'woocommerce-paypal-commerce-gateway' ),
|
||||||
|
(int) $wc_order->get_id()
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'order' => $wc_order,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->process_order( $wc_order );
|
||||||
|
} catch ( \Exception $error ) {
|
||||||
|
$this->logger->log(
|
||||||
|
'error',
|
||||||
|
sprintf(
|
||||||
|
// translators: %1$d is the order number, %2$s the error message.
|
||||||
|
__(
|
||||||
|
'An error occured while trying to renew the subscription for order %1$d: %2$s',
|
||||||
|
'woocommerce-paypal-commerce-gateway'
|
||||||
|
),
|
||||||
|
(int) $wc_order->get_id(),
|
||||||
|
$error->getMessage()
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'order' => $wc_order,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
\WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $wc_order );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->logger->log(
|
||||||
|
'info',
|
||||||
|
sprintf(
|
||||||
|
// translators: %d is the order number.
|
||||||
|
__(
|
||||||
|
'Moneytransfer for order %d is completed.',
|
||||||
|
'woocommerce-paypal-commerce-gateway'
|
||||||
|
),
|
||||||
|
(int) $wc_order->get_id()
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'order' => $wc_order,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a Woocommerce order.
|
||||||
|
*
|
||||||
|
* @param \WC_Order $wc_order The Woocommerce order.
|
||||||
|
*
|
||||||
|
* @throws \Exception If customer cannot be read/found.
|
||||||
|
*/
|
||||||
|
private function process_order( \WC_Order $wc_order ) {
|
||||||
|
|
||||||
|
$user_id = (int) $wc_order->get_customer_id();
|
||||||
|
$customer = new \WC_Customer( $user_id );
|
||||||
|
$token = $this->get_token_for_customer( $customer, $wc_order );
|
||||||
|
if ( ! $token ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$purchase_unit = $this->purchase_unit_factory->fromWcOrder( $wc_order );
|
||||||
|
$payer = $this->payer_factory->fromCustomer( $customer );
|
||||||
|
$order = $this->order_endpoint->createForPurchaseUnits(
|
||||||
|
array( $purchase_unit ),
|
||||||
|
$payer,
|
||||||
|
$token,
|
||||||
|
(string) $wc_order->get_id()
|
||||||
|
);
|
||||||
|
$this->capture_order( $order, $wc_order );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a payment token for a customer.
|
||||||
|
*
|
||||||
|
* @param \WC_Customer $customer The customer.
|
||||||
|
* @param \WC_Order $wc_order The current Woocommerce order we want to process.
|
||||||
|
*
|
||||||
|
* @return PaymentToken|null
|
||||||
|
*/
|
||||||
|
private function get_token_for_customer( \WC_Customer $customer, \WC_Order $wc_order ): ?PaymentToken {
|
||||||
|
|
||||||
|
$token = $this->repository->for_user_id( (int) $customer->get_id() );
|
||||||
|
if ( ! $token ) {
|
||||||
|
$this->logger->log(
|
||||||
|
'error',
|
||||||
|
sprintf(
|
||||||
|
// translators: %d is the customer id.
|
||||||
|
__(
|
||||||
|
'No payment token found for customer %d',
|
||||||
|
'woocommerce-paypal-commerce-gateway'
|
||||||
|
),
|
||||||
|
(int) $customer->get_id()
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'customer' => $customer,
|
||||||
|
'order' => $wc_order,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
\WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $wc_order );
|
||||||
|
}
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the PayPal order is captured/authorized the Woocommerce order gets updated accordingly.
|
||||||
|
*
|
||||||
|
* @param Order $order The PayPal order.
|
||||||
|
* @param \WC_Order $wc_order The related Woocommerce order.
|
||||||
|
*/
|
||||||
|
private function capture_order( Order $order, \WC_Order $wc_order ) {
|
||||||
|
|
||||||
|
if ( $order->intent() === 'CAPTURE' && $order->status()->is( OrderStatus::COMPLETED ) ) {
|
||||||
|
$wc_order->update_status(
|
||||||
|
'processing',
|
||||||
|
__( 'Payment received.', 'woocommerce-paypal-commerce-gateway' )
|
||||||
|
);
|
||||||
|
\WC_Subscriptions_Manager::process_subscription_payments_on_order( $wc_order );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $order->intent() === 'AUTHORIZE' ) {
|
||||||
|
$this->order_endpoint->authorize( $order );
|
||||||
|
$wc_order->update_meta_data( PayPalGateway::CAPTURED_META_KEY, 'false' );
|
||||||
|
\WC_Subscriptions_Manager::process_subscription_payments_on_order( $wc_order );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* The subscription module.
|
||||||
|
*
|
||||||
|
* @package Inpsyde\PayPalCommerce\Subscription
|
||||||
|
*/
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
@ -10,9 +15,16 @@ use Inpsyde\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
use Interop\Container\ServiceProviderInterface;
|
use Interop\Container\ServiceProviderInterface;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SubscriptionModule
|
||||||
|
*/
|
||||||
class SubscriptionModule implements ModuleInterface {
|
class SubscriptionModule implements ModuleInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the module.
|
||||||
|
*
|
||||||
|
* @return ServiceProviderInterface
|
||||||
|
*/
|
||||||
public function setup(): ServiceProviderInterface {
|
public function setup(): ServiceProviderInterface {
|
||||||
return new ServiceProvider(
|
return new ServiceProvider(
|
||||||
require __DIR__ . '/../services.php',
|
require __DIR__ . '/../services.php',
|
||||||
|
@ -21,7 +33,9 @@ class SubscriptionModule implements ModuleInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* Runs the module.
|
||||||
|
*
|
||||||
|
* @param ContainerInterface $container The container.
|
||||||
*/
|
*/
|
||||||
public function run( ContainerInterface $container ) {
|
public function run( ContainerInterface $container ) {
|
||||||
add_action(
|
add_action(
|
Loading…
Add table
Add a link
Reference in a new issue