Create wc order in approval webhook if missing

This commit is contained in:
Alex P 2023-06-14 12:44:06 +03:00
parent 10d99578d6
commit 46ea7621d3
No known key found for this signature in database
GPG key ID: 54487A734A204D71
8 changed files with 302 additions and 44 deletions

View file

@ -9,11 +9,18 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
use WC_Checkout;
use WC_Order;
use WC_Session_Handler;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\Session\MemoryWcSession;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
/**
* Class CheckoutOrderApproved
@ -36,15 +43,48 @@ class CheckoutOrderApproved implements RequestHandler {
*/
private $order_endpoint;
/**
* The Session handler.
*
* @var SessionHandler
*/
private $session_handler;
/**
* The funding source renderer.
*
* @var FundingSourceRenderer
*/
protected $funding_source_renderer;
/**
* The processor for orders.
*
* @var OrderProcessor
*/
protected $order_processor;
/**
* CheckoutOrderApproved constructor.
*
* @param LoggerInterface $logger The logger.
* @param OrderEndpoint $order_endpoint The order endpoint.
* @param LoggerInterface $logger The logger.
* @param OrderEndpoint $order_endpoint The order endpoint.
* @param SessionHandler $session_handler The session handler.
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
* @param OrderProcessor $order_processor The Order Processor.
*/
public function __construct( LoggerInterface $logger, OrderEndpoint $order_endpoint ) {
$this->logger = $logger;
$this->order_endpoint = $order_endpoint;
public function __construct(
LoggerInterface $logger,
OrderEndpoint $order_endpoint,
SessionHandler $session_handler,
FundingSourceRenderer $funding_source_renderer,
OrderProcessor $order_processor
) {
$this->logger = $logger;
$this->order_endpoint = $order_endpoint;
$this->session_handler = $session_handler;
$this->funding_source_renderer = $funding_source_renderer;
$this->order_processor = $order_processor;
}
/**
@ -77,36 +117,93 @@ class CheckoutOrderApproved implements RequestHandler {
* @return \WP_REST_Response
*/
public function handle_request( \WP_REST_Request $request ): \WP_REST_Response {
$custom_ids = $this->get_custom_ids_from_request( $request );
if ( empty( $custom_ids ) ) {
return $this->no_custom_ids_response( $request );
}
try {
$order = isset( $request['resource']['id'] ) ?
$this->order_endpoint->order( $request['resource']['id'] ) : null;
if ( ! $order ) {
$message = sprintf(
'No paypal payment for webhook event %s was found.',
isset( $request['id'] ) ? $request['id'] : ''
);
return $this->failure_response( $message );
}
if ( $order->intent() === 'CAPTURE' ) {
$order = $this->order_endpoint->capture( $order );
}
} catch ( RuntimeException $error ) {
$message = sprintf(
'Could not capture payment for webhook event %s.',
isset( $request['id'] ) ? $request['id'] : ''
$order_id = isset( $request['resource']['id'] ) ? $request['resource']['id'] : null;
if ( ! $order_id ) {
return $this->failure_response(
sprintf(
'No order ID in webhook event %s.',
$request['id'] ?: ''
)
);
return $this->failure_response( $message );
}
$wc_orders = $this->get_wc_orders_from_custom_ids( $custom_ids );
if ( ! $wc_orders ) {
return $this->no_wc_orders_response( $request );
$order = $this->order_endpoint->order( $order_id );
if ( $order->status()->is( OrderStatus::COMPLETED ) ) {
return $this->success_response();
}
$wc_orders = array();
$custom_ids = $this->get_wc_order_ids_from_request( $request );
if ( empty( $custom_ids ) ) {
$custom_ids = $this->get_wc_customer_ids_from_request( $request );
if ( empty( $custom_ids ) ) {
return $this->no_custom_ids_response( $request );
}
$customer_id = $custom_ids[0];
$wc_session = new WC_Session_Handler();
$session_data = $wc_session->get_session( $customer_id );
if ( ! is_array( $session_data ) ) {
return $this->failure_response( "Failed to get session data {$customer_id}" );
}
MemoryWcSession::replace_session_handler( $session_data, $customer_id );
wc_load_cart();
WC()->cart->get_cart_from_session();
WC()->cart->calculate_shipping();
$form = $this->session_handler->checkout_form();
$checkout = new WC_Checkout();
$wc_order_id = $checkout->create_order( $form );
$wc_order = wc_get_order( $wc_order_id );
if ( ! $wc_order instanceof WC_Order ) {
return $this->failure_response(
sprintf(
'Failed to create WC order in webhook event %s.',
$request['id'] ?: ''
)
);
}
$funding_source = $this->session_handler->funding_source();
if ( $funding_source ) {
$wc_order->set_payment_method_title( $this->funding_source_renderer->render_name( $funding_source ) );
}
if ( is_numeric( $customer_id ) ) {
$wc_order->set_customer_id( (int) $customer_id );
}
$wc_order->save();
$wc_orders[] = $wc_order;
add_action(
'shutdown',
function () use ( $customer_id ): void {
$session = WC()->session;
assert( $session instanceof WC_Session_Handler );
/**
* Wrong type-hint.
*
* @psalm-suppress InvalidScalarArgument
*/
$session->delete_session( $customer_id );
$session->forget_session();
}
);
} else {
$wc_orders = $this->get_wc_orders_from_custom_ids( $custom_ids );
if ( ! $wc_orders ) {
return $this->no_wc_orders_response( $request );
}
}
foreach ( $wc_orders as $wc_order ) {
@ -117,17 +214,20 @@ class CheckoutOrderApproved implements RequestHandler {
if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) {
continue;
}
if ( $order->intent() === 'CAPTURE' ) {
$wc_order->payment_complete();
} else {
$wc_order->update_status(
'on-hold',
__( 'Payment can be captured.', 'woocommerce-paypal-payments' )
if ( ! $this->order_processor->process( $wc_order ) ) {
return $this->failure_response(
sprintf(
'Failed to process WC order %s: %s.',
(string) $wc_order->get_id(),
$this->order_processor->last_error()
)
);
}
$this->logger->info(
sprintf(
'Order %s has been updated through PayPal',
'WC order %s has been processed after approval in PayPal.',
(string) $wc_order->get_id()
)
);