mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 18:16:38 +08:00
Use Composer modules and convert modules to PSR-4
PSR-4 is much more robust and predictable. But to do this, a source root dir must be specified for every module. This could be done in the root file, but this is not very modular. Instead, now every module declares its own source root by using the amazing Composer Merge Plugin. This approach allows each module to also declare its own dependencies. Together, these changes allow modules to be easily extractable to separate pacakges when the need arises, and in general improves modularity significantly.
This commit is contained in:
parent
45db097bd8
commit
d4c8282518
157 changed files with 168 additions and 8 deletions
338
modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php
Normal file
338
modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php
Normal file
|
@ -0,0 +1,338 @@
|
|||
<?php
|
||||
/**
|
||||
* Processes orders for the gateways.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Processor
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class OrderProcessor
|
||||
*/
|
||||
class OrderProcessor {
|
||||
|
||||
/**
|
||||
* Whether current payment mode is sandbox.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $sandbox_mode;
|
||||
|
||||
/**
|
||||
* The payment token repository.
|
||||
*
|
||||
* @var PaymentTokenRepository
|
||||
*/
|
||||
protected $payment_token_repository;
|
||||
|
||||
/**
|
||||
* The Session Handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* The Order Endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
private $order_endpoint;
|
||||
|
||||
/**
|
||||
* The Order Factory.
|
||||
*
|
||||
* @var OrderFactory
|
||||
*/
|
||||
private $order_factory;
|
||||
|
||||
/**
|
||||
* The helper for 3d secure.
|
||||
*
|
||||
* @var ThreeDSecure
|
||||
*/
|
||||
private $threed_secure;
|
||||
|
||||
/**
|
||||
* The processor for authorized payments.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor
|
||||
*/
|
||||
private $authorized_payments_processor;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The last error.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $last_error = '';
|
||||
|
||||
/**
|
||||
* A logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* OrderProcessor constructor.
|
||||
*
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param OrderEndpoint $order_endpoint The Order Endpoint.
|
||||
* @param OrderFactory $order_factory The Order Factory.
|
||||
* @param ThreeDSecure $three_d_secure The ThreeDSecure Helper.
|
||||
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor.
|
||||
* @param Settings $settings The Settings.
|
||||
* @param LoggerInterface $logger A logger service.
|
||||
* @param bool $sandbox_mode Whether sandbox mode enabled.
|
||||
*/
|
||||
public function __construct(
|
||||
SessionHandler $session_handler,
|
||||
OrderEndpoint $order_endpoint,
|
||||
OrderFactory $order_factory,
|
||||
ThreeDSecure $three_d_secure,
|
||||
AuthorizedPaymentsProcessor $authorized_payments_processor,
|
||||
Settings $settings,
|
||||
LoggerInterface $logger,
|
||||
bool $sandbox_mode
|
||||
) {
|
||||
|
||||
$this->session_handler = $session_handler;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->order_factory = $order_factory;
|
||||
$this->threed_secure = $three_d_secure;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
$this->settings = $settings;
|
||||
$this->sandbox_mode = $sandbox_mode;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a given WooCommerce order and captured/authorizes the connected PayPal orders.
|
||||
*
|
||||
* @param \WC_Order $wc_order The WooCommerce order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function process( \WC_Order $wc_order ): bool {
|
||||
$order = $this->session_handler->order();
|
||||
if ( ! $order ) {
|
||||
return false;
|
||||
}
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() );
|
||||
$wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() );
|
||||
$wc_order->update_meta_data(
|
||||
PayPalGateway::ORDER_PAYMENT_MODE_META_KEY,
|
||||
$this->sandbox_mode ? 'sandbox' : 'live'
|
||||
);
|
||||
|
||||
$error_message = null;
|
||||
if ( ! $this->order_is_approved( $order ) ) {
|
||||
$error_message = __(
|
||||
'The payment has not been approved yet.',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
}
|
||||
if ( $error_message ) {
|
||||
$this->last_error = sprintf(
|
||||
// translators: %s is the message of the error.
|
||||
__( 'Payment error: %s', 'woocommerce-paypal-payments' ),
|
||||
$error_message
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$order = $this->patch_order( $wc_order, $order );
|
||||
if ( $order->intent() === 'CAPTURE' ) {
|
||||
$order = $this->order_endpoint->capture( $order );
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'AUTHORIZE' ) {
|
||||
$order = $this->order_endpoint->authorize( $order );
|
||||
$wc_order->update_meta_data( PayPalGateway::CAPTURED_META_KEY, 'false' );
|
||||
}
|
||||
|
||||
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
||||
|
||||
if ( '' !== $transaction_id ) {
|
||||
$this->set_order_transaction_id( $transaction_id, $wc_order );
|
||||
}
|
||||
|
||||
$wc_order->update_status(
|
||||
'on-hold',
|
||||
__( 'Awaiting payment.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
if ( $order->status()->is( OrderStatus::COMPLETED ) && $order->intent() === 'CAPTURE' ) {
|
||||
|
||||
$wc_order->payment_complete();
|
||||
}
|
||||
|
||||
if ( $this->capture_authorized_downloads( $order ) && $this->authorized_payments_processor->process( $wc_order ) ) {
|
||||
$wc_order->add_order_note(
|
||||
__( 'Payment successfully captured.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
$wc_order->update_meta_data( PayPalGateway::CAPTURED_META_KEY, 'true' );
|
||||
$wc_order->update_status( 'processing' );
|
||||
}
|
||||
WC()->cart->empty_cart();
|
||||
$this->session_handler->destroy_session_data();
|
||||
$this->last_error = '';
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set transaction id to WC order meta data.
|
||||
*
|
||||
* @param string $transaction_id Transaction id to set.
|
||||
* @param \WC_Order $wc_order Order to set transaction ID to.
|
||||
*/
|
||||
public function set_order_transaction_id( string $transaction_id, \WC_Order $wc_order ) {
|
||||
try {
|
||||
$wc_order->set_transaction_id( $transaction_id );
|
||||
} catch ( \WC_Data_Exception $exception ) {
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
sprintf(
|
||||
'Failed to set transaction ID. Exception caught when tried: %1$s',
|
||||
$exception->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve transaction id from PayPal order.
|
||||
*
|
||||
* @param Order $order Order to get transaction id from.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_paypal_order_transaction_id( Order $order ): string {
|
||||
$purchase_units = $order->purchase_units();
|
||||
|
||||
if ( ! isset( $purchase_units[0] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$payments = $purchase_units[0]->payments();
|
||||
|
||||
if ( null === $payments ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$captures = $payments->captures();
|
||||
|
||||
if ( isset( $captures[0] ) ) {
|
||||
return $captures[0]->id();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if an order should be captured immediately.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function capture_authorized_downloads( Order $order ): bool {
|
||||
if (
|
||||
! $this->settings->has( 'capture_for_virtual_only' )
|
||||
|| ! $this->settings->get( 'capture_for_virtual_only' )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'CAPTURE' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* We fetch the order again as the authorize endpoint (from which the Order derives)
|
||||
* drops the item's category, making it impossible to check, if purchase units contain
|
||||
* physical goods.
|
||||
*/
|
||||
$order = $this->order_endpoint->order( $order->id() );
|
||||
|
||||
foreach ( $order->purchase_units() as $unit ) {
|
||||
if ( $unit->contains_physical_goods() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last error.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function last_error(): string {
|
||||
|
||||
return $this->last_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches a given PayPal order with a WooCommerce order.
|
||||
*
|
||||
* @param \WC_Order $wc_order The WooCommerce order.
|
||||
* @param Order $order The PayPal order.
|
||||
*
|
||||
* @return Order
|
||||
*/
|
||||
public function patch_order( \WC_Order $wc_order, Order $order ): Order {
|
||||
$updated_order = $this->order_factory->from_wc_order( $wc_order, $order );
|
||||
$order = $this->order_endpoint->patch_order_with( $order, $updated_order );
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a given order is approved.
|
||||
*
|
||||
* @param Order $order The order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function order_is_approved( Order $order ): bool {
|
||||
|
||||
if ( $order->status()->is( OrderStatus::APPROVED ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! $order->payment_source() || ! $order->payment_source()->card() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$is_approved = in_array(
|
||||
$this->threed_secure->proceed_with_order( $order ),
|
||||
array(
|
||||
ThreeDSecure::NO_DECISION,
|
||||
ThreeDSecure::PROCCEED,
|
||||
),
|
||||
true
|
||||
);
|
||||
return $is_approved;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue