move module.local to module

This commit is contained in:
David Remer 2020-09-01 14:21:58 +03:00
parent c443e4053c
commit f8e82bdfaf
217 changed files with 8 additions and 2 deletions

View file

@ -0,0 +1,8 @@
{
"name": "inpsyde/ppcp-subscription",
"type": "inpsyde-module",
"require": {
"dhii/module-interface": "0.2.x-dev",
"inpsyde/ppcp-api-client": "dev-master"
}
}

View file

@ -0,0 +1,10 @@
<?php
/**
* The extensions.
*
* @package Inpsyde\PayPalCommerce\Subscription
*/
declare(strict_types=1);
return array();

View file

@ -0,0 +1,16 @@
<?php
/**
* The module.
*
* @package Inpsyde\PayPalCommerce\Subscription
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Subscription;
use Dhii\Modular\Module\ModuleInterface;
return static function (): ModuleInterface {
return new SubscriptionModule();
};

View file

@ -0,0 +1,39 @@
<?php
/**
* The services
*
* @package Inpsyde\PayPalCommerce\Subscription
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Subscription;
use Inpsyde\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
use Inpsyde\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
use Psr\Container\ContainerInterface;
return array(
'subscription.helper' => static function ( ContainerInterface $container ): SubscriptionHelper {
return new SubscriptionHelper();
},
'subscription.renewal-handler' => static function ( ContainerInterface $container ): RenewalHandler {
$logger = $container->get( 'woocommerce.logger.woocommerce' );
$repository = $container->get( 'subscription.repository.payment-token' );
$endpoint = $container->get( 'api.endpoint.order' );
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
$payer_factory = $container->get( 'api.factory.payer' );
return new RenewalHandler(
$logger,
$repository,
$endpoint,
$purchase_unit_factory,
$payer_factory
);
},
'subscription.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository {
$factory = $container->get( 'api.factory.payment-token' );
$endpoint = $container->get( 'api.endpoint.payment-token' );
return new PaymentTokenRepository( $factory, $endpoint );
},
);

View file

@ -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 );
}
}

View file

@ -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->from_array( $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->delete_token( $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->for_user( $id );
$token = current( $tokens );
$token_array = $token->to_array();
update_user_meta( $id, self::USER_META, $token_array );
return $token;
}
}

View 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', 'paypal-for-woocommerce' ),
(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',
'paypal-for-woocommerce'
),
(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.',
'paypal-for-woocommerce'
),
(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->from_wc_order( $wc_order );
$payer = $this->payer_factory->from_customer( $customer );
$order = $this->order_endpoint->create(
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',
'paypal-for-woocommerce'
),
(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.', 'paypal-for-woocommerce' )
);
\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 );
}
}
}

View file

@ -0,0 +1,54 @@
<?php
/**
* The subscription module.
*
* @package Inpsyde\PayPalCommerce\Subscription
*/
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Subscription;
use Dhii\Container\ServiceProvider;
use Dhii\Modular\Module\ModuleInterface;
use Inpsyde\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
/**
* Class SubscriptionModule
*/
class SubscriptionModule implements ModuleInterface {
/**
* Setup the module.
*
* @return ServiceProviderInterface
*/
public function setup(): ServiceProviderInterface {
return new ServiceProvider(
require __DIR__ . '/../services.php',
require __DIR__ . '/../extensions.php'
);
}
/**
* Runs the module.
*
* @param ContainerInterface $container The container.
*/
public function run( ContainerInterface $container ) {
add_action(
'woocommerce_scheduled_subscription_payment_' . PayPalGateway::ID,
static function ( $amount, $order ) use ( $container ) {
if ( ! is_a( $order, \WC_Order::class ) ) {
return;
}
$handler = $container->get( 'subscription.renewal-handler' );
$handler->renew( $order );
},
10,
2
);
}
}