Refactoring

This commit is contained in:
dinamiko 2021-05-19 15:39:33 +02:00
parent 1783467af4
commit 47c4c62d6f
9 changed files with 237 additions and 167 deletions

View file

@ -200,69 +200,4 @@ class PaymentTokenEndpoint {
return wp_remote_retrieve_response_code( $response ) === 204;
}
/**
* Creates a payment token for a user.
*
* @param int $customer_id The customer Id.
* @param array $source The payment source.
* @return PaymentToken
* @throws RuntimeException If the request fails.
*/
public function create( $customer_id, $source ): PaymentToken {
$data = array(
'customer_id' => $this->prefix . $customer_id,
'source' => array(
'card' => array(
'number' => $source['credit_card_number'],
'expiry' => $source['credit_card_expiry'],
'security_code' => $source['credit_card_cvc'],
),
),
);
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/vault/payment-tokens';
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'PayPal-Request-Id' => uniqid( 'ppcp-', true ),
'body' => wp_json_encode( $data ),
),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
sprintf(
// translators: %s is the error message.
__( 'Could not create payment token: %s', 'woocommerce-paypal-payments' ),
$response->get_error_message()
)
);
$this->logger->log( 'error', $error->getMessage() );
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 !== $status_code ) {
$error = new RuntimeException(
sprintf(
// translators: %s is the error message.
__( 'Could not create payment token: %s', 'woocommerce-paypal-payments' ),
$json->message
)
);
$this->logger->log( 'error', $error->getMessage() );
throw $error;
}
return $this->factory->from_paypal_response( $json );
}
}

View file

@ -9,7 +9,6 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Button\Assets;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayeeRepository;
@ -23,7 +22,7 @@ use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
@ -200,18 +199,17 @@ class SmartButton implements SmartButtonInterface {
11
);
$payment_token_repository = $this->payment_token_repository;
add_filter(
'woocommerce_credit_card_form_fields',
function ( $default_fields, $id ) use ( $payment_token_repository ) {
if ( $this->settings->has( 'vault_enabled' ) && $this->settings->get( 'vault_enabled' ) ) {
function ( $default_fields, $id ) {
if ( $this->settings->has( 'vault_enabled' ) && $this->settings->get( 'vault_enabled' ) && CreditCardGateway::ID === $id ) {
$default_fields['card-vault'] = sprintf(
'<p class="form-row form-row-wide"><label for="vault"><input class="ppcp-credit-card-vault" type="checkbox" id="ppcp-credit-card-vault" name="vault">%s</label></p>',
esc_html__( 'Save your Credit Card', 'woocommerce-paypal-payments' )
);
$tokens = $payment_token_repository->all_for_user_id( get_current_user_id() );
if ( $tokens && $this->tokens_contains_card( $tokens ) ) {
$tokens = $this->payment_token_repository->all_for_user_id( get_current_user_id() );
if ( $tokens && $this->payment_token_repository->tokens_contains_card( $tokens ) ) {
$output = sprintf(
'<p class="form-row form-row-wide"><label>%1$s</label><select id="saved-credit-card" name="saved_credit_card"><option value="">%2$s</option>',
esc_html__( 'Or select a saved Credit Card payment', 'woocommerce-paypal-payments' ),
@ -942,19 +940,4 @@ class SmartButton implements SmartButtonInterface {
}
return (string) $value;
}
/**
* Check if tokens has card source.
*
* @param PaymentToken[] $tokens The tokens.
* @return bool Wether tokens contains card or not.
*/
protected function tokens_contains_card( $tokens ) {
foreach ( $tokens as $token ) {
if ( isset( $token->source()->card ) ) {
return true;
}
}
return false;
}
}

View file

@ -83,4 +83,25 @@ class SubscriptionHelper {
return class_exists( \WC_Subscriptions::class );
}
/**
* Checks if order contains subscription.
*
* @param int $order_id The order Id.
* @return boolean Whether order is a subscription or not.
*/
public function has_subscription( $order_id ): bool {
return ( function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ) );
}
/**
* Checks if page is pay for order and change subscription payment page.
*
* @return bool Whether page is change subscription or not.
*/
public function is_subscription_change_payment(): bool {
$pay_for_order = filter_input( INPUT_GET, 'pay_for_order', FILTER_SANITIZE_STRING );
$change_payment_method = filter_input( INPUT_GET, 'change_payment_method', FILTER_SANITIZE_STRING );
return ( isset( $pay_for_order ) && isset( $change_payment_method ) );
}
}

View file

@ -102,19 +102,33 @@ class PaymentTokenRepository {
}
/**
* Create payment token for customer.
* Check if tokens has card source.
*
* @param int $customer_id The customer Id.
* @param array $source The payment source.
* @return PaymentToken
* @throws RuntimeException If the request fails.
* @param PaymentToken[] $tokens The tokens.
* @return bool Whether tokens contains card or not.
*/
public function create( $customer_id, $source ): PaymentToken {
try {
return $this->endpoint->create( $customer_id, $source );
} catch ( RuntimeException $exception ) {
throw new RuntimeException( $exception->getMessage() );
public function tokens_contains_card( $tokens ): bool {
foreach ( $tokens as $token ) {
if ( isset( $token->source()->card ) ) {
return true;
}
}
return false;
}
/**
* Check if tokens has PayPal source.
*
* @param PaymentToken[] $tokens The tokens.
* @return bool Whether tokens contains card or not.
*/
public function tokens_contains_paypal( $tokens ): bool {
foreach ( $tokens as $token ) {
if ( isset( $token->source()->paypal ) ) {
return true;
}
}
return false;
}
/**

View file

@ -13,11 +13,14 @@ use Dhii\Container\ServiceProvider;
use Dhii\Modular\Module\ModuleInterface;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
/**
* Class SubscriptionModule
@ -69,6 +72,40 @@ class SubscriptionModule implements ModuleInterface {
$this->add_payment_token_id( $subscription, $payment_token_repository, $logger );
}
);
add_filter(
'woocommerce_gateway_description',
function ( $description, $id ) use ( $container ) {
$payment_token_repository = $container->get( 'subscription.repository.payment-token' );
$settings = $container->get( 'wcgateway.settings' );
$subscription_helper = $container->get( 'subscription.helper' );
return $this->display_saved_paypal_payments( $settings, $id, $payment_token_repository, $description, $subscription_helper );
},
10,
2
);
add_filter(
'woocommerce_credit_card_form_fields',
function ( $default_fields, $id ) use ( $container ) {
$payment_token_repository = $container->get( 'subscription.repository.payment-token' );
$settings = $container->get( 'wcgateway.settings' );
$subscription_helper = $container->get( 'subscription.helper' );
return $this->display_saved_credit_cards( $settings, $id, $payment_token_repository, $default_fields, $subscription_helper );
},
20,
2
);
}
/**
* Returns the key for the module.
*
* @return string|void
*/
public function getKey() {
}
/**
@ -87,14 +124,6 @@ class SubscriptionModule implements ModuleInterface {
$handler->renew( $order );
}
/**
* Returns the key for the module.
*
* @return string|void
*/
public function getKey() {
}
/**
* Adds Payment token ID to subscription.
*
@ -102,7 +131,7 @@ class SubscriptionModule implements ModuleInterface {
* @param PaymentTokenRepository $payment_token_repository The payment repository.
* @param LoggerInterface $logger The logger.
*/
private function add_payment_token_id(
protected function add_payment_token_id(
\WC_Subscription $subscription,
PaymentTokenRepository $payment_token_repository,
LoggerInterface $logger
@ -128,4 +157,113 @@ class SubscriptionModule implements ModuleInterface {
$logger->log( 'warning', $message );
}
}
/**
* Displays saved PayPal payments.
*
* @param Settings $settings The settings.
* @param string $id The payment gateway Id.
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
* @param string $description The payment gateway description.
* @param SubscriptionHelper $subscription_helper The subscription helper.
* @return string
*/
protected function display_saved_paypal_payments(
Settings $settings,
string $id,
PaymentTokenRepository $payment_token_repository,
string $description,
SubscriptionHelper $subscription_helper
): string {
if ( $settings->has( 'vault_enabled' )
&& $settings->get( 'vault_enabled' )
&& PayPalGateway::ID === $id
&& $subscription_helper->is_subscription_change_payment()
) {
$tokens = $payment_token_repository->all_for_user_id( get_current_user_id() );
if ( ! $tokens || ! $payment_token_repository->tokens_contains_paypal( $tokens ) ) {
return esc_html__(
'No PayPal payments saved, in order to use a saved payment you first need to create it through a purchase.',
'woocommerce-paypal-payments'
);
}
$output = sprintf(
'<p class="form-row form-row-wide"><label>%1$s</label><select id="saved-paypal-payment" name="saved_paypal_payment">',
esc_html__( 'Select a saved PayPal payment', 'woocommerce-paypal-payments' )
);
foreach ( $tokens as $token ) {
if ( isset( $token->source()->paypal ) ) {
$output .= sprintf(
'<option value="%1$s">%2$s</option>',
$token->id(),
$token->source()->paypal->payer->email_address
);
}
}
$output .= '</select></p>';
return $output;
}
return $description;
}
/**
* Displays saved credit cards.
*
* @param Settings $settings The settings.
* @param string $id The payment gateway Id.
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
* @param array $default_fields Default payment gateway fields.
* @param SubscriptionHelper $subscription_helper The subscription helper.
* @return array|mixed|string
* @throws NotFoundException When setting was not found.
*/
protected function display_saved_credit_cards(
Settings $settings,
string $id,
PaymentTokenRepository $payment_token_repository,
array $default_fields,
SubscriptionHelper $subscription_helper
) {
if ( $settings->has( 'vault_enabled' )
&& $settings->get( 'vault_enabled' )
&& $subscription_helper->is_subscription_change_payment()
&& CreditCardGateway::ID === $id
) {
$tokens = $payment_token_repository->all_for_user_id( get_current_user_id() );
if ( ! $tokens || ! $payment_token_repository->tokens_contains_card( $tokens ) ) {
$default_fields = array();
$default_fields['saved-credit-card'] = esc_html__(
'No Credit Card saved, in order to use a saved Credit Card you first need to create it through a purchase.',
'woocommerce-paypal-payments'
);
return $default_fields;
}
$output = sprintf(
'<p class="form-row form-row-wide"><label>%1$s</label><select id="saved-credit-card" name="saved_credit_card">',
esc_html__( 'Select a saved Credit Card payment', 'woocommerce-paypal-payments' )
);
foreach ( $tokens as $token ) {
if ( isset( $token->source()->card ) ) {
$output .= sprintf(
'<option value="%1$s">%2$s ...%3$s</option>',
$token->id(),
$token->source()->card->brand,
$token->source()->card->last_digits
);
}
}
$output .= '</select></p>';
$default_fields = array();
$default_fields['saved-credit-card'] = $output;
return $default_fields;
}
return $default_fields;
}
}

View file

@ -46,7 +46,7 @@ return array(
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
$state = $container->get( 'onboarding.state' );
$transaction_url_provider = $container->get( 'wcgateway.transaction-url-provider' );
$subscription_helper = $container->get( 'subscription.helper' );
return new PayPalGateway(
$settings_renderer,
$order_processor,
@ -56,7 +56,8 @@ return array(
$session_handler,
$refund_processor,
$state,
$transaction_url_provider
$transaction_url_provider,
$subscription_helper
);
},
'wcgateway.credit-card-gateway' => static function ( $container ): CreditCardGateway {
@ -74,6 +75,7 @@ return array(
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
$payer_factory = $container->get( 'api.factory.payer' );
$order_endpoint = $container->get( 'api.endpoint.order' );
$subscription_helper = $container->get( 'subscription.helper' );
return new CreditCardGateway(
$settings_renderer,
$order_processor,
@ -88,7 +90,8 @@ return array(
$payment_token_repository,
$purchase_unit_factory,
$payer_factory,
$order_endpoint
$order_endpoint,
$subscription_helper
);
},
'wcgateway.disabler' => static function ( $container ): DisableGateways {

View file

@ -14,6 +14,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
@ -38,6 +39,13 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
*/
protected $transaction_url_provider;
/**
* The subscription helper.
*
* @var SubscriptionHelper
*/
protected $subscription_helper;
/**
* The URL to the module.
*
@ -97,6 +105,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
* @param PayerFactory $payer_factory The payer factory.
* @param OrderEndpoint $order_endpoint The order endpoint.
* @param SubscriptionHelper $subscription_helper The subscription helper.
*/
public function __construct(
SettingsRenderer $settings_renderer,
@ -112,7 +121,8 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
PaymentTokenRepository $payment_token_repository,
PurchaseUnitFactory $purchase_unit_factory,
PayerFactory $payer_factory,
OrderEndpoint $order_endpoint
OrderEndpoint $order_endpoint,
SubscriptionHelper $subscription_helper
) {
$this->id = self::ID;
@ -179,6 +189,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
$this->payer_factory = $payer_factory;
$this->order_endpoint = $order_endpoint;
$this->transaction_url_provider = $transaction_url_provider;
$this->subscription_helper = $subscription_helper;
}
/**

View file

@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
@ -81,6 +82,13 @@ class PayPalGateway extends \WC_Payment_Gateway {
*/
protected $transaction_url_provider;
/**
* The subscription helper.
*
* @var SubscriptionHelper
*/
protected $subscription_helper;
/**
* The Refund Processor.
*
@ -100,6 +108,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
* @param RefundProcessor $refund_processor The Refund Processor.
* @param State $state The state.
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
* @param SubscriptionHelper $subscription_helper The subscription helper.
*/
public function __construct(
SettingsRenderer $settings_renderer,
@ -110,7 +119,8 @@ class PayPalGateway extends \WC_Payment_Gateway {
SessionHandler $session_handler,
RefundProcessor $refund_processor,
State $state,
TransactionUrlProvider $transaction_url_provider
TransactionUrlProvider $transaction_url_provider,
SubscriptionHelper $subscription_helper
) {
$this->id = self::ID;
@ -165,6 +175,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
'process_admin_options',
)
);
$this->subscription_helper = $subscription_helper;
}
/**

View file

@ -95,8 +95,8 @@ trait ProcessPaymentTrait {
/**
* If customer has chosen change Subscription payment.
*/
if ( $this->has_subscription( $order_id ) && $this->is_subscription_change_payment() ) {
if ( $saved_credit_card ) {
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
if ( 'ppcp-credit-card-gateway' === $this->id && $saved_credit_card ) {
update_post_meta( $order_id, 'payment_token_id', $saved_credit_card );
$this->session_handler->destroy_session_data();
@ -106,40 +106,15 @@ trait ProcessPaymentTrait {
);
}
$credit_card_number = filter_input( INPUT_POST, 'ppcp-credit-card-gateway-card-number', FILTER_SANITIZE_STRING );
$credit_card_expiry = filter_input( INPUT_POST, 'ppcp-credit-card-gateway-card-expiry', FILTER_SANITIZE_STRING );
$credit_card_cvc = filter_input( INPUT_POST, 'ppcp-credit-card-gateway-card-cvc', FILTER_SANITIZE_STRING );
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
if ( 'ppcp-gateway' === $this->id && $saved_paypal_payment ) {
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
if ( $credit_card_number && $credit_card_expiry && $credit_card_cvc ) {
try {
$token = $this->payment_token_repository->create(
$wc_order->get_customer_id(),
array(
'credit_card_number' => $credit_card_number,
'credit_card_expiry' => $credit_card_expiry,
'credit_card_cvc' => $credit_card_cvc,
)
);
update_post_meta( $order_id, 'payment_token_id', $token->id() );
$this->session_handler->destroy_session_data();
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $wc_order ),
);
} catch ( RuntimeException $exception ) {
wc_add_notice(
$exception->getMessage(),
'error'
);
$this->session_handler->destroy_session_data();
return array(
'result' => 'failure',
'redirect' => $this->get_return_url( $wc_order ),
);
}
$this->session_handler->destroy_session_data();
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $wc_order ),
);
}
}
@ -226,25 +201,4 @@ trait ProcessPaymentTrait {
}
return false;
}
/**
* Is $order_id a subscription?
*
* @param int $order_id The order Id.
* @return boolean Whether order is a subscription or not.
*/
private function has_subscription( $order_id ): bool {
return ( function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ) );
}
/**
* Checks if page is pay for order and change subscription payment page.
*
* @return bool
*/
private function is_subscription_change_payment(): bool {
$pay_for_order = filter_input( INPUT_GET, 'pay_for_order', FILTER_SANITIZE_STRING );
$change_payment_method = filter_input( INPUT_GET, 'change_payment_method', FILTER_SANITIZE_STRING );
return ( isset( $pay_for_order ) && isset( $change_payment_method ) );
}
}