Skip to content

Commit

Permalink
Merge branch 'develop' into add/pay-for-order-tracks
Browse files Browse the repository at this point in the history
  • Loading branch information
malithsen authored Oct 24, 2023
2 parents 7df5ff6 + 0e2fe50 commit ce8d718
Show file tree
Hide file tree
Showing 17 changed files with 524 additions and 124 deletions.
4 changes: 4 additions & 0 deletions changelog/deposits-506-percentage-display
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fix

Improve multi-currency compatibility with WooCommerce Deposits
4 changes: 4 additions & 0 deletions changelog/rpp-7414-authentication-required-state
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: dev

Added authentication required state
9 changes: 9 additions & 0 deletions includes/class-wc-payment-gateway-wcpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use WCPay\Duplicate_Payment_Prevention_Service;
use WCPay\Fraud_Prevention\Fraud_Prevention_Service;
use WCPay\Fraud_Prevention\Fraud_Risk_Tools;
use WCPay\Internal\Payment\State\AuthenticationRequiredState;
use WCPay\Logger;
use WCPay\Payment_Information;
use WCPay\Payment_Methods\UPE_Payment_Gateway;
Expand Down Expand Up @@ -856,6 +857,14 @@ public function new_process_payment( WC_Order $order ) {
];
}

if ( $state instanceof AuthenticationRequiredState ) {
$context = $state->get_context();
return [
'result' => 'success',
'redirect' => $service->get_authentication_redirect_url( $context->get_intent(), $context->get_order_id() ),
];
}

throw new Exception( __( 'The payment process could not be completed.', 'woocommerce-payments' ) );
}

Expand Down
13 changes: 13 additions & 0 deletions includes/multi-currency/Compatibility/WooCommerceDeposits.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ class WooCommerceDeposits extends BaseCompatibility {
*/
protected function init() {
if ( class_exists( 'WC_Deposits' ) ) {
/*
* Multi-currency support was added to WooCommerce Deposits in version 2.0.1.
*
* This prevents the loading of the compatibility class for Deposits in versions
* of Deposits that support multi-currency.
*
* @see https://github.com/woocommerce/woocommerce-deposits/pull/425
* @see https://github.com/woocommerce/woocommerce-deposits/issues/506
*/
if ( version_compare( WC_DEPOSITS_VERSION, '2.0.1', '>=' ) ) {
return;
}

// Add compatibility filters here.
add_action( 'woocommerce_deposits_create_order', [ $this, 'modify_order_currency' ] );
add_filter( 'woocommerce_get_cart_contents', [ $this, 'modify_cart_item_deposit_amounts' ] );
Expand Down
2 changes: 1 addition & 1 deletion readme.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== WooPayments - Fully Integrated Solution Built and Supported by Woo ===
Contributors: woocommerce, automattic
Tags: payment gateway, payment, apple pay, credit card, google pay, woocommerce payments
Tags: woocommerce payments, apple pay, credit card, google pay, payment, payment gateway
Requires at least: 6.0
Tested up to: 6.2
Requires PHP: 7.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
use WCPay\Database_Cache;
use WCPay\Internal\DependencyManagement\AbstractServiceProvider;
use WCPay\Internal\Payment\Router;
use WCPay\Internal\Payment\State\AuthenticationRequiredState;
use WCPay\Internal\Payment\State\CompletedState;
use WCPay\Internal\Payment\State\InitialState;
use WCPay\Internal\Payment\State\PaymentErrorState;
use WCPay\Internal\Payment\State\ProcessedState;
use WCPay\Internal\Payment\State\StateFactory;
use WCPay\Internal\Payment\State\SystemErrorState;
use WCPay\Internal\Proxy\LegacyProxy;
Expand All @@ -41,6 +43,8 @@ class PaymentsServiceProvider extends AbstractServiceProvider {
Router::class,
StateFactory::class,
InitialState::class,
AuthenticationRequiredState::class,
ProcessedState::class,
CompletedState::class,
SystemErrorState::class,
PaymentErrorState::class,
Expand Down Expand Up @@ -71,6 +75,13 @@ public function register(): void {
->addArgument( Level3Service::class )
->addArgument( PaymentRequestService::class );

$container->add( ProcessedState::class )
->addArgument( StateFactory::class )
->addArgument( OrderService::class );

$container->add( AuthenticationRequiredState::class )
->addArgument( StateFactory::class );

$container->add( CompletedState::class )
->addArgument( StateFactory::class );

Expand Down
19 changes: 19 additions & 0 deletions src/Internal/Payment/PaymentContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace WCPay\Internal\Payment;

use WC_Payments_API_Abstract_Intention;
use WCPay\Internal\Payment\PaymentMethod\PaymentMethodInterface;

/**
Expand Down Expand Up @@ -225,6 +226,24 @@ public function get_customer_id(): ?string {
return $this->get( 'customer_id' );
}

/**
* Stores the payment intent object.
*
* @param WC_Payments_API_Abstract_Intention $intent Instance of intent.
*/
public function set_intent( WC_Payments_API_Abstract_Intention $intent ) {
$this->set( 'intent', $intent );
}

/**
* Returns the payment intent object.
*
* @return WC_Payments_API_Abstract_Intention|null
*/
public function get_intent(): ?WC_Payments_API_Abstract_Intention {
return $this->get( 'intent' );
}

/**
* Stores an internal value.
* Use this method for changes to allow logging in the future.
Expand Down
31 changes: 21 additions & 10 deletions src/Internal/Payment/State/AbstractPaymentState.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,37 @@ public function get_context(): PaymentContext {
return $this->context;
}

// phpcs:disable Squiz.Commenting.FunctionComment.InvalidNoReturn
/**
* State-specific methods might declare a return type, but
* their hollow definitions here would only throw an exception.
* phpcs:disable Squiz.Commenting.FunctionComment.InvalidNoReturn
*/

/**
* Initialtes the payment process.
* Initiates the payment process.
*
* @psalm-suppress InvalidReturnType
*
* @param PaymentRequest $request The incoming payment processing request.
* @return CompletedState The next state.
* @return AbstractPaymentState The next state.
*
* @throws StateTransitionException In case the completed state could not be initialized.
* @throws ContainerException When the dependency container cannot instantiate the state.
* @throws Order_Not_Found_Exception Order could not be found.
* @throws PaymentRequestException When data is not available or invalid.
* @psalm-suppress InvalidReturnType If this method does not throw, it will return a new state.
*/
public function process( PaymentRequest $request ) {
public function start_processing( PaymentRequest $request ) {
$this->throw_unavailable_method_exception( __METHOD__ );
}

/**
* Complete processing.
*
* @psalm-suppress InvalidReturnType
*
* @return AbstractPaymentState
* @throws Order_Not_Found_Exception
* @throws StateTransitionException
*/
public function complete_processing() {
$this->throw_unavailable_method_exception( __METHOD__ );
}
// phpcs:enable Squiz.Commenting.FunctionComment.InvalidNoReturn

/**
* Creates a new instance of a given payment state class.
Expand Down
14 changes: 14 additions & 0 deletions src/Internal/Payment/State/AuthenticationRequiredState.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
/**
* Class AuthenticationRequiredState
*
* @package WooCommerce\Payments
*/

namespace WCPay\Internal\Payment\State;

/**
* The state, which indicates that the payment requires authentication (3DS).
*/
class AuthenticationRequiredState extends AbstractPaymentState {
}
38 changes: 21 additions & 17 deletions src/Internal/Payment/State/InitialState.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
namespace WCPay\Internal\Payment\State;

use WC_Payments_Customer_Service;
use WCPay\Constants\Intent_Status;
use WCPay\Core\Exceptions\Server\Request\Extend_Request_Exception;
use WCPay\Core\Exceptions\Server\Request\Immutable_Parameter_Exception;
use WCPay\Core\Exceptions\Server\Request\Invalid_Request_Parameter_Exception;
use WCPay\Internal\Service\PaymentRequestService;
use WCPay\Vendor\League\Container\Exception\ContainerException;
use WCPay\Internal\Payment\Exception\StateTransitionException;
use WCPay\Internal\Service\OrderService;
use WCPay\Internal\Service\Level3Service;
use WCPay\Internal\Service\PaymentRequestService;
use WCPay\Core\Exceptions\Server\Request\Extend_Request_Exception;
use WCPay\Core\Exceptions\Server\Request\Immutable_Parameter_Exception;
use WCPay\Core\Exceptions\Server\Request\Invalid_Request_Parameter_Exception;
use WCPay\Exceptions\Order_Not_Found_Exception;
use WCPay\Internal\Payment\PaymentContext;
use WCPay\Internal\Payment\PaymentRequest;
use WCPay\Internal\Payment\PaymentRequestException;

Expand Down Expand Up @@ -78,19 +78,17 @@ public function __construct(
}

/**
* Initialtes the payment process.
* Initiates the payment process.
*
* @param PaymentRequest $request The incoming payment processing request.
*
* @param PaymentRequest $request The incoming payment processing request.
* @return CompletedState The next state.
* @return AbstractPaymentState The next state.
* @throws StateTransitionException In case the completed state could not be initialized.
* @throws ContainerException When the dependency container cannot instantiate the state.
* @throws Order_Not_Found_Exception Order could not be found.
* @throws PaymentRequestException When data is not available or invalid.
*/
public function process( PaymentRequest $request ) {
$context = $this->get_context();
$order_id = $context->get_order_id();

public function start_processing( PaymentRequest $request ) {
// Populate basic details from the request.
$this->populate_context_from_request( $request );

Expand All @@ -99,16 +97,22 @@ public function process( PaymentRequest $request ) {

// Payments are currently based on intents, request one from the API.
try {
$intent = $this->payment_request_service->create_intent( $context );
$context = $this->get_context();
$intent = $this->payment_request_service->create_intent( $context );
$context->set_intent( $intent );
} catch ( Invalid_Request_Parameter_Exception | Extend_Request_Exception | Immutable_Parameter_Exception $e ) {
return $this->create_state( SystemErrorState::class );
}

// Intent available, complete processing.
$this->order_service->update_order_from_successful_intent( $order_id, $intent, $context );
// Intent requires authorization (3DS check).
if ( Intent_Status::REQUIRES_ACTION === $intent->get_status() ) {
return $this->create_state( AuthenticationRequiredState::class );
}

// All good. Proceed to processed state.
$next_state = $this->create_state( ProcessedState::class );

// If everything went well, transition to the completed state.
return $this->create_state( CompletedState::class );
return $next_state->complete_processing();
}

/**
Expand Down
58 changes: 58 additions & 0 deletions src/Internal/Payment/State/ProcessedState.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
/**
* Class ProcessedState
*
* @package WooCommerce\Payments
*/

namespace WCPay\Internal\Payment\State;

use WCPay\Exceptions\Order_Not_Found_Exception;
use WCPay\Internal\Payment\Exception\StateTransitionException;
use WCPay\Internal\Service\OrderService;
use WCPay\Vendor\League\Container\Exception\ContainerException;

/**
* This state is used when payment is completed on the server, and we need to update date on the plugin side.
*/
class ProcessedState extends AbstractPaymentState {
/**
* Order service.
*
* @var OrderService
*/
private $order_service;

/**
* Class constructor, only meant for storing dependencies.
*
* @param StateFactory $state_factory Factory for payment states.
* @param OrderService $order_service Service for order-related actions.
*/
public function __construct(
StateFactory $state_factory,
OrderService $order_service
) {
parent::__construct( $state_factory );

$this->order_service = $order_service;
}

/**
* Complete processing.
*
* @return AbstractPaymentState
* @throws Order_Not_Found_Exception
* @throws StateTransitionException
* @throws ContainerException
*/
public function complete_processing() {
$context = $this->get_context();

// Complete processing.
$this->order_service->update_order_from_successful_intent( $context->get_order_id(), $context->get_intent(), $context );

// If everything went well, transition to the completed state.
return $this->create_state( CompletedState::class );
}
}
Loading

0 comments on commit ce8d718

Please sign in to comment.