349 lines
11 KiB
PHP
349 lines
11 KiB
PHP
<?php
|
|
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
|
|
|
|
use Exception;
|
|
use WC_Stripe_Payment_Request;
|
|
use WC_Stripe_Helper;
|
|
use WC_Gateway_Stripe;
|
|
use Automattic\WooCommerce\Blocks\Assets\Api;
|
|
use Automattic\WooCommerce\Blocks\Payments\PaymentContext;
|
|
use Automattic\WooCommerce\Blocks\Payments\PaymentResult;
|
|
|
|
/**
|
|
* Stripe payment method integration
|
|
*
|
|
* Temporary integration of the stripe payment method for the new cart and
|
|
* checkout blocks. Once the api is demonstrated to be stable, this integration
|
|
* will be moved to the Stripe extension
|
|
*
|
|
* @since 2.6.0
|
|
*/
|
|
final class Stripe extends AbstractPaymentMethodType {
|
|
/**
|
|
* Payment method name defined by payment methods extending this class.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $name = 'stripe';
|
|
|
|
/**
|
|
* An instance of the Asset Api
|
|
*
|
|
* @var Api
|
|
*/
|
|
private $asset_api;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param Api $asset_api An instance of Api.
|
|
*/
|
|
public function __construct( Api $asset_api ) {
|
|
$this->asset_api = $asset_api;
|
|
add_action( 'woocommerce_rest_checkout_process_payment_with_context', [ $this, 'add_payment_request_order_meta' ], 8, 2 );
|
|
add_action( 'woocommerce_rest_checkout_process_payment_with_context', [ $this, 'add_stripe_intents' ], 9999, 2 );
|
|
}
|
|
|
|
/**
|
|
* Initializes the payment method type.
|
|
*/
|
|
public function initialize() {
|
|
$this->settings = get_option( 'woocommerce_stripe_settings', [] );
|
|
}
|
|
|
|
/**
|
|
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function is_active() {
|
|
return ! empty( $this->settings['enabled'] ) && 'yes' === $this->settings['enabled'];
|
|
}
|
|
|
|
/**
|
|
* Returns an array of scripts/handles to be registered for this payment method.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_payment_method_script_handles() {
|
|
$this->asset_api->register_script(
|
|
'wc-payment-method-stripe',
|
|
'build/wc-payment-method-stripe.js',
|
|
[]
|
|
);
|
|
|
|
return [ 'wc-payment-method-stripe' ];
|
|
}
|
|
|
|
/**
|
|
* Returns an array of key=>value pairs of data made available to the payment methods script.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_payment_method_data() {
|
|
return [
|
|
'stripeTotalLabel' => $this->get_total_label(),
|
|
'publicKey' => $this->get_publishable_key(),
|
|
'allowPrepaidCard' => $this->get_allow_prepaid_card(),
|
|
'title' => $this->get_title(),
|
|
'button' => [
|
|
'type' => $this->get_button_type(),
|
|
'theme' => $this->get_button_theme(),
|
|
'height' => $this->get_button_height(),
|
|
'locale' => $this->get_button_locale(),
|
|
],
|
|
'inline_cc_form' => $this->get_inline_cc_form(),
|
|
'icons' => $this->get_icons(),
|
|
'showSavedCards' => $this->get_show_saved_cards(),
|
|
'allowPaymentRequest' => $this->get_allow_payment_request(),
|
|
'showSaveOption' => $this->get_show_save_option(),
|
|
'supports' => $this->get_supported_features(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Determine if store allows cards to be saved during checkout.
|
|
*
|
|
* @return bool True if merchant allows shopper to save card (payment method) during checkout).
|
|
*/
|
|
private function get_show_saved_cards() {
|
|
return isset( $this->settings['saved_cards'] ) ? 'yes' === $this->settings['saved_cards'] : false;
|
|
}
|
|
|
|
/**
|
|
* Determine if the checkbox to enable the user to save their payment method should be shown.
|
|
*
|
|
* @return bool True if the save payment checkbox should be displayed to the user.
|
|
*/
|
|
private function get_show_save_option() {
|
|
$saved_cards = $this->get_show_saved_cards();
|
|
// This assumes that Stripe supports `tokenization` - currently this is true, based on
|
|
// https://github.com/woocommerce/woocommerce-gateway-stripe/blob/master/includes/class-wc-gateway-stripe.php#L95 .
|
|
// See https://github.com/woocommerce/woocommerce-gateway-stripe/blob/ad19168b63df86176cbe35c3e95203a245687640/includes/class-wc-gateway-stripe.php#L271 and
|
|
// https://github.com/woocommerce/woocommerce/wiki/Payment-Token-API .
|
|
return apply_filters( 'wc_stripe_display_save_payment_method_checkbox', filter_var( $saved_cards, FILTER_VALIDATE_BOOLEAN ) );
|
|
}
|
|
|
|
/**
|
|
* Returns the label to use accompanying the total in the stripe statement.
|
|
*
|
|
* @return string Statement descriptor.
|
|
*/
|
|
private function get_total_label() {
|
|
return ! empty( $this->settings['statement_descriptor'] ) ? WC_Stripe_Helper::clean_statement_descriptor( $this->settings['statement_descriptor'] ) : '';
|
|
}
|
|
|
|
/**
|
|
* Returns the publishable api key for the Stripe service.
|
|
*
|
|
* @return string Public api key.
|
|
*/
|
|
private function get_publishable_key() {
|
|
$test_mode = ( ! empty( $this->settings['testmode'] ) && 'yes' === $this->settings['testmode'] );
|
|
$setting_key = $test_mode ? 'test_publishable_key' : 'publishable_key';
|
|
return ! empty( $this->settings[ $setting_key ] ) ? $this->settings[ $setting_key ] : '';
|
|
}
|
|
|
|
/**
|
|
* Returns whether to allow prepaid cards for payments.
|
|
*
|
|
* @return bool True means to allow prepaid card (default).
|
|
*/
|
|
private function get_allow_prepaid_card() {
|
|
return apply_filters( 'wc_stripe_allow_prepaid_card', true );
|
|
}
|
|
|
|
/**
|
|
* Returns the title string to use in the UI (customisable via admin settings screen).
|
|
*
|
|
* @return string Title / label string
|
|
*/
|
|
private function get_title() {
|
|
return isset( $this->settings['title'] ) ? $this->settings['title'] : __( 'Credit / Debit Card', 'woocommerce' );
|
|
}
|
|
|
|
/**
|
|
* Determine if store allows Payment Request buttons - e.g. Apple Pay / Chrome Pay.
|
|
*
|
|
* @return bool True if merchant has opted into payment request.
|
|
*/
|
|
private function get_allow_payment_request() {
|
|
$option = isset( $this->settings['payment_request'] ) ? $this->settings['payment_request'] : false;
|
|
return filter_var( $option, FILTER_VALIDATE_BOOLEAN );
|
|
}
|
|
|
|
/**
|
|
* Return the button type for the payment button.
|
|
*
|
|
* @return string Defaults to 'default'.
|
|
*/
|
|
private function get_button_type() {
|
|
return isset( $this->settings['payment_request_button_type'] ) ? $this->settings['payment_request_button_type'] : 'default';
|
|
}
|
|
|
|
/**
|
|
* Return the theme to use for the payment button.
|
|
*
|
|
* @return string Defaults to 'dark'.
|
|
*/
|
|
private function get_button_theme() {
|
|
return isset( $this->settings['payment_request_button_theme'] ) ? $this->settings['payment_request_button_theme'] : 'dark';
|
|
}
|
|
|
|
/**
|
|
* Return the height for the payment button.
|
|
*
|
|
* @return string A pixel value for the height (defaults to '64').
|
|
*/
|
|
private function get_button_height() {
|
|
return isset( $this->settings['payment_request_button_height'] ) ? str_replace( 'px', '', $this->settings['payment_request_button_height'] ) : '64';
|
|
}
|
|
|
|
/**
|
|
* Return the inline cc option.
|
|
*
|
|
* @return boolean True if the inline CC form option is enabled.
|
|
*/
|
|
private function get_inline_cc_form() {
|
|
return isset( $this->settings['inline_cc_form'] ) && 'yes' === $this->settings['inline_cc_form'];
|
|
}
|
|
|
|
/**
|
|
* Return the locale for the payment button.
|
|
*
|
|
* @return string Defaults to en_US.
|
|
*/
|
|
private function get_button_locale() {
|
|
return apply_filters( 'wc_stripe_payment_request_button_locale', substr( get_locale(), 0, 2 ) );
|
|
}
|
|
|
|
/**
|
|
* Return the icons urls.
|
|
*
|
|
* @return array Arrays of icons metadata.
|
|
*/
|
|
private function get_icons() {
|
|
$icons_src = [
|
|
'visa' => [
|
|
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/visa.svg',
|
|
'alt' => __( 'Visa', 'woocommerce' ),
|
|
],
|
|
'amex' => [
|
|
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/amex.svg',
|
|
'alt' => __( 'American Express', 'woocommerce' ),
|
|
],
|
|
'mastercard' => [
|
|
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/mastercard.svg',
|
|
'alt' => __( 'Mastercard', 'woocommerce' ),
|
|
],
|
|
];
|
|
|
|
if ( 'USD' === get_woocommerce_currency() ) {
|
|
$icons_src['discover'] = [
|
|
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/discover.svg',
|
|
'alt' => __( 'Discover', 'woocommerce' ),
|
|
];
|
|
$icons_src['jcb'] = [
|
|
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/jcb.svg',
|
|
'alt' => __( 'JCB', 'woocommerce' ),
|
|
];
|
|
$icons_src['diners'] = [
|
|
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/diners.svg',
|
|
'alt' => __( 'Diners', 'woocommerce' ),
|
|
];
|
|
}
|
|
return $icons_src;
|
|
}
|
|
|
|
/**
|
|
* Add payment request data to the order meta as hooked on the
|
|
* woocommerce_rest_checkout_process_payment_with_context action.
|
|
*
|
|
* @param PaymentContext $context Holds context for the payment.
|
|
* @param PaymentResult $result Result object for the payment.
|
|
*/
|
|
public function add_payment_request_order_meta( PaymentContext $context, PaymentResult &$result ) {
|
|
$data = $context->payment_data;
|
|
if ( ! empty( $data['payment_request_type'] ) && 'stripe' === $context->payment_method ) {
|
|
// phpcs:ignore WordPress.Security.NonceVerification
|
|
$post_data = $_POST;
|
|
$_POST = $context->payment_data;
|
|
$this->add_order_meta( $context->order, $data['payment_request_type'] );
|
|
$_POST = $post_data;
|
|
}
|
|
|
|
// hook into stripe error processing so that we can capture the error to
|
|
// payment details (which is added to notices and thus not helpful for
|
|
// this context).
|
|
if ( 'stripe' === $context->payment_method ) {
|
|
add_action(
|
|
'wc_gateway_stripe_process_payment_error',
|
|
function( $error ) use ( &$result ) {
|
|
$payment_details = $result->payment_details;
|
|
$payment_details['errorMessage'] = wp_strip_all_tags( $error->getLocalizedMessage() );
|
|
$result->set_payment_details( $payment_details );
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles any potential stripe intents on the order that need handled.
|
|
*
|
|
* This is configured to execute after legacy payment processing has
|
|
* happened on the woocommerce_rest_checkout_process_payment_with_context
|
|
* action hook.
|
|
*
|
|
* @param PaymentContext $context Holds context for the payment.
|
|
* @param PaymentResult $result Result object for the payment.
|
|
*/
|
|
public function add_stripe_intents( PaymentContext $context, PaymentResult &$result ) {
|
|
if ( 'stripe' === $context->payment_method
|
|
&& (
|
|
! empty( $result->payment_details['payment_intent_secret'] )
|
|
|| ! empty( $result->payment_details['setup_intent_secret'] )
|
|
)
|
|
) {
|
|
$payment_details = $result->payment_details;
|
|
$payment_details['verification_endpoint'] = add_query_arg(
|
|
[
|
|
'order' => $context->order->get_id(),
|
|
'nonce' => wp_create_nonce( 'wc_stripe_confirm_pi' ),
|
|
'redirect_to' => rawurlencode( $result->redirect_url ),
|
|
],
|
|
home_url() . \WC_Ajax::get_endpoint( 'wc_stripe_verify_intent' )
|
|
);
|
|
$result->set_payment_details( $payment_details );
|
|
$result->set_status( 'success' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles adding information about the payment request type used to the order meta.
|
|
*
|
|
* @param \WC_Order $order The order being processed.
|
|
* @param string $payment_request_type The payment request type used for payment.
|
|
*/
|
|
private function add_order_meta( \WC_Order $order, string $payment_request_type ) {
|
|
if ( 'apple_pay' === $payment_request_type ) {
|
|
$order->set_payment_method_title( 'Apple Pay (Stripe)' );
|
|
$order->save();
|
|
}
|
|
|
|
if ( 'payment_request_api' === $payment_request_type ) {
|
|
$order->set_payment_method_title( 'Chrome Payment Request (Stripe)' );
|
|
$order->save();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns an array of supported features.
|
|
*
|
|
* @return string[]
|
|
*/
|
|
public function get_supported_features() {
|
|
$gateway = new WC_Gateway_Stripe();
|
|
return array_filter( $gateway->supports, array( $gateway, 'supports' ) );
|
|
}
|
|
}
|