mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-04 08:47:23 +08:00
Merge branch 'trunk' into PCP-2085-next-payment-status-not-updated-when-using-pay-pal-subscriptions
This commit is contained in:
commit
aeecb72589
68 changed files with 1695 additions and 330 deletions
|
@ -87,6 +87,32 @@ function ppcp_capture_order( WC_Order $wc_order ): void {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthorizes the PayPal order.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @throws InvalidArgumentException When the order cannot be captured.
|
||||
* @throws Exception When the operation fails.
|
||||
*/
|
||||
function ppcp_reauthorize_order( WC_Order $wc_order ): void {
|
||||
$intent = strtoupper( (string) $wc_order->get_meta( PayPalGateway::INTENT_META_KEY ) );
|
||||
|
||||
if ( $intent !== 'AUTHORIZE' ) {
|
||||
throw new InvalidArgumentException( 'Only orders with "authorize" intent can be reauthorized.' );
|
||||
}
|
||||
$captured = wc_string_to_bool( $wc_order->get_meta( AuthorizedPaymentsProcessor::CAPTURED_META_KEY ) );
|
||||
if ( $captured ) {
|
||||
throw new InvalidArgumentException( 'The order is already captured.' );
|
||||
}
|
||||
|
||||
$authorized_payment_processor = PPCP::container()->get( 'wcgateway.processor.authorized-payments' );
|
||||
assert( $authorized_payment_processor instanceof AuthorizedPaymentsProcessor );
|
||||
|
||||
if ( $authorized_payment_processor->reauthorize_payment( $wc_order ) !== AuthorizedPaymentsProcessor::SUCCESSFUL ) {
|
||||
throw new RuntimeException( $authorized_payment_processor->reauthorization_failure_reason() ?: 'Reauthorization failed.' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refunds the PayPal order.
|
||||
* Note that you can use wc_refund_payment() to trigger the refund in WC and PayPal.
|
||||
|
|
|
@ -1,5 +1,40 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 2.6.1 - 2024-04-09 =
|
||||
* Fix - Payment tokens fixes and adjustments #2106
|
||||
* Fix - Pay upon Invoice: Add input validation to Experience Context fields #2092
|
||||
* Fix - Disable markup in get_plugin_data() returns to fix an issue with wptexturize() #2094
|
||||
* Fix - Problem changing the shipping option in block pages #2142
|
||||
* Fix - Saved payment token deleted after payment with another saved payment token #2146
|
||||
* Enhancement - Pay later messaging configurator improvements #2107
|
||||
* Enhancement - Replace the middleware URL from connect.woocommerce.com to api.woocommerce.com/integrations #2130
|
||||
* Enhancement - Remove all Sofort references as it has been deprecated #2124
|
||||
* Enhancement - Improve funding source names #2118
|
||||
* Enhancement - More fraud prevention capabilities by storing additional data in the order #2125
|
||||
* Enhancement - Update ACDC currency eligibility for AMEX #2129
|
||||
* Enhancement - Sync shipping options with Venmo when skipping final confirmation on Checkout #2108
|
||||
* Enhancement - Card Fields: Add a filter for the CVC field and update the placeholder to match the label #2089
|
||||
* Enhancement - Product Title: Sanitize before sending to PayPal #2090
|
||||
* Enhancement - Add filter for disabling permit_multiple_payment_tokens vault attribute #2136
|
||||
* Enhancement - Filter to hide PayPal email address not working on order detail #2137
|
||||
|
||||
= 2.6.0 - 2024-03-20 =
|
||||
* Fix - invoice_id not included in API call when creating payment with saved card #2086
|
||||
* Fix - Typo in SCA indicators for ACDC Vault transactions #2083
|
||||
* Fix - Payments with saved card tokens use Capture intent when Authorize is configured #2069
|
||||
* Fix - WooPayments multi-currency causing currency mismatch error on Block Cart & Checkout pages #2054
|
||||
* Fix - "Must pass createSubscription with intent=subscription" error with PayPal Subscriptions mode #2058
|
||||
* Fix - "Proceed to PayPal" button displayed for Free trial PayPal Subscription products when payment token is saved #2041
|
||||
* Fix - ACDC payments with new credit card may fail when debugging is enabled (JSON malformed by warning) #2051
|
||||
* Enhancement - Add Pay Later Messaging block #1897
|
||||
* Enhancement - Submit the form instead of refreshing the page to show the save notice #2081
|
||||
* Enhancement - Integrate pay later messaging block with the messaging configurator #2080
|
||||
* Enhancement - Reauthorize authorized payments #2062
|
||||
* Enhancement - Do not handle VAULT.PAYMENT-TOKEN.CREATED webhook for Vault v3 #2079
|
||||
* Enhancement - Improve the messaging configurator styles #2053
|
||||
* Enhancement - Ensure PayPal Vaulting is not selected as Subscriptions Mode when Reference Transactions are disabled #2057
|
||||
* Enhancement - Pay later messaging configurator & messaging block adjustments #2096
|
||||
|
||||
= 2.5.4 - 2024-02-27 =
|
||||
* Fix - Cannot enable Apple Pay when API credentials were manually created #2015
|
||||
* Fix - Cart simulation type error #1943
|
||||
|
|
|
@ -68,7 +68,7 @@ return function ( string $root_dir ): iterable {
|
|||
$modules[] = ( require "$modules_dir/ppcp-save-payment-methods/module.php" )();
|
||||
}
|
||||
|
||||
if ( PayLaterBlockModule::is_enabled() ) {
|
||||
if ( PayLaterBlockModule::is_module_loading_required() ) {
|
||||
$modules[] = ( require "$modules_dir/ppcp-paylater-block/module.php" )();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\AdminNotices;
|
||||
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Repository\Repository;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
|
@ -40,6 +42,34 @@ class AdminNotices implements ModuleInterface {
|
|||
$renderer->render();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
Repository::NOTICES_FILTER,
|
||||
/**
|
||||
* Adds persisted notices to the notices array.
|
||||
*
|
||||
* @param array $notices The notices.
|
||||
* @return array
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function ( $notices ) use ( $c ) {
|
||||
if ( ! is_array( $notices ) ) {
|
||||
return $notices;
|
||||
}
|
||||
|
||||
$admin_notices = $c->get( 'admin-notices.repository' );
|
||||
assert( $admin_notices instanceof Repository );
|
||||
|
||||
$persisted_notices = $admin_notices->get_persisted_and_clear();
|
||||
|
||||
if ( $persisted_notices ) {
|
||||
$notices = array_merge( $notices, $persisted_notices );
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -92,4 +92,18 @@ class Message {
|
|||
public function wrapper(): string {
|
||||
return $this->wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'type' => $this->type,
|
||||
'message' => $this->message,
|
||||
'dismissable' => $this->dismissable,
|
||||
'wrapper' => $this->wrapper,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
|||
*/
|
||||
class Repository implements RepositoryInterface {
|
||||
|
||||
const NOTICES_FILTER = 'ppcp.admin-notices.current-notices';
|
||||
const NOTICES_FILTER = 'ppcp.admin-notices.current-notices';
|
||||
const PERSISTED_NOTICES_OPTION = 'woocommerce_ppcp-admin-notices';
|
||||
|
||||
/**
|
||||
* Returns the current messages.
|
||||
|
@ -37,4 +38,40 @@ class Repository implements RepositoryInterface {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message to persist between page reloads.
|
||||
*
|
||||
* @param Message $message The message.
|
||||
* @return void
|
||||
*/
|
||||
public function persist( Message $message ): void {
|
||||
$persisted_notices = get_option( self::PERSISTED_NOTICES_OPTION ) ?: array();
|
||||
|
||||
$persisted_notices[] = $message->to_array();
|
||||
|
||||
update_option( self::PERSISTED_NOTICES_OPTION, $persisted_notices );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message to persist between page reloads.
|
||||
*
|
||||
* @return array|Message[]
|
||||
*/
|
||||
public function get_persisted_and_clear(): array {
|
||||
$notices = array();
|
||||
|
||||
$persisted_data = get_option( self::PERSISTED_NOTICES_OPTION ) ?: array();
|
||||
foreach ( $persisted_data as $notice_data ) {
|
||||
$notices[] = new Message(
|
||||
(string) ( $notice_data['message'] ?? '' ),
|
||||
(string) ( $notice_data['type'] ?? '' ),
|
||||
(bool) ( $notice_data['dismissable'] ?? true ),
|
||||
(string) ( $notice_data['wrapper'] ?? '' )
|
||||
);
|
||||
}
|
||||
|
||||
update_option( self::PERSISTED_NOTICES_OPTION, array(), true );
|
||||
return $notices;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1408,32 +1408,32 @@ return array(
|
|||
'BE' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD', 'CAD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'BG' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'CY' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'CZ' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'CZK' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'DE' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'DK' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'DKK' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'EE' => array(
|
||||
'mastercard' => array(),
|
||||
|
@ -1443,32 +1443,32 @@ return array(
|
|||
'ES' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'FI' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'FR' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'GB' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'GBP', 'USD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'GR' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'HU' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'HUF' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'IE' => array(
|
||||
'mastercard' => array(),
|
||||
|
@ -1478,7 +1478,7 @@ return array(
|
|||
'IT' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'US' => array(
|
||||
'mastercard' => array(),
|
||||
|
@ -1489,7 +1489,7 @@ return array(
|
|||
'CA' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'CAD' ),
|
||||
'amex' => array( 'CAD', 'USD' ),
|
||||
'jcb' => array( 'CAD' ),
|
||||
),
|
||||
'LI' => array(
|
||||
|
@ -1500,22 +1500,22 @@ return array(
|
|||
'LT' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'LU' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'LV' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'MT' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'MX' => array(
|
||||
'mastercard' => array(),
|
||||
|
@ -1525,7 +1525,7 @@ return array(
|
|||
'NL' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'NO' => array(
|
||||
'mastercard' => array(),
|
||||
|
@ -1535,32 +1535,32 @@ return array(
|
|||
'PL' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD', 'GBP', 'PLN' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'PT' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD', 'CAD', 'GBP' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'RO' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'SE' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'SEK' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'SI' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'SK' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'GBP' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'JP' => array(
|
||||
'mastercard' => array(),
|
||||
|
|
|
@ -115,7 +115,7 @@ class PaymentMethodTokensEndpoint {
|
|||
* @throws RuntimeException When something when wrong with the request.
|
||||
* @throws PayPalApiException When something when wrong setting up the token.
|
||||
*/
|
||||
public function payment_tokens( PaymentSource $payment_source ): stdClass {
|
||||
public function create_payment_token( PaymentSource $payment_source ): stdClass {
|
||||
$data = array(
|
||||
'payment_source' => array(
|
||||
$payment_source->name() => $payment_source->properties(),
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WP_Error;
|
||||
|
@ -92,4 +93,53 @@ class PaymentTokensEndpoint {
|
|||
throw new PayPalApiException( $json, $status_code );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all payment tokens for the given customer.
|
||||
*
|
||||
* @param string $customer_id PayPal customer id.
|
||||
* @return array
|
||||
*
|
||||
* @throws RuntimeException When something went wrong with the request.
|
||||
* @throws PayPalApiException When something went wrong getting the payment tokens.
|
||||
*/
|
||||
public function payment_tokens_for_customer( string $customer_id ): array {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v3/vault/payment-tokens?customer_id=' . $customer_id;
|
||||
$args = array(
|
||||
'method' => 'GET',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( $response instanceof WP_Error ) {
|
||||
throw new RuntimeException( $response->get_error_message() );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $status_code ) {
|
||||
throw new PayPalApiException( $json, $status_code );
|
||||
}
|
||||
|
||||
$tokens = array();
|
||||
$payment_tokens = $json->payment_tokens ?? array();
|
||||
foreach ( $payment_tokens as $payment_token ) {
|
||||
$name = array_key_first( (array) $payment_token->payment_source ) ?? '';
|
||||
if ( $name ) {
|
||||
$tokens[] = array(
|
||||
'id' => $payment_token->id,
|
||||
'payment_source' => new PaymentSource(
|
||||
$name,
|
||||
$payment_token->payment_source->$name
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,6 +193,53 @@ class PaymentsEndpoint {
|
|||
return $this->capture_factory->from_paypal_response( $json );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthorizes an order.
|
||||
*
|
||||
* @param string $authorization_id The id.
|
||||
* @param Money|null $amount The amount to capture. If not specified, the whole authorized amount is captured.
|
||||
*
|
||||
* @return string
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function reauthorize( string $authorization_id, ?Money $amount = null ) : string {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/payments/authorizations/' . $authorization_id . '/reauthorize';
|
||||
|
||||
$data = array();
|
||||
if ( $amount ) {
|
||||
$data['amount'] = $amount->to_array();
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
'body' => wp_json_encode( $data, JSON_FORCE_OBJECT ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
$json = json_decode( $response['body'] );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
throw new RuntimeException( 'Could not reauthorize authorized payment.' );
|
||||
}
|
||||
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 201 !== $status_code || ! is_object( $json ) ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $json->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refunds a payment.
|
||||
*
|
||||
|
|
|
@ -61,10 +61,10 @@ class ItemFactory {
|
|||
|
||||
$price = (float) $item['line_subtotal'] / (float) $item['quantity'];
|
||||
return new Item(
|
||||
mb_substr( $product->get_name(), 0, 127 ),
|
||||
$this->prepare_item_string( $product->get_name() ),
|
||||
new Money( $price, $this->currency ),
|
||||
$quantity,
|
||||
$this->prepare_description( $product->get_description() ),
|
||||
$this->prepare_item_string( $product->get_description() ),
|
||||
null,
|
||||
$this->prepare_sku( $product->get_sku() ),
|
||||
( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
|
@ -138,10 +138,10 @@ class ItemFactory {
|
|||
$image = $product instanceof WC_Product ? wp_get_attachment_image_src( (int) $product->get_image_id(), 'full' ) : '';
|
||||
|
||||
return new Item(
|
||||
mb_substr( $item->get_name(), 0, 127 ),
|
||||
$this->prepare_item_string( $item->get_name() ),
|
||||
new Money( $price_without_tax_rounded, $currency ),
|
||||
$quantity,
|
||||
$product instanceof WC_Product ? $this->prepare_description( $product->get_description() ) : '',
|
||||
$product instanceof WC_Product ? $this->prepare_item_string( $product->get_description() ) : '',
|
||||
null,
|
||||
$product instanceof WC_Product ? $this->prepare_sku( $product->get_sku() ) : '',
|
||||
( $product instanceof WC_Product && $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
|
@ -160,7 +160,7 @@ class ItemFactory {
|
|||
*/
|
||||
private function from_wc_order_fee( \WC_Order_Item_Fee $item, \WC_Order $order ): Item {
|
||||
return new Item(
|
||||
$item->get_name(),
|
||||
$this->prepare_item_string( $item->get_name() ),
|
||||
new Money( (float) $item->get_amount(), $order->get_currency() ),
|
||||
$item->get_quantity(),
|
||||
'',
|
||||
|
|
|
@ -12,14 +12,14 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
|||
trait ItemTrait {
|
||||
|
||||
/**
|
||||
* Cleanups the description and prepares it for sending to PayPal.
|
||||
* Cleans up item strings (title and description for example) and prepares them for sending to PayPal.
|
||||
*
|
||||
* @param string $description Item description.
|
||||
* @param string $string Item string.
|
||||
* @return string
|
||||
*/
|
||||
protected function prepare_description( string $description ): string {
|
||||
$description = strip_shortcodes( wp_strip_all_tags( $description ) );
|
||||
return substr( $description, 0, 127 ) ?: '';
|
||||
protected function prepare_item_string( string $string ): string {
|
||||
$string = strip_shortcodes( wp_strip_all_tags( $string ) );
|
||||
return substr( $string, 0, 127 ) ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
22
modules/ppcp-blocks/resources/js/Helper/Helper.js
Normal file
22
modules/ppcp-blocks/resources/js/Helper/Helper.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* @param str
|
||||
* @returns {string}
|
||||
*/
|
||||
export const toSnakeCase = (str) => {
|
||||
return str.replace(/[\w]([A-Z])/g, function(m) {
|
||||
return m[0] + "_" + m[1];
|
||||
}).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj
|
||||
* @returns {{}}
|
||||
*/
|
||||
export const convertKeysToSnakeCase = (obj) => {
|
||||
const newObj = {};
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const newKey = toSnakeCase(key);
|
||||
newObj[newKey] = obj[key];
|
||||
});
|
||||
return newObj;
|
||||
}
|
|
@ -6,6 +6,9 @@ import {
|
|||
paypalOrderToWcAddresses,
|
||||
paypalSubscriptionToWcAddresses
|
||||
} from "./Helper/Address";
|
||||
import {
|
||||
convertKeysToSnakeCase
|
||||
} from "./Helper/Helper";
|
||||
import {
|
||||
cartHasSubscriptionProducts,
|
||||
isPayPalSubscription
|
||||
|
@ -18,6 +21,7 @@ import {
|
|||
} from '../../../ppcp-button/resources/js/modules/Helper/Style'
|
||||
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
|
||||
import BlockCheckoutMessagesBootstrap from "./Bootstrap/BlockCheckoutMessagesBootstrap";
|
||||
import {keysToCamelCase} from "../../../ppcp-button/resources/js/modules/Helper/Utils";
|
||||
const config = wc.wcSettings.getSetting('ppcp-gateway_data');
|
||||
|
||||
window.ppcpFundingSource = config.fundingSource;
|
||||
|
@ -286,17 +290,43 @@ const PayPalComponent = ({
|
|||
onClick();
|
||||
};
|
||||
|
||||
let handleShippingChange = null;
|
||||
let handleSubscriptionShippingChange = null;
|
||||
let handleShippingOptionsChange = null;
|
||||
let handleShippingAddressChange = null;
|
||||
let handleSubscriptionShippingOptionsChange = null;
|
||||
let handleSubscriptionShippingAddressChange = null;
|
||||
if (shippingData.needsShipping && !config.finalReviewEnabled) {
|
||||
handleShippingChange = async (data, actions) => {
|
||||
handleShippingOptionsChange = async (data, actions) => {
|
||||
try {
|
||||
const shippingOptionId = data.selected_shipping_option?.id;
|
||||
const shippingOptionId = data.selectedShippingOption?.id;
|
||||
if (shippingOptionId) {
|
||||
await wp.data.dispatch('wc/store/cart').selectShippingRate(shippingOptionId);
|
||||
await shippingData.setSelectedRates(shippingOptionId);
|
||||
}
|
||||
|
||||
const address = paypalAddressToWc(data.shipping_address);
|
||||
const res = await fetch(config.ajax.update_shipping.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
actions.reject();
|
||||
}
|
||||
};
|
||||
|
||||
handleShippingAddressChange = async (data, actions) => {
|
||||
try {
|
||||
const address = paypalAddressToWc(convertKeysToSnakeCase(data.shippingAddress));
|
||||
|
||||
await wp.data.dispatch('wc/store/cart').updateCustomerData({
|
||||
shipping_address: address,
|
||||
|
@ -325,14 +355,23 @@ const PayPalComponent = ({
|
|||
}
|
||||
};
|
||||
|
||||
handleSubscriptionShippingChange = async (data, actions) => {
|
||||
handleSubscriptionShippingOptionsChange = async (data, actions) => {
|
||||
try {
|
||||
const shippingOptionId = data.selected_shipping_option?.id;
|
||||
const shippingOptionId = data.selectedShippingOption?.id;
|
||||
if (shippingOptionId) {
|
||||
await wp.data.dispatch('wc/store/cart').selectShippingRate(shippingOptionId);
|
||||
await shippingData.setSelectedRates(shippingOptionId);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
const address = paypalAddressToWc(data.shipping_address);
|
||||
actions.reject();
|
||||
}
|
||||
};
|
||||
|
||||
handleSubscriptionShippingAddressChange = async (data, actions) => {
|
||||
try {
|
||||
const address = paypalAddressToWc(convertKeysToSnakeCase(data.shippingAddress));
|
||||
|
||||
await wp.data.dispatch('wc/store/cart').updateCustomerData({
|
||||
shipping_address: address,
|
||||
|
@ -442,7 +481,8 @@ const PayPalComponent = ({
|
|||
onError={onClose}
|
||||
createSubscription={createSubscription}
|
||||
onApprove={handleApproveSubscription}
|
||||
onShippingChange={handleSubscriptionShippingChange}
|
||||
onShippingOptionsChange={handleSubscriptionShippingOptionsChange}
|
||||
onShippingAddressChange={handleSubscriptionShippingAddressChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -456,7 +496,8 @@ const PayPalComponent = ({
|
|||
onError={onClose}
|
||||
createOrder={createOrder}
|
||||
onApprove={handleApprove}
|
||||
onShippingChange={handleShippingChange}
|
||||
onShippingOptionsChange={handleShippingOptionsChange}
|
||||
onShippingAddressChange={handleShippingAddressChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -137,7 +137,12 @@ const bootstrap = () => {
|
|||
}
|
||||
|
||||
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
|
||||
if (isFreeTrial && data.fundingSource !== 'card' && ! PayPalCommerceGateway.subscription_plan_id) {
|
||||
if (
|
||||
isFreeTrial
|
||||
&& data.fundingSource !== 'card'
|
||||
&& ! PayPalCommerceGateway.subscription_plan_id
|
||||
&& ! PayPalCommerceGateway.vault_v3_enabled
|
||||
) {
|
||||
freeTrialHandler.handle();
|
||||
return actions.reject();
|
||||
}
|
||||
|
@ -241,7 +246,6 @@ document.addEventListener(
|
|||
if (!typeof (PayPalCommerceGateway)) {
|
||||
console.error('PayPal button could not be configured.');
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
|
|
|
@ -144,6 +144,54 @@ class CheckoutActionHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
addPaymentMethodConfiguration() {
|
||||
return {
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(this.config.ajax.create_setup_token.endpoint, {
|
||||
method: "POST",
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.create_setup_token.nonce,
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json()
|
||||
if (result.data.id) {
|
||||
return result.data.id
|
||||
}
|
||||
|
||||
console.error(result)
|
||||
},
|
||||
onApprove: async ({vaultSetupToken}) => {
|
||||
const response = await fetch(this.config.ajax.create_payment_token_for_guest.endpoint, {
|
||||
method: "POST",
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.create_payment_token_for_guest.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
})
|
||||
})
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success === true) {
|
||||
document.querySelector('#place_order').click()
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(result)
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CheckoutActionHandler;
|
||||
|
|
|
@ -116,6 +116,14 @@ class CheckoutBootstap {
|
|||
return;
|
||||
}
|
||||
|
||||
if(
|
||||
PayPalCommerceGateway.is_free_trial_cart
|
||||
&& PayPalCommerceGateway.vault_v3_enabled
|
||||
) {
|
||||
this.renderer.render(actionHandler.addPaymentMethodConfiguration(), {}, actionHandler.configuration());
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderer.render(actionHandler.configuration(), {}, actionHandler.configuration());
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ return array(
|
|||
$container->get( 'button.early-wc-checkout-validation-enabled' ),
|
||||
$container->get( 'button.pay-now-contexts' ),
|
||||
$container->get( 'wcgateway.funding-sources-without-redirect' ),
|
||||
$container->get( 'vaulting.vault-v3-enabled' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
|
|
|
@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface;
|
|||
use WC_Order;
|
||||
use WC_Product;
|
||||
use WC_Product_Variation;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
|
@ -33,6 +34,9 @@ use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
|||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\PayLaterBlock\PayLaterBlockModule;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
|
@ -184,13 +188,6 @@ class SmartButton implements SmartButtonInterface {
|
|||
*/
|
||||
private $funding_sources_without_redirect;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Session handler.
|
||||
*
|
||||
|
@ -198,6 +195,27 @@ class SmartButton implements SmartButtonInterface {
|
|||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* Whether Vault v3 module is enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $vault_v3_enabled;
|
||||
|
||||
/**
|
||||
* Payment tokens endpoint.
|
||||
*
|
||||
* @var PaymentTokensEndpoint
|
||||
*/
|
||||
private $payment_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* SmartButton constructor.
|
||||
*
|
||||
|
@ -220,6 +238,8 @@ class SmartButton implements SmartButtonInterface {
|
|||
* @param bool $early_validation_enabled Whether to execute WC validation of the checkout form.
|
||||
* @param array $pay_now_contexts The contexts that should have the Pay Now button.
|
||||
* @param string[] $funding_sources_without_redirect The sources that do not cause issues about redirecting (on mobile, ...) and sometimes not returning back.
|
||||
* @param bool $vault_v3_enabled Whether Vault v3 module is enabled.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
|
@ -242,6 +262,8 @@ class SmartButton implements SmartButtonInterface {
|
|||
bool $early_validation_enabled,
|
||||
array $pay_now_contexts,
|
||||
array $funding_sources_without_redirect,
|
||||
bool $vault_v3_enabled,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
|
@ -264,7 +286,9 @@ class SmartButton implements SmartButtonInterface {
|
|||
$this->early_validation_enabled = $early_validation_enabled;
|
||||
$this->pay_now_contexts = $pay_now_contexts;
|
||||
$this->funding_sources_without_redirect = $funding_sources_without_redirect;
|
||||
$this->vault_v3_enabled = $vault_v3_enabled;
|
||||
$this->logger = $logger;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -631,7 +655,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
|
||||
$messaging_enabled_for_current_location = $this->settings_status->is_pay_later_messaging_enabled_for_location( $location );
|
||||
|
||||
$has_paylater_block = has_block( 'woocommerce-paypal-payments/paylater-messages' ) && PayLaterBlockModule::is_enabled();
|
||||
$has_paylater_block = has_block( 'woocommerce-paypal-payments/paylater-messages' ) && PayLaterBlockModule::is_block_enabled( $this->settings_status );
|
||||
|
||||
switch ( $location ) {
|
||||
case 'checkout':
|
||||
|
@ -878,7 +902,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
'wrapper' => '#ppcp-messages',
|
||||
'is_hidden' => ! $this->is_pay_later_filter_enabled_for_location( $this->context() ),
|
||||
'block' => array(
|
||||
'enabled' => PayLaterBlockModule::is_enabled(),
|
||||
'enabled' => PayLaterBlockModule::is_block_enabled( $this->settings_status ),
|
||||
),
|
||||
'amount' => $amount,
|
||||
'placement' => $placement,
|
||||
|
@ -990,11 +1014,21 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
if ( $this->settings->has( '3d_secure_contingency' ) ) {
|
||||
$value = $this->settings->get( '3d_secure_contingency' );
|
||||
if ( $value ) {
|
||||
return $value;
|
||||
return $this->return_3ds_contingency( $value );
|
||||
}
|
||||
}
|
||||
|
||||
return 'SCA_WHEN_REQUIRED';
|
||||
return $this->return_3ds_contingency( 'SCA_WHEN_REQUIRED' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and returns the 3D Secure contingency.
|
||||
*
|
||||
* @param string $contingency The ThreeD secure contingency.
|
||||
* @return string
|
||||
*/
|
||||
private function return_3ds_contingency( string $contingency ): string {
|
||||
return apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $contingency );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1025,44 +1059,57 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
'redirect' => wc_get_checkout_url(),
|
||||
'context' => $this->context(),
|
||||
'ajax' => array(
|
||||
'simulate_cart' => array(
|
||||
'simulate_cart' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( SimulateCartEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( SimulateCartEndpoint::nonce() ),
|
||||
),
|
||||
'change_cart' => array(
|
||||
'change_cart' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( ChangeCartEndpoint::nonce() ),
|
||||
),
|
||||
'create_order' => array(
|
||||
'create_order' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CreateOrderEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CreateOrderEndpoint::nonce() ),
|
||||
),
|
||||
'approve_order' => array(
|
||||
'approve_order' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( ApproveOrderEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( ApproveOrderEndpoint::nonce() ),
|
||||
),
|
||||
'approve_subscription' => array(
|
||||
'approve_subscription' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( ApproveSubscriptionEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( ApproveSubscriptionEndpoint::nonce() ),
|
||||
),
|
||||
'vault_paypal' => array(
|
||||
'vault_paypal' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( StartPayPalVaultingEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( StartPayPalVaultingEndpoint::nonce() ),
|
||||
),
|
||||
'save_checkout_form' => array(
|
||||
'save_checkout_form' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( SaveCheckoutFormEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( SaveCheckoutFormEndpoint::nonce() ),
|
||||
),
|
||||
'validate_checkout' => array(
|
||||
'validate_checkout' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( ValidateCheckoutEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( ValidateCheckoutEndpoint::nonce() ),
|
||||
),
|
||||
'cart_script_params' => array(
|
||||
'cart_script_params' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CartScriptParamsEndpoint::ENDPOINT ),
|
||||
),
|
||||
'create_setup_token' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CreateSetupToken::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CreateSetupToken::nonce() ),
|
||||
),
|
||||
'create_payment_token' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentToken::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CreatePaymentToken::nonce() ),
|
||||
),
|
||||
'create_payment_token_for_guest' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentTokenForGuest::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CreatePaymentTokenForGuest::nonce() ),
|
||||
),
|
||||
),
|
||||
'cart_contains_subscription' => $this->subscription_helper->cart_contains_subscription(),
|
||||
'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(),
|
||||
'vault_v3_enabled' => $this->vault_v3_enabled,
|
||||
'variable_paypal_subscription_variations' => $this->subscription_helper->variable_paypal_subscription_variations(),
|
||||
'subscription_product_allowed' => $this->subscription_helper->checkout_subscription_product_allowed(),
|
||||
'locations_with_subscription_product' => $this->subscription_helper->locations_with_subscription_product(),
|
||||
|
@ -1318,7 +1365,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
$disable_funding,
|
||||
array_diff(
|
||||
array_keys( $this->all_funding_sources ),
|
||||
array( 'venmo', 'paylater' )
|
||||
array( 'venmo', 'paylater', 'paypal' )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1339,6 +1386,20 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
$disable_funding[] = 'paylater';
|
||||
}
|
||||
|
||||
$disable_funding = array_filter(
|
||||
$disable_funding,
|
||||
/**
|
||||
* Make sure paypal is not sent in disable funding.
|
||||
*
|
||||
* @param string $funding_source The funding_source.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function( $funding_source ) {
|
||||
return $funding_source !== 'paypal';
|
||||
}
|
||||
);
|
||||
|
||||
if ( count( $disable_funding ) > 0 ) {
|
||||
$params['disable-funding'] = implode( ',', array_unique( $disable_funding ) );
|
||||
}
|
||||
|
@ -1880,8 +1941,18 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
*/
|
||||
private function get_vaulted_paypal_email(): string {
|
||||
try {
|
||||
$tokens = $this->get_payment_tokens();
|
||||
$customer_id = get_user_meta( get_current_user_id(), '_ppcp_target_customer_id', true );
|
||||
if ( $customer_id ) {
|
||||
$customer_tokens = $this->payment_tokens_endpoint->payment_tokens_for_customer( $customer_id );
|
||||
foreach ( $customer_tokens as $token ) {
|
||||
$email_address = $token['payment_source']->properties()->email_address ?? '';
|
||||
if ( $email_address ) {
|
||||
return $email_address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tokens = $this->get_payment_tokens();
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( isset( $token->source()->paypal ) ) {
|
||||
return $token->source()->paypal->payer->email_address;
|
||||
|
@ -1890,6 +1961,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( 'Failed to get PayPal vaulted email. ' . $exception->getMessage() );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -329,6 +329,21 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
if ( 'pay-now' === $data['context'] && is_a( $wc_order, \WC_Order::class ) ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() );
|
||||
$wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() );
|
||||
|
||||
$payment_source = $order->payment_source();
|
||||
$payment_source_name = $payment_source ? $payment_source->name() : null;
|
||||
$payer = $order->payer();
|
||||
if (
|
||||
$payer
|
||||
&& $payment_source_name
|
||||
&& in_array( $payment_source_name, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, true )
|
||||
) {
|
||||
$payer_email = $payer->email_address();
|
||||
if ( $payer_email ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email );
|
||||
}
|
||||
}
|
||||
|
||||
$wc_order->save_meta_data();
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_woocommerce_order_created', $wc_order, $order );
|
||||
|
|
|
@ -159,6 +159,22 @@ class EarlyOrderHandler {
|
|||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() );
|
||||
$wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() );
|
||||
|
||||
$payment_source = $order->payment_source();
|
||||
$payment_source_name = $payment_source ? $payment_source->name() : null;
|
||||
$payer = $order->payer();
|
||||
if (
|
||||
$payer
|
||||
&& $payment_source_name
|
||||
&& in_array( $payment_source_name, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, true )
|
||||
&& $wc_order instanceof \WC_Order
|
||||
) {
|
||||
$payer_email = $payer->email_address();
|
||||
if ( $payer_email ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email );
|
||||
}
|
||||
}
|
||||
|
||||
$wc_order->save_meta_data();
|
||||
|
||||
/**
|
||||
|
|
|
@ -57,21 +57,24 @@ class ThreeDSecure {
|
|||
*
|
||||
* @link https://developer.paypal.com/docs/business/checkout/add-capabilities/3d-secure/#authenticationresult
|
||||
*
|
||||
* @param Order $order The order for which the decission is needed.
|
||||
* @param Order $order The order for which the decision is needed.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function proceed_with_order( Order $order ): int {
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_three_d_secure_before_check', $order );
|
||||
|
||||
$payment_source = $order->payment_source();
|
||||
if ( ! $payment_source ) {
|
||||
return self::NO_DECISION;
|
||||
return $this->return_decision( self::NO_DECISION, $order );
|
||||
}
|
||||
|
||||
if ( ! ( $payment_source->properties()->brand ?? '' ) ) {
|
||||
return self::NO_DECISION;
|
||||
return $this->return_decision( self::NO_DECISION, $order );
|
||||
}
|
||||
if ( ! ( $payment_source->properties()->authentication_result ?? '' ) ) {
|
||||
return self::NO_DECISION;
|
||||
return $this->return_decision( self::NO_DECISION, $order );
|
||||
}
|
||||
|
||||
$authentication_result = $payment_source->properties()->authentication_result ?? null;
|
||||
|
@ -81,18 +84,31 @@ class ThreeDSecure {
|
|||
$this->logger->info( '3DS Authentication Result: ' . wc_print_r( $result->to_array(), true ) );
|
||||
|
||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_POSSIBLE ) {
|
||||
return self::PROCCEED;
|
||||
return $this->return_decision( self::PROCCEED, $order );
|
||||
}
|
||||
|
||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_UNKNOWN ) {
|
||||
return self::RETRY;
|
||||
return $this->return_decision( self::RETRY, $order );
|
||||
}
|
||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_NO ) {
|
||||
return $this->no_liability_shift( $result );
|
||||
return $this->return_decision( $this->no_liability_shift( $result ), $order );
|
||||
}
|
||||
}
|
||||
|
||||
return self::NO_DECISION;
|
||||
return $this->return_decision( self::NO_DECISION, $order );
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and returns a ThreeD secure decision.
|
||||
*
|
||||
* @param int $decision The ThreeD secure decision.
|
||||
* @param Order $order The PayPal Order object.
|
||||
* @return int
|
||||
*/
|
||||
public function return_decision( int $decision, Order $order ) {
|
||||
$decision = apply_filters( 'woocommerce_paypal_payments_three_d_secure_decision', $decision, $order );
|
||||
do_action( 'woocommerce_paypal_payments_three_d_secure_after_check', $order, $decision );
|
||||
return $decision;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -115,17 +115,19 @@ class CardFieldsModule implements ModuleInterface {
|
|||
$settings = $c->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
|
||||
$three_d_secure_contingency =
|
||||
$settings->has( '3d_secure_contingency' )
|
||||
? apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $settings->get( '3d_secure_contingency' ) )
|
||||
: '';
|
||||
|
||||
if (
|
||||
$settings->has( '3d_secure_contingency' )
|
||||
&& (
|
||||
$settings->get( '3d_secure_contingency' ) === 'SCA_ALWAYS'
|
||||
|| $settings->get( '3d_secure_contingency' ) === 'SCA_WHEN_REQUIRED'
|
||||
)
|
||||
$three_d_secure_contingency === 'SCA_ALWAYS'
|
||||
|| $three_d_secure_contingency === 'SCA_WHEN_REQUIRED'
|
||||
) {
|
||||
$data['payment_source']['card'] = array(
|
||||
'attributes' => array(
|
||||
'verification' => array(
|
||||
'method' => $settings->get( '3d_secure_contingency' ),
|
||||
'method' => $three_d_secure_contingency,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -169,10 +169,10 @@ class Shipment implements ShipmentInterface {
|
|||
$image = wp_get_attachment_image_src( (int) $product->get_image_id(), 'full' );
|
||||
|
||||
$ppcp_order_item = new Item(
|
||||
mb_substr( $item->get_name(), 0, 127 ),
|
||||
$this->prepare_item_string( $item->get_name() ),
|
||||
new Money( $price_without_tax_rounded, $currency ),
|
||||
$quantity,
|
||||
$this->prepare_description( $product->get_description() ),
|
||||
$this->prepare_item_string( $product->get_description() ),
|
||||
null,
|
||||
$this->prepare_sku( $product->get_sku() ),
|
||||
$product->is_virtual() ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
|
|
|
@ -7,7 +7,7 @@ import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Help
|
|||
import PayPalMessages from "./components/PayPalMessages";
|
||||
|
||||
export default function Edit( { attributes, clientId, setAttributes } ) {
|
||||
const { layout, logo, position, color, flexColor, flexRatio, placement, id } = attributes;
|
||||
const { layout, logo, position, color, size, flexColor, flexRatio, placement, id } = attributes;
|
||||
const isFlex = layout === 'flex';
|
||||
|
||||
const [paypalScriptState, setPaypalScriptState] = useState(null);
|
||||
|
@ -30,11 +30,12 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
ratio: flexRatio,
|
||||
text: {
|
||||
color,
|
||||
size
|
||||
},
|
||||
};
|
||||
|
||||
let classes = ['ppcp-paylater-block-preview', 'ppcp-overlay-parent'];
|
||||
if (PcpPayLaterBlock.vaultingEnabled) {
|
||||
if (PcpPayLaterBlock.vaultingEnabled || !PcpPayLaterBlock.placementEnabled) {
|
||||
classes = ['ppcp-paylater-block-preview', 'ppcp-paylater-unavailable', 'block-editor-warning'];
|
||||
}
|
||||
const props = useBlockProps({className: classes});
|
||||
|
@ -68,6 +69,27 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
</div>
|
||||
}
|
||||
|
||||
if (!PcpPayLaterBlock.placementEnabled) {
|
||||
return <div {...props}>
|
||||
<div className={'block-editor-warning__contents'}>
|
||||
<h3>{__('PayPal Pay Later Messaging', 'woocommerce-paypal-payments')}</h3>
|
||||
<p className={'block-editor-warning__message'}>{__('Pay Later Messaging cannot be used while the “WooCommerce Block” messaging placement is disabled. Enable the placement in the PayPal Payments Pay Later settings to reactivate this block.', 'woocommerce-paypal-payments')}</p>
|
||||
<div className={'class="block-editor-warning__actions"'}>
|
||||
<span className={'block-editor-warning__action'}>
|
||||
<a href={PcpPayLaterBlock.payLaterSettingsUrl} className={'components-button is-primary'}>
|
||||
{__('PayPal Payments Settings', 'woocommerce-paypal-payments')}
|
||||
</a>
|
||||
</span>
|
||||
<span className={'block-editor-warning__action'}>
|
||||
<button onClick={() => wp.data.dispatch( 'core/block-editor' ).removeBlock(clientId)} type={'button'} className={'components-button is-secondary'}>
|
||||
{__('Remove Block', 'woocommerce-paypal-payments')}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
let scriptParams = useScriptParams(PcpPayLaterBlock.ajax.cart_script_params);
|
||||
if (scriptParams === null) {
|
||||
return loadingElement;
|
||||
|
@ -108,10 +130,10 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
{ !isFlex && (<SelectControl
|
||||
label={__('Logo', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __('Primary', 'woocommerce-paypal-payments'), value: 'primary' },
|
||||
{ label: __('Alternative', 'woocommerce-paypal-payments'), value: 'alternative' },
|
||||
{ label: __('Full logo', 'woocommerce-paypal-payments'), value: 'primary' },
|
||||
{ label: __('Monogram', 'woocommerce-paypal-payments'), value: 'alternative' },
|
||||
{ label: __('Inline', 'woocommerce-paypal-payments'), value: 'inline' },
|
||||
{ label: __('None', 'woocommerce-paypal-payments'), value: 'none' },
|
||||
{ label: __('Message only', 'woocommerce-paypal-payments'), value: 'none' },
|
||||
]}
|
||||
value={logo}
|
||||
onChange={(value) => setAttributes({logo: value})}
|
||||
|
@ -129,24 +151,31 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
{ !isFlex && (<SelectControl
|
||||
label={__('Text Color', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __( 'Black', 'woocommerce-paypal-payments' ), value: 'black' },
|
||||
{ label: __( 'White', 'woocommerce-paypal-payments' ), value: 'white' },
|
||||
{ label: __( 'Black / Blue logo', 'woocommerce-paypal-payments' ), value: 'black' },
|
||||
{ label: __( 'White / White logo', 'woocommerce-paypal-payments' ), value: 'white' },
|
||||
{ label: __( 'Monochrome', 'woocommerce-paypal-payments' ), value: 'monochrome' },
|
||||
{ label: __( 'Grayscale', 'woocommerce-paypal-payments' ), value: 'grayscale' },
|
||||
{ label: __( 'Black / Gray logo', 'woocommerce-paypal-payments' ), value: 'grayscale' },
|
||||
]}
|
||||
value={color}
|
||||
onChange={(value) => setAttributes({color: value})}
|
||||
/>)}
|
||||
{ !isFlex && (<SelectControl
|
||||
label={__('Text Size', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __( 'Small', 'woocommerce-paypal-payments' ), value: '12' },
|
||||
{ label: __( 'Medium', 'woocommerce-paypal-payments' ), value: '14' },
|
||||
{ label: __( 'Large', 'woocommerce-paypal-payments' ), value: '16' },
|
||||
]}
|
||||
value={size}
|
||||
onChange={(value) => setAttributes({size: value})}
|
||||
/>)}
|
||||
{ isFlex && (<SelectControl
|
||||
label={__('Color', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __( 'Blue', 'woocommerce-paypal-payments' ), value: 'blue' },
|
||||
{ label: __( 'Black', 'woocommerce-paypal-payments' ), value: 'black' },
|
||||
{ label: __( 'White', 'woocommerce-paypal-payments' ), value: 'white' },
|
||||
{ label: __( 'White no border', 'woocommerce-paypal-payments' ), value: 'white-no-border' },
|
||||
{ label: __( 'Gray', 'woocommerce-paypal-payments' ), value: 'gray' },
|
||||
{ label: __( 'Monochrome', 'woocommerce-paypal-payments' ), value: 'monochrome' },
|
||||
{ label: __( 'Grayscale', 'woocommerce-paypal-payments' ), value: 'grayscale' },
|
||||
{ label: __( 'White (no border)', 'woocommerce-paypal-payments' ), value: 'white-no-border' },
|
||||
]}
|
||||
value={flexColor}
|
||||
onChange={(value) => setAttributes({flexColor: value})}
|
||||
|
@ -154,8 +183,6 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
{ isFlex && (<SelectControl
|
||||
label={__('Ratio', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __( '1x1', 'woocommerce-paypal-payments' ), value: '1x1' },
|
||||
{ label: __( '1x4', 'woocommerce-paypal-payments' ), value: '1x4' },
|
||||
{ label: __( '8x1', 'woocommerce-paypal-payments' ), value: '8x1' },
|
||||
{ label: __( '20x1', 'woocommerce-paypal-payments' ), value: '20x1' },
|
||||
]}
|
||||
|
@ -167,12 +194,11 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
help={ __( 'Used for the analytics dashboard in the merchant account.', 'woocommerce-paypal-payments' ) }
|
||||
options={ [
|
||||
{ label: __( 'Detect automatically', 'woocommerce-paypal-payments' ), value: 'auto' },
|
||||
{ label: __( 'Product Page', 'woocommerce-paypal-payments' ), value: 'product' },
|
||||
{ label: __( 'Cart', 'woocommerce-paypal-payments' ), value: 'cart' },
|
||||
{ label: __( 'Payment', 'woocommerce-paypal-payments' ), value: 'payment' },
|
||||
{ label: __( 'Product', 'woocommerce-paypal-payments' ), value: 'product' },
|
||||
{ label: __( 'Product list', 'woocommerce-paypal-payments' ), value: 'product-list' },
|
||||
{ label: __( 'Checkout', 'woocommerce-paypal-payments' ), value: 'checkout' },
|
||||
{ label: __( 'Home', 'woocommerce-paypal-payments' ), value: 'home' },
|
||||
{ label: __( 'Category', 'woocommerce-paypal-payments' ), value: 'category' },
|
||||
{ label: __( 'Shop', 'woocommerce-paypal-payments' ), value: 'shop' },
|
||||
] }
|
||||
value={ placement }
|
||||
onChange={ ( value ) => setAttributes( { placement: value } ) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
|
||||
export default function save( { attributes } ) {
|
||||
const { layout, logo, position, color, flexColor, flexRatio, placement, id } = attributes;
|
||||
const { layout, logo, position, color, size, flexColor, flexRatio, placement, id } = attributes;
|
||||
const paypalAttributes = layout === 'flex' ? {
|
||||
'data-pp-style-layout': 'flex',
|
||||
'data-pp-style-color': flexColor,
|
||||
|
@ -11,6 +11,7 @@ export default function save( { attributes } ) {
|
|||
'data-pp-style-logo-type': logo,
|
||||
'data-pp-style-logo-position': position,
|
||||
'data-pp-style-text-color': color,
|
||||
'data-pp-style-text-size': size,
|
||||
};
|
||||
if (placement && placement !== 'auto') {
|
||||
paypalAttributes['data-pp-placement'] = placement;
|
||||
|
|
|
@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
|||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
|
@ -22,16 +23,26 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
|||
*/
|
||||
class PayLaterBlockModule implements ModuleInterface {
|
||||
/**
|
||||
* Returns whether the block should be loaded.
|
||||
* Returns whether the block module should be loaded.
|
||||
*/
|
||||
public static function is_enabled(): bool {
|
||||
public static function is_module_loading_required(): bool {
|
||||
return apply_filters(
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
'woocommerce.feature-flags.woocommerce_paypal_payments.paylater_block_enabled',
|
||||
getenv( 'PCP_PAYLATER_BLOCK' ) === '1'
|
||||
getenv( 'PCP_PAYLATER_BLOCK' ) !== '0'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the block is enabled.
|
||||
*
|
||||
* @param SettingsStatus $settings_status The Settings status helper.
|
||||
* @return bool true if the block is enabled, otherwise false.
|
||||
*/
|
||||
public static function is_block_enabled( SettingsStatus $settings_status ): bool {
|
||||
return self::is_module_loading_required() && $settings_status->is_pay_later_messaging_enabled_for_location( 'custom_placement' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -71,13 +82,15 @@ class PayLaterBlockModule implements ModuleInterface {
|
|||
$script_handle,
|
||||
'PcpPayLaterBlock',
|
||||
array(
|
||||
'ajax' => array(
|
||||
'ajax' => array(
|
||||
'cart_script_params' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CartScriptParamsEndpoint::ENDPOINT ),
|
||||
),
|
||||
),
|
||||
'settingsUrl' => admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' ),
|
||||
'vaultingEnabled' => $settings->has( 'vault_enabled' ) && $settings->get( 'vault_enabled' ),
|
||||
'settingsUrl' => admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' ),
|
||||
'vaultingEnabled' => $settings->has( 'vault_enabled' ) && $settings->get( 'vault_enabled' ),
|
||||
'placementEnabled' => self::is_block_enabled( $c->get( 'wcgateway.settings.status' ) ),
|
||||
'payLaterSettingsUrl' => admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=ppcp-pay-later' ),
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -43,6 +43,11 @@
|
|||
.css-1yo2lxy-text_body_strong, span.css-16jt5za-text_body, span.css-1yo2lxy-text_body_strong, span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-right: 16px;
|
||||
border-top-color: #B1B7BD;
|
||||
}
|
||||
}
|
||||
|
||||
#field-pay_later_messaging_heading h3{
|
||||
|
|
|
@ -15,13 +15,22 @@ document.addEventListener( 'DOMContentLoaded', () => {
|
|||
headingRow.parentNode.insertBefore(newRow, headingRow.nextSibling);
|
||||
|
||||
|
||||
saveChangesButton.addEventListener('click', () => {
|
||||
form.querySelector('.' + publishButtonClassName).click();
|
||||
let isSaving = false; // Flag variable to track whether saving is in progress
|
||||
|
||||
// Delay the page refresh by a few milliseconds to ensure changes take effect
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 1000);
|
||||
saveChangesButton.addEventListener('click', () => {
|
||||
// Check if saving is not already in progress
|
||||
if (!isSaving) {
|
||||
isSaving = true; // Set flag to indicate saving is in progress
|
||||
|
||||
// Trigger the click event on the publish button
|
||||
form.querySelector('.' + publishButtonClassName).click();
|
||||
|
||||
// Trigger click event on saveChangesButton after a short delay
|
||||
setTimeout(() => {
|
||||
saveChangesButton.click(); // Trigger click event on saveChangesButton
|
||||
isSaving = false; // Reset flag when saving is complete
|
||||
}, 1000); // Adjust the delay as needed
|
||||
}
|
||||
});
|
||||
|
||||
merchantConfigurators.Messaging({
|
||||
|
@ -30,7 +39,7 @@ document.addEventListener( 'DOMContentLoaded', () => {
|
|||
partnerClientId: PcpPayLaterConfigurator.partnerClientId,
|
||||
partnerName: 'WooCommerce',
|
||||
bnCode: 'Woo_PPCP',
|
||||
placements: ['cart', 'checkout', 'product', 'category', 'homepage', 'custom_placement'],
|
||||
placements: ['cart', 'checkout', 'product', 'shop', 'home', 'custom_placement'],
|
||||
styleOverrides: {
|
||||
button: publishButtonClassName,
|
||||
header: PcpPayLaterConfigurator.headerClassName,
|
||||
|
|
|
@ -99,14 +99,15 @@ class SaveConfig {
|
|||
$this->settings->set( 'pay_later_messaging_enabled', true );
|
||||
|
||||
$enabled_locations = array();
|
||||
|
||||
foreach ( $config as $placement => $data ) {
|
||||
$location = $this->configurator_placement_to_location( $placement );
|
||||
$this->save_config_for_location( $data, $placement );
|
||||
|
||||
$this->save_config_for_location( $data, $location );
|
||||
if ( $placement === 'custom_placement' ) {
|
||||
$data = $data[0] ?? array();
|
||||
}
|
||||
|
||||
if ( $data['status'] === 'enabled' ) {
|
||||
$enabled_locations[] = $location;
|
||||
$enabled_locations[] = $placement;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,6 +132,7 @@ class SaveConfig {
|
|||
$this->set_value_if_present( $config, 'logo-type', "pay_later_{$location}_message_logo" );
|
||||
$this->set_value_if_present( $config, 'logo-color', "pay_later_{$location}_message_color" );
|
||||
$this->set_value_if_present( $config, 'text-size', "pay_later_{$location}_message_text_size" );
|
||||
$this->set_value_if_present( $config, 'text-color', "pay_later_{$location}_message_color" );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,24 +147,4 @@ class SaveConfig {
|
|||
$this->settings->set( $settings_key, $config[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the configurator placement into location in the old settings.
|
||||
*
|
||||
* @param string $placement The configurator placement.
|
||||
*/
|
||||
private function configurator_placement_to_location( string $placement ): string {
|
||||
switch ( $placement ) {
|
||||
case 'cart':
|
||||
case 'checkout':
|
||||
case 'product':
|
||||
return $placement;
|
||||
case 'category':
|
||||
return 'shop';
|
||||
case 'homepage':
|
||||
return 'home';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,11 +22,12 @@ class ConfigFactory {
|
|||
*/
|
||||
public function from_settings( Settings $settings ): array {
|
||||
return array(
|
||||
$this->location_to_configurator_placement( 'cart' ) => $this->for_location( $settings, 'cart' ),
|
||||
$this->location_to_configurator_placement( 'checkout' ) => $this->for_location( $settings, 'checkout' ),
|
||||
$this->location_to_configurator_placement( 'product' ) => $this->for_location( $settings, 'product' ),
|
||||
$this->location_to_configurator_placement( 'shop' ) => $this->for_location( $settings, 'shop' ),
|
||||
$this->location_to_configurator_placement( 'home' ) => $this->for_location( $settings, 'home' ),
|
||||
'cart' => $this->for_location( $settings, 'cart' ),
|
||||
'checkout' => $this->for_location( $settings, 'checkout' ),
|
||||
'product' => $this->for_location( $settings, 'product' ),
|
||||
'shop' => $this->for_location( $settings, 'shop' ),
|
||||
'home' => $this->for_location( $settings, 'home' ),
|
||||
'custom_placement' => array( $this->for_location( $settings, 'woocommerceBlock' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -39,51 +40,88 @@ class ConfigFactory {
|
|||
private function for_location( Settings $settings, string $location ): array {
|
||||
$selected_locations = $settings->has( 'pay_later_messaging_locations' ) ? $settings->get( 'pay_later_messaging_locations' ) : array();
|
||||
|
||||
$placement = $this->location_to_configurator_placement( $location );
|
||||
if ( in_array( $placement, array( 'category', 'homepage' ), true ) ) {
|
||||
$config = array(
|
||||
'layout' => 'flex',
|
||||
'color' => $this->get_or_default( $settings, "pay_later_{$location}_message_flex_color", 'black', array( 'black', 'blue', 'white', 'white-no-border' ) ),
|
||||
'ratio' => $this->get_or_default( $settings, "pay_later_{$location}_message_flex_ratio", '8x1', array( '8x1', '20x1' ) ),
|
||||
);
|
||||
} else {
|
||||
$config = array(
|
||||
'layout' => 'text',
|
||||
'logo-position' => $this->get_or_default( $settings, "pay_later_{$location}_message_position", 'left' ),
|
||||
'logo-type' => $this->get_or_default( $settings, "pay_later_{$location}_message_logo", 'inline' ),
|
||||
'text-color' => $this->get_or_default( $settings, "pay_later_{$location}_message_color", 'black' ),
|
||||
'text-size' => $this->get_or_default( $settings, "pay_later_{$location}_message_text_size", '12' ),
|
||||
|
||||
);
|
||||
switch ( $location ) {
|
||||
case 'shop':
|
||||
case 'home':
|
||||
$config = $this->for_shop_or_home( $settings, $location, $selected_locations );
|
||||
break;
|
||||
case 'woocommerceBlock':
|
||||
$config = $this->for_woocommerce_block( $selected_locations );
|
||||
break;
|
||||
default:
|
||||
$config = $this->for_default_location( $settings, $location, $selected_locations );
|
||||
break;
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
array(
|
||||
'status' => in_array( $location, $selected_locations, true ) ? 'enabled' : 'disabled',
|
||||
'placement' => $placement,
|
||||
),
|
||||
$config
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configurator config for shop, home locations.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @param string $location The location.
|
||||
* @param string[] $selected_locations The list of selected locations.
|
||||
* @return array{
|
||||
* layout: string,
|
||||
* color: string,
|
||||
* ratio: string,
|
||||
* status: "disabled"|"enabled",
|
||||
* placement: string
|
||||
* } The configurator config map.
|
||||
*/
|
||||
private function for_shop_or_home( Settings $settings, string $location, array $selected_locations ): array {
|
||||
return array(
|
||||
'layout' => $this->get_or_default( $settings, "pay_later_{$location}_message_layout", 'flex' ),
|
||||
'color' => $this->get_or_default( $settings, "pay_later_{$location}_message_flex_color", 'black' ),
|
||||
'ratio' => $this->get_or_default( $settings, "pay_later_{$location}_message_flex_ratio", '8x1' ),
|
||||
'status' => in_array( $location, $selected_locations, true ) ? 'enabled' : 'disabled',
|
||||
'placement' => $location,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the location name from the old settings into the configurator placement.
|
||||
* Returns the configurator config for woocommerceBlock location.
|
||||
*
|
||||
* @param string $location The location name in the old settings.
|
||||
* @param array $selected_locations The list of selected locations.
|
||||
* @return array{
|
||||
* status: "disabled"|"enabled",
|
||||
* message_reference: string
|
||||
* } The configurator config map.
|
||||
*/
|
||||
private function location_to_configurator_placement( string $location ): string {
|
||||
switch ( $location ) {
|
||||
case 'cart':
|
||||
case 'checkout':
|
||||
case 'product':
|
||||
return $location;
|
||||
case 'shop':
|
||||
return 'category';
|
||||
case 'home':
|
||||
return 'homepage';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
private function for_woocommerce_block( array $selected_locations ): array {
|
||||
return array(
|
||||
'status' => in_array( 'custom_placement', $selected_locations, true ) ? 'enabled' : 'disabled',
|
||||
'message_reference' => 'woocommerceBlock',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configurator config for default locations.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @param string $location The location.
|
||||
* @param string[] $selected_locations The list of selected locations.
|
||||
* @return array{
|
||||
* layout: string,
|
||||
* logo-position: string,
|
||||
* logo-type: string,
|
||||
* text-color: string,
|
||||
* text-size: string,
|
||||
* status: "disabled"|"enabled",
|
||||
* placement: string
|
||||
* } The configurator config map.
|
||||
*/
|
||||
private function for_default_location( Settings $settings, string $location, array $selected_locations ): array {
|
||||
return array(
|
||||
'layout' => $this->get_or_default( $settings, "pay_later_{$location}_message_layout", 'text' ),
|
||||
'logo-position' => $this->get_or_default( $settings, "pay_later_{$location}_message_position", 'left' ),
|
||||
'logo-type' => $this->get_or_default( $settings, "pay_later_{$location}_message_logo", 'inline' ),
|
||||
'text-color' => $this->get_or_default( $settings, "pay_later_{$location}_message_color", 'black' ),
|
||||
'text-size' => $this->get_or_default( $settings, "pay_later_{$location}_message_text_size", '12' ),
|
||||
'status' => in_array( $location, $selected_locations, true ) ? 'enabled' : 'disabled',
|
||||
'placement' => $location,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,9 +131,9 @@ class ConfigFactory {
|
|||
* @param string $key The key.
|
||||
* @param mixed $default The default value.
|
||||
* @param array|null $allowed_values The list of allowed values, or null if all values are allowed.
|
||||
* @return mixed
|
||||
* @return string
|
||||
*/
|
||||
private function get_or_default( Settings $settings, string $key, $default, ?array $allowed_values = null ) {
|
||||
private function get_or_default( Settings $settings, string $key, $default, ?array $allowed_values = null ): string {
|
||||
if ( $settings->has( $key ) ) {
|
||||
$value = $settings->get( $key );
|
||||
if ( ! $allowed_values || in_array( $value, $allowed_values, true ) ) {
|
||||
|
|
|
@ -29,7 +29,7 @@ class PayLaterConfiguratorModule implements ModuleInterface {
|
|||
return apply_filters(
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
'woocommerce.feature-flags.woocommerce_paypal_payments.paylater_configurator_enabled',
|
||||
getenv( 'PCP_PAYLATER_CONFIGURATOR' ) === '1'
|
||||
getenv( 'PCP_PAYLATER_CONFIGURATOR' ) !== '0'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ class PayLaterConfiguratorModule implements ModuleInterface {
|
|||
static function () use ( $c, $settings ) {
|
||||
wp_enqueue_script(
|
||||
'ppcp-paylater-configurator-lib',
|
||||
'https://www.paypalobjects.com/merchant-library/preview/merchant-configurator.js',
|
||||
'https://www.paypalobjects.com/merchant-library/merchant-configurator.js',
|
||||
array(),
|
||||
$c->get( 'ppcp.asset-version' ),
|
||||
true
|
||||
|
|
|
@ -114,7 +114,7 @@ class SubscriptionsApiHandler {
|
|||
*/
|
||||
public function create_product( WC_Product $product ) {
|
||||
try {
|
||||
$subscription_product = $this->products_endpoint->create( $product->get_title(), $this->prepare_description( $product->get_description() ) );
|
||||
$subscription_product = $this->products_endpoint->create( $this->prepare_item_string( $product->get_title() ), $this->prepare_item_string( $product->get_description() ) );
|
||||
$product->update_meta_data( 'ppcp_subscription_product', $subscription_product->to_array() );
|
||||
$product->save();
|
||||
} catch ( RuntimeException $exception ) {
|
||||
|
@ -169,7 +169,7 @@ class SubscriptionsApiHandler {
|
|||
$catalog_product_name = $catalog_product->name() ?: '';
|
||||
$catalog_product_description = $catalog_product->description() ?: '';
|
||||
|
||||
$wc_product_description = $this->prepare_description( $product->get_description() ) ?: $product->get_title();
|
||||
$wc_product_description = $this->prepare_item_string( $product->get_description() ) ?: $this->prepare_item_string( $product->get_title() );
|
||||
|
||||
if ( $catalog_product_name !== $product->get_title() || $catalog_product_description !== $wc_product_description ) {
|
||||
$data = array();
|
||||
|
|
|
@ -12,7 +12,7 @@ import ErrorHandler from "../../../ppcp-button/resources/js/modules/ErrorHandler
|
|||
import {cardFieldStyles} from "../../../ppcp-button/resources/js/modules/Helper/CardFieldsHelper";
|
||||
|
||||
const errorHandler = new ErrorHandler(
|
||||
PayPalCommerceGateway.labels.error.generic,
|
||||
ppcp_add_payment_method.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
);
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods;
|
||||
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Helper\SavePaymentMethodsApplies;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
|
@ -805,31 +805,17 @@ return array(
|
|||
$container->get( 'api.endpoint.payment-method-tokens' )
|
||||
);
|
||||
},
|
||||
'save-payment-methods.wc-payment-tokens' => static function( ContainerInterface $container ): WooCommercePaymentTokens {
|
||||
return new WooCommercePaymentTokens(
|
||||
$container->get( 'vaulting.payment-token-helper' ),
|
||||
$container->get( 'vaulting.payment-token-factory' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'save-payment-methods.endpoint.create-payment-token' => static function ( ContainerInterface $container ): CreatePaymentToken {
|
||||
return new CreatePaymentToken(
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'api.endpoint.payment-method-tokens' ),
|
||||
$container->get( 'save-payment-methods.wc-payment-tokens' )
|
||||
$container->get( 'vaulting.wc-payment-tokens' )
|
||||
);
|
||||
},
|
||||
'save-payment-methods.endpoint.capture-card-payment' => static function( ContainerInterface $container ): CaptureCardPayment {
|
||||
return new CaptureCardPayment(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'api.factory.order' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'wc-subscriptions.helpers.real-time-account-updater' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
'save-payment-methods.endpoint.create-payment-token-for-guest' => static function ( ContainerInterface $container ): CreatePaymentTokenForGuest {
|
||||
return new CreatePaymentTokenForGuest(
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'api.endpoint.payment-method-tokens' )
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -14,9 +14,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentMethodTokensEndpoint;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
|
||||
/**
|
||||
* Class CreatePaymentToken
|
||||
|
@ -96,7 +94,7 @@ class CreatePaymentToken implements EndpointInterface {
|
|||
)
|
||||
);
|
||||
|
||||
$result = $this->payment_method_tokens_endpoint->payment_tokens( $payment_source );
|
||||
$result = $this->payment_method_tokens_endpoint->create_payment_token( $payment_source );
|
||||
|
||||
if ( is_user_logged_in() && isset( $result->customer->id ) ) {
|
||||
$current_user_id = get_current_user_id();
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
/**
|
||||
* Create payment token for guest user.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentMethodTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
|
||||
/**
|
||||
* Class UpdateCustomerId
|
||||
*/
|
||||
class CreatePaymentTokenForGuest implements EndpointInterface {
|
||||
|
||||
const ENDPOINT = 'ppc-update-customer-id';
|
||||
|
||||
/**
|
||||
* The request data.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The payment method tokens endpoint.
|
||||
*
|
||||
* @var PaymentMethodTokensEndpoint
|
||||
*/
|
||||
private $payment_method_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* CreatePaymentToken constructor.
|
||||
*
|
||||
* @param RequestData $request_data The request data.
|
||||
* @param PaymentMethodTokensEndpoint $payment_method_tokens_endpoint The payment method tokens endpoint.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
PaymentMethodTokensEndpoint $payment_method_tokens_endpoint
|
||||
) {
|
||||
$this->request_data = $request_data;
|
||||
$this->payment_method_tokens_endpoint = $payment_method_tokens_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception On Error.
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
|
||||
/**
|
||||
* Suppress ArgumentTypeCoercion
|
||||
*
|
||||
* @psalm-suppress ArgumentTypeCoercion
|
||||
*/
|
||||
$payment_source = new PaymentSource(
|
||||
'token',
|
||||
(object) array(
|
||||
'id' => $data['vault_setup_token'],
|
||||
'type' => 'SETUP_TOKEN',
|
||||
)
|
||||
);
|
||||
|
||||
$result = $this->payment_method_tokens_endpoint->create_payment_token( $payment_source );
|
||||
WC()->session->set( 'ppcp_guest_payment_for_free_trial', $result );
|
||||
|
||||
wp_send_json_success();
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -19,9 +19,10 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
|
@ -141,7 +142,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
'vault' => array(
|
||||
'store_in_vault' => 'ON_SUCCESS',
|
||||
'usage_type' => 'MERCHANT',
|
||||
'permit_multiple_payment_tokens' => true,
|
||||
'permit_multiple_payment_tokens' => apply_filters( 'woocommerce_paypal_payments_permit_multiple_payment_tokens', false ),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -167,7 +168,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
'vault' => array(
|
||||
'store_in_vault' => 'ON_SUCCESS',
|
||||
'usage_type' => 'MERCHANT',
|
||||
'permit_multiple_payment_tokens' => true,
|
||||
'permit_multiple_payment_tokens' => apply_filters( 'woocommerce_paypal_payments_permit_multiple_payment_tokens', false ),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -197,7 +198,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
|
||||
update_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', $customer_id );
|
||||
|
||||
$wc_payment_tokens = $c->get( 'save-payment-methods.wc-payment-tokens' );
|
||||
$wc_payment_tokens = $c->get( 'vaulting.wc-payment-tokens' );
|
||||
assert( $wc_payment_tokens instanceof WooCommercePaymentTokens );
|
||||
|
||||
if ( $wc_order->get_payment_method() === CreditCardGateway::ID ) {
|
||||
|
@ -281,7 +282,11 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
|
||||
$settings = $c->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
$verification_method = $settings->has( '3d_secure_contingency' ) ? $settings->get( '3d_secure_contingency' ) : '';
|
||||
|
||||
$verification_method =
|
||||
$settings->has( '3d_secure_contingency' )
|
||||
? apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $settings->get( '3d_secure_contingency' ) )
|
||||
: '';
|
||||
|
||||
$change_payment_method = wc_clean( wp_unslash( $_GET['change_payment_method'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification
|
||||
|
||||
|
@ -312,6 +317,14 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
'nonce' => wp_create_nonce( SubscriptionChangePaymentMethod::nonce() ),
|
||||
),
|
||||
),
|
||||
'labels' => array(
|
||||
'error' => array(
|
||||
'generic' => __(
|
||||
'Something went wrong. Please try again or choose another payment source.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
} catch ( RuntimeException $exception ) {
|
||||
|
@ -359,6 +372,16 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . CreatePaymentTokenForGuest::ENDPOINT,
|
||||
static function () use ( $c ) {
|
||||
$endpoint = $c->get( 'save-payment-methods.endpoint.create-payment-token-for-guest' );
|
||||
assert( $endpoint instanceof CreatePaymentTokenForGuest );
|
||||
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_before_delete_payment_token',
|
||||
function( string $token_id ) use ( $c ) {
|
||||
|
|
|
@ -56,4 +56,15 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'vaulting.wc-payment-tokens' => static function( ContainerInterface $container ): WooCommercePaymentTokens {
|
||||
return new WooCommercePaymentTokens(
|
||||
$container->get( 'vaulting.payment-token-helper' ),
|
||||
$container->get( 'vaulting.payment-token-factory' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'vaulting.vault-v3-enabled' => static function( ContainerInterface $container ): bool {
|
||||
return $container->has( 'save-payment-methods.eligible' ) && $container->get( 'save-payment-methods.eligible' );
|
||||
},
|
||||
);
|
||||
|
|
|
@ -7,18 +7,15 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods;
|
||||
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use stdClass;
|
||||
use WC_Payment_Token_CC;
|
||||
use WC_Payment_Tokens;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenApplePay;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenFactory;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenPayPal;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenVenmo;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
||||
|
@ -41,6 +38,13 @@ class WooCommercePaymentTokens {
|
|||
*/
|
||||
private $payment_token_factory;
|
||||
|
||||
/**
|
||||
* Payment tokens endpoint.
|
||||
*
|
||||
* @var PaymentTokensEndpoint
|
||||
*/
|
||||
private $payment_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -51,18 +55,21 @@ class WooCommercePaymentTokens {
|
|||
/**
|
||||
* WooCommercePaymentTokens constructor.
|
||||
*
|
||||
* @param PaymentTokenHelper $payment_token_helper The payment token helper.
|
||||
* @param PaymentTokenFactory $payment_token_factory The payment token factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentTokenHelper $payment_token_helper The payment token helper.
|
||||
* @param PaymentTokenFactory $payment_token_factory The payment token factory.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
PaymentTokenHelper $payment_token_helper,
|
||||
PaymentTokenFactory $payment_token_factory,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->payment_token_helper = $payment_token_helper;
|
||||
$this->payment_token_factory = $payment_token_factory;
|
||||
$this->logger = $logger;
|
||||
$this->payment_token_helper = $payment_token_helper;
|
||||
$this->payment_token_factory = $payment_token_factory;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,6 +87,10 @@ class WooCommercePaymentTokens {
|
|||
string $email
|
||||
): int {
|
||||
|
||||
if ( $customer_id === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $token, PaymentTokenPayPal::class ) ) {
|
||||
return 0;
|
||||
|
@ -128,6 +139,10 @@ class WooCommercePaymentTokens {
|
|||
string $email
|
||||
): int {
|
||||
|
||||
if ( $customer_id === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $token, PaymentTokenVenmo::class ) ) {
|
||||
return 0;
|
||||
|
@ -174,6 +189,10 @@ class WooCommercePaymentTokens {
|
|||
string $token
|
||||
): int {
|
||||
|
||||
if ( $customer_id === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $token, PaymentTokenApplePay::class ) ) {
|
||||
return 0;
|
||||
|
@ -212,6 +231,10 @@ class WooCommercePaymentTokens {
|
|||
* @return int
|
||||
*/
|
||||
public function create_payment_token_card( int $customer_id, stdClass $payment_token ): int {
|
||||
if ( $customer_id === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, CreditCardGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $payment_token->id ) ) {
|
||||
return 0;
|
||||
|
@ -219,7 +242,7 @@ class WooCommercePaymentTokens {
|
|||
|
||||
$token = new WC_Payment_Token_CC();
|
||||
$token->set_token( $payment_token->id );
|
||||
$token->set_user_id( get_current_user_id() );
|
||||
$token->set_user_id( $customer_id );
|
||||
$token->set_gateway_id( CreditCardGateway::ID );
|
||||
|
||||
$token->set_last4( $payment_token->payment_source->card->last_digits ?? '' );
|
||||
|
@ -243,4 +266,61 @@ class WooCommercePaymentTokens {
|
|||
$token->save();
|
||||
return $token->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns PayPal payment tokens for the given WP user id.
|
||||
*
|
||||
* @param int $user_id WP user id.
|
||||
* @return array
|
||||
*/
|
||||
public function customer_tokens( int $user_id ): array {
|
||||
$customer_id = get_user_meta( $user_id, '_ppcp_target_customer_id', true );
|
||||
if ( ! $customer_id ) {
|
||||
$customer_id = get_user_meta( $user_id, 'ppcp_customer_id', true );
|
||||
}
|
||||
|
||||
try {
|
||||
$customer_tokens = $this->payment_tokens_endpoint->payment_tokens_for_customer( $customer_id );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$customer_tokens = array();
|
||||
}
|
||||
|
||||
return $customer_tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates WC payment tokens for the given WP user id using PayPal payment tokens as source.
|
||||
*
|
||||
* @param array $customer_tokens PayPal customer payment tokens.
|
||||
* @param int $user_id WP user id.
|
||||
* @return void
|
||||
*/
|
||||
public function create_wc_tokens( array $customer_tokens, int $user_id ): void {
|
||||
foreach ( $customer_tokens as $customer_token ) {
|
||||
if ( $customer_token['payment_source']->name() === 'paypal' ) {
|
||||
$this->create_payment_token_paypal(
|
||||
$user_id,
|
||||
$customer_token['id'],
|
||||
$customer_token['payment_source']->properties()->email_address ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
if ( $customer_token['payment_source']->name() === 'card' ) {
|
||||
/**
|
||||
* Suppress ArgumentTypeCoercion
|
||||
*
|
||||
* @psalm-suppress ArgumentTypeCoercion
|
||||
*/
|
||||
$this->create_payment_token_card(
|
||||
$user_id,
|
||||
(object) array(
|
||||
'id' => $customer_token['id'],
|
||||
'payment_source' => (object) array(
|
||||
$customer_token['payment_source']->name() => $customer_token['payment_source']->properties(),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@ use WooCommerce\PayPalCommerce\Common\Pattern\SingletonDecorator;
|
|||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Admin\RenderReauthorizeAction;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\RefreshFeatureStatusEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
@ -101,7 +103,10 @@ return array(
|
|||
$api_shop_country,
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'api.factory.paypal-checkout-url' ),
|
||||
$container->get( 'wcgateway.place-order-button-text' )
|
||||
$container->get( 'wcgateway.place-order-button-text' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'vaulting.vault-v3-enabled' ),
|
||||
$container->get( 'vaulting.wc-payment-tokens' )
|
||||
);
|
||||
},
|
||||
'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
|
||||
|
@ -131,8 +136,10 @@ return array(
|
|||
$vaulted_credit_card_handler,
|
||||
$container->get( 'onboarding.environment' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'save-payment-methods.endpoint.capture-card-payment' ),
|
||||
$container->get( 'wcgateway.endpoint.capture-card-payment' ),
|
||||
$container->get( 'api.prefix' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'vaulting.wc-payment-tokens' ),
|
||||
$logger
|
||||
);
|
||||
},
|
||||
|
@ -384,19 +391,25 @@ return array(
|
|||
$notice = $container->get( 'wcgateway.notice.authorize-order-action' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$subscription_helper = $container->get( 'wc-subscriptions.helper' );
|
||||
$amount_factory = $container->get( 'api.factory.amount' );
|
||||
return new AuthorizedPaymentsProcessor(
|
||||
$order_endpoint,
|
||||
$payments_endpoint,
|
||||
$logger,
|
||||
$notice,
|
||||
$settings,
|
||||
$subscription_helper
|
||||
$subscription_helper,
|
||||
$amount_factory
|
||||
);
|
||||
},
|
||||
'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
|
||||
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
||||
return new RenderAuthorizeAction( $column );
|
||||
},
|
||||
'wcgateway.admin.render-reauthorize-action' => static function ( ContainerInterface $container ): RenderReauthorizeAction {
|
||||
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
||||
return new RenderReauthorizeAction( $column );
|
||||
},
|
||||
'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
|
||||
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
||||
return new PaymentStatusOrderDetail( $column );
|
||||
|
@ -952,10 +965,10 @@ return array(
|
|||
'ideal' => _x( 'iDEAL', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'mybank' => _x( 'MyBank', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'p24' => _x( 'Przelewy24', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'sofort' => _x( 'Sofort', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'venmo' => _x( 'Venmo', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'trustly' => _x( 'Trustly', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'paylater' => _x( 'Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'paylater' => _x( 'PayPal Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'paypal' => _x( 'PayPal', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -978,6 +991,7 @@ return array(
|
|||
array_flip(
|
||||
array(
|
||||
'paylater',
|
||||
'paypal',
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -1579,4 +1593,17 @@ return array(
|
|||
)
|
||||
);
|
||||
},
|
||||
'wcgateway.endpoint.capture-card-payment' => static function( ContainerInterface $container ): CaptureCardPayment {
|
||||
return new CaptureCardPayment(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'api.factory.order' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'wc-subscriptions.helpers.real-time-account-updater' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -9,9 +9,6 @@ declare( strict_types=1 );
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Admin;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
|
||||
/**
|
||||
* Class RenderAuthorizeAction
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* Renders the order action "Reauthorize PayPal payment"
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Admin
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Admin;
|
||||
|
||||
/**
|
||||
* Class RenderReauthorizeAction
|
||||
*/
|
||||
class RenderReauthorizeAction {
|
||||
/**
|
||||
* The capture info column.
|
||||
*
|
||||
* @var OrderTablePaymentStatusColumn
|
||||
*/
|
||||
private $column;
|
||||
|
||||
/**
|
||||
* PaymentStatusOrderDetail constructor.
|
||||
*
|
||||
* @param OrderTablePaymentStatusColumn $column The capture info column.
|
||||
*/
|
||||
public function __construct( OrderTablePaymentStatusColumn $column ) {
|
||||
$this->column = $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the action into the $order_actions array based on the WooCommerce order.
|
||||
*
|
||||
* @param array $order_actions The actions to render into.
|
||||
* @param \WC_Order $wc_order The order for which to render the action.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function render( array $order_actions, \WC_Order $wc_order ) : array {
|
||||
|
||||
if ( ! $this->should_render_for_order( $wc_order ) ) {
|
||||
return $order_actions;
|
||||
}
|
||||
|
||||
$order_actions['ppcp_reauthorize_order'] = esc_html__(
|
||||
'Reauthorize PayPal payment',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
return $order_actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the action should be rendered for a certain WooCommerce order.
|
||||
*
|
||||
* @param \WC_Order $order The Woocommerce order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function should_render_for_order( \WC_Order $order ) : bool {
|
||||
$status = $order->get_status();
|
||||
$not_allowed_statuses = array( 'refunded', 'cancelled', 'failed' );
|
||||
return $this->column->should_render_for_order( $order ) &&
|
||||
! $this->column->is_captured( $order ) &&
|
||||
! in_array( $status, $not_allowed_statuses, true );
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint;
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
|
@ -34,7 +34,7 @@ class FundingSourceRenderer {
|
|||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $own_funding_sources = array( 'venmo', 'paylater' );
|
||||
protected $own_funding_sources = array( 'venmo', 'paylater', 'paypal' );
|
||||
|
||||
/**
|
||||
* FundingSourceRenderer constructor.
|
||||
|
@ -63,7 +63,7 @@ class FundingSourceRenderer {
|
|||
return $this->funding_sources[ $id ];
|
||||
}
|
||||
return sprintf(
|
||||
/* translators: %s - Sofort, BLIK, iDeal, Mercado Pago, etc. */
|
||||
/* translators: %s - BLIK, iDeal, Mercado Pago, etc. */
|
||||
__( '%s (via PayPal)', 'woocommerce-paypal-payments' ),
|
||||
$this->funding_sources[ $id ]
|
||||
);
|
||||
|
@ -84,7 +84,7 @@ class FundingSourceRenderer {
|
|||
|
||||
if ( array_key_exists( $id, $this->funding_sources ) ) {
|
||||
return sprintf(
|
||||
/* translators: %s - Sofort, BLIK, iDeal, Mercado Pago, etc. */
|
||||
/* translators: %s - BLIK, iDeal, Mercado Pago, etc. */
|
||||
__( 'Pay via %s.', 'woocommerce-paypal-payments' ),
|
||||
$this->funding_sources[ $id ]
|
||||
);
|
||||
|
|
|
@ -15,30 +15,33 @@ use WC_Order;
|
|||
use WC_Payment_Tokens;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\VaultedCreditCardHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
|
||||
/**
|
||||
* Class CreditCardGateway
|
||||
*/
|
||||
class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||
|
||||
use ProcessPaymentTrait, GatewaySettingsRendererTrait, TransactionIdHandlingTrait, PaymentsStatusHandlingTrait;
|
||||
use ProcessPaymentTrait, GatewaySettingsRendererTrait, TransactionIdHandlingTrait, PaymentsStatusHandlingTrait, FreeTrialHandlerTrait;
|
||||
|
||||
const ID = 'ppcp-credit-card-gateway';
|
||||
|
||||
|
@ -154,6 +157,20 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* Payment tokens endpoint.
|
||||
*
|
||||
* @var PaymentTokensEndpoint
|
||||
*/
|
||||
private $payment_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* WooCommerce payment tokens factory.
|
||||
*
|
||||
* @var WooCommercePaymentTokens
|
||||
*/
|
||||
private $wc_payment_tokens;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -179,6 +196,8 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param CaptureCardPayment $capture_card_payment Capture card payment.
|
||||
* @param string $prefix The prefix.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param WooCommercePaymentTokens $wc_payment_tokens WooCommerce payment tokens factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
|
@ -197,6 +216,8 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
OrderEndpoint $order_endpoint,
|
||||
CaptureCardPayment $capture_card_payment,
|
||||
string $prefix,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
WooCommercePaymentTokens $wc_payment_tokens,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
@ -215,6 +236,8 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
$this->order_endpoint = $order_endpoint;
|
||||
$this->capture_card_payment = $capture_card_payment;
|
||||
$this->prefix = $prefix;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
$this->wc_payment_tokens = $wc_payment_tokens;
|
||||
$this->logger = $logger;
|
||||
|
||||
if ( $state->current_state() === State::STATE_ONBOARDED ) {
|
||||
|
@ -291,8 +314,10 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
public function form() {
|
||||
add_action( 'gettext', array( $this, 'replace_credit_card_cvv_label' ), 10, 3 );
|
||||
add_action( 'gettext', array( $this, 'replace_credit_card_cvv_placeholder' ), 10, 3 );
|
||||
parent::form();
|
||||
remove_action( 'gettext', 'replace_credit_card_cvv_label' );
|
||||
remove_action( 'gettext', 'replace_credit_card_cvv_placeholder' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -312,6 +337,23 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
return __( 'CVV', 'woocommerce-paypal-payments' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace WooCommerce credit card CVV field placeholder.
|
||||
*
|
||||
* @param string $translation Translated text.
|
||||
* @param string $text Original text to translate.
|
||||
* @param string $domain Text domain.
|
||||
*
|
||||
* @return string Translated field.
|
||||
*/
|
||||
public function replace_credit_card_cvv_placeholder( string $translation, string $text, string $domain ): string {
|
||||
if ( 'woocommerce' !== $domain || 'CVC' !== $text || ! apply_filters( 'woocommerce_paypal_payments_card_fields_translate_card_cvv', true ) ) {
|
||||
return $translation;
|
||||
}
|
||||
|
||||
return __( 'CVV', 'woocommerce-paypal-payments' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icons of the gateway.
|
||||
*
|
||||
|
@ -413,10 +455,39 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$card_payment_token_id = wc_clean( wp_unslash( $_POST['wc-ppcp-credit-card-gateway-payment-token'] ?? '' ) );
|
||||
|
||||
if ( $this->is_free_trial_order( $wc_order ) && $card_payment_token_id ) {
|
||||
$customer_tokens = $this->wc_payment_tokens->customer_tokens( get_current_user_id() );
|
||||
foreach ( $customer_tokens as $token ) {
|
||||
if ( $token['payment_source']->name() === 'card' ) {
|
||||
$wc_order->payment_complete();
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $card_payment_token_id ) {
|
||||
$customer_tokens = $this->wc_payment_tokens->customer_tokens( get_current_user_id() );
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), self::ID );
|
||||
|
||||
if ( $customer_tokens && empty( $wc_tokens ) ) {
|
||||
$this->wc_payment_tokens->create_wc_tokens( $customer_tokens, get_current_user_id() );
|
||||
}
|
||||
|
||||
$customer_token_ids = array();
|
||||
foreach ( $customer_tokens as $customer_token ) {
|
||||
$customer_token_ids[] = $customer_token['id'];
|
||||
}
|
||||
|
||||
$tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id() );
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->get_id() === (int) $card_payment_token_id ) {
|
||||
if ( ! in_array( $token->get_token(), $customer_token_ids, true ) ) {
|
||||
$token->delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
$custom_id = $wc_order->get_order_number();
|
||||
$invoice_id = $this->prefix . $wc_order->get_order_number();
|
||||
$create_order = $this->capture_card_payment->create_order( $token->get_token(), $custom_id, $invoice_id );
|
||||
|
|
|
@ -14,12 +14,14 @@ use Psr\Log\LoggerInterface;
|
|||
use WC_Order;
|
||||
use WC_Payment_Tokens;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
|
@ -48,12 +50,18 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
const ORDER_ID_META_KEY = '_ppcp_paypal_order_id';
|
||||
const ORDER_PAYMENT_MODE_META_KEY = '_ppcp_paypal_payment_mode';
|
||||
const ORDER_PAYMENT_SOURCE_META_KEY = '_ppcp_paypal_payment_source';
|
||||
const ORDER_PAYER_EMAIL_META_KEY = '_ppcp_paypal_payer_email';
|
||||
const FEES_META_KEY = '_ppcp_paypal_fees';
|
||||
const REFUND_FEES_META_KEY = '_ppcp_paypal_refund_fees';
|
||||
const REFUNDS_META_KEY = '_ppcp_refunds';
|
||||
const THREE_D_AUTH_RESULT_META_KEY = '_ppcp_paypal_3DS_auth_result';
|
||||
const FRAUD_RESULT_META_KEY = '_ppcp_paypal_fraud_result';
|
||||
|
||||
/**
|
||||
* List of payment sources wich we are expected to store the payer email in the WC Order metadata.
|
||||
*/
|
||||
const PAYMENT_SOURCES_WITH_PAYER_EMAIL = array( 'paypal', 'paylater', 'venmo' );
|
||||
|
||||
/**
|
||||
* The Settings Renderer.
|
||||
*
|
||||
|
@ -173,26 +181,50 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
*/
|
||||
private $paypal_checkout_url_factory;
|
||||
|
||||
/**
|
||||
* Payment tokens endpoint.
|
||||
*
|
||||
* @var PaymentTokensEndpoint
|
||||
*/
|
||||
private $payment_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* Whether Vault v3 module is enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $vault_v3_enabled;
|
||||
|
||||
/**
|
||||
* WooCommerce payment tokens.
|
||||
*
|
||||
* @var WooCommercePaymentTokens
|
||||
*/
|
||||
private $wc_payment_tokens;
|
||||
|
||||
/**
|
||||
* PayPalGateway constructor.
|
||||
*
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @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.
|
||||
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $api_shop_country The api shop country.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param callable(string):string $paypal_checkout_url_factory The function return the PayPal checkout URL for the given order ID.
|
||||
* @param string $place_order_button_text The text for the standard "Place order" button.
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @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.
|
||||
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $api_shop_country The api shop country.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param callable(string):string $paypal_checkout_url_factory The function return the PayPal checkout URL for the given order ID.
|
||||
* @param string $place_order_button_text The text for the standard "Place order" button.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param bool $vault_v3_enabled Whether Vault v3 module is enabled.
|
||||
* @param WooCommercePaymentTokens $wc_payment_tokens WooCommerce payment tokens.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
|
@ -211,7 +243,10 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
string $api_shop_country,
|
||||
OrderEndpoint $order_endpoint,
|
||||
callable $paypal_checkout_url_factory,
|
||||
string $place_order_button_text
|
||||
string $place_order_button_text,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
bool $vault_v3_enabled,
|
||||
WooCommercePaymentTokens $wc_payment_tokens
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
|
@ -231,6 +266,10 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
$this->api_shop_country = $api_shop_country;
|
||||
$this->paypal_checkout_url_factory = $paypal_checkout_url_factory;
|
||||
$this->order_button_text = $place_order_button_text;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
$this->vault_v3_enabled = $vault_v3_enabled;
|
||||
$this->wc_payment_tokens = $wc_payment_tokens;
|
||||
|
||||
if ( $this->onboarded ) {
|
||||
$this->supports = array( 'refunds', 'tokenization' );
|
||||
|
@ -295,8 +334,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -496,7 +533,49 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
$wc_order->save();
|
||||
}
|
||||
|
||||
if ( 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) && ! $this->subscription_helper->paypal_subscription_id() ) {
|
||||
if (
|
||||
'card' !== $funding_source
|
||||
&& $this->is_free_trial_order( $wc_order )
|
||||
&& ! $this->subscription_helper->paypal_subscription_id()
|
||||
) {
|
||||
$ppcp_guest_payment_for_free_trial = WC()->session->get( 'ppcp_guest_payment_for_free_trial' ) ?? null;
|
||||
if ( $this->vault_v3_enabled && $ppcp_guest_payment_for_free_trial ) {
|
||||
$customer_id = $ppcp_guest_payment_for_free_trial->customer->id ?? '';
|
||||
if ( $customer_id ) {
|
||||
update_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', $customer_id );
|
||||
}
|
||||
|
||||
if ( isset( $ppcp_guest_payment_for_free_trial->payment_source->paypal ) ) {
|
||||
$email = '';
|
||||
if ( isset( $ppcp_guest_payment_for_free_trial->payment_source->paypal->email_address ) ) {
|
||||
$email = $ppcp_guest_payment_for_free_trial->payment_source->paypal->email_address;
|
||||
}
|
||||
|
||||
$this->wc_payment_tokens->create_payment_token_paypal(
|
||||
$wc_order->get_customer_id(),
|
||||
$ppcp_guest_payment_for_free_trial->id,
|
||||
$email
|
||||
);
|
||||
}
|
||||
|
||||
WC()->session->set( 'ppcp_guest_payment_for_free_trial', null );
|
||||
|
||||
$wc_order->payment_complete();
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
$customer_id = get_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', true );
|
||||
if ( $customer_id ) {
|
||||
$customer_tokens = $this->payment_tokens_endpoint->payment_tokens_for_customer( $customer_id );
|
||||
foreach ( $customer_tokens as $token ) {
|
||||
$payment_source_name = $token['payment_source']->name() ?? '';
|
||||
if ( $payment_source_name === 'paypal' || $payment_source_name === 'venmo' ) {
|
||||
$wc_order->payment_complete();
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
||||
if ( ! array_filter(
|
||||
|
@ -509,7 +588,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
|
|
|
@ -198,25 +198,41 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
'description' => __( "Specify brand name, logo and customer service instructions to be presented on Ratepay's payment instructions.", 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'brand_name' => array(
|
||||
'title' => __( 'Brand name', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => get_bloginfo( 'name' ) ?? '',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Merchant name displayed in Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
|
||||
'title' => __( 'Brand name', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => get_bloginfo( 'name' ) ?? '',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Merchant name displayed in Ratepay\'s payment instructions. Should not exceed 127 characters.', 'woocommerce-paypal-payments' ),
|
||||
'maxlength' => 127,
|
||||
'custom_attributes' => array(
|
||||
'pattern' => '.{1,127}',
|
||||
'autocomplete' => 'off',
|
||||
'required' => '',
|
||||
),
|
||||
),
|
||||
'logo_url' => array(
|
||||
'title' => __( 'Logo URL', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'url',
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Logo to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
|
||||
'title' => __( 'Logo URL', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'url',
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Logo to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
|
||||
'custom_attributes' => array(
|
||||
'pattern' => '.+',
|
||||
'autocomplete' => 'off',
|
||||
'required' => '',
|
||||
),
|
||||
),
|
||||
'customer_service_instructions' => array(
|
||||
'title' => __( 'Customer service instructions', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Customer service instructions to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
|
||||
'title' => __( 'Customer service instructions', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Customer service instructions to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
|
||||
'custom_attributes' => array(
|
||||
'pattern' => '.+',
|
||||
'autocomplete' => 'off',
|
||||
'required' => '',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\AmountFactory;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
|
@ -91,6 +93,20 @@ class AuthorizedPaymentsProcessor {
|
|||
*/
|
||||
private $subscription_helper;
|
||||
|
||||
/**
|
||||
* The amount factory.
|
||||
*
|
||||
* @var AmountFactory
|
||||
*/
|
||||
private $amount_factory;
|
||||
|
||||
/**
|
||||
* The reauthorization failure reason.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $reauthorization_failure_reason = '';
|
||||
|
||||
/**
|
||||
* AuthorizedPaymentsProcessor constructor.
|
||||
*
|
||||
|
@ -100,6 +116,7 @@ class AuthorizedPaymentsProcessor {
|
|||
* @param AuthorizeOrderActionNotice $notice The notice.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param AmountFactory $amount_factory The amount factory.
|
||||
*/
|
||||
public function __construct(
|
||||
OrderEndpoint $order_endpoint,
|
||||
|
@ -107,7 +124,8 @@ class AuthorizedPaymentsProcessor {
|
|||
LoggerInterface $logger,
|
||||
AuthorizeOrderActionNotice $notice,
|
||||
ContainerInterface $config,
|
||||
SubscriptionHelper $subscription_helper
|
||||
SubscriptionHelper $subscription_helper,
|
||||
AmountFactory $amount_factory
|
||||
) {
|
||||
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
|
@ -116,6 +134,7 @@ class AuthorizedPaymentsProcessor {
|
|||
$this->notice = $notice;
|
||||
$this->config = $config;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->amount_factory = $amount_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,6 +268,67 @@ class AuthorizedPaymentsProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthorizes an authorized payment for an WooCommerce order.
|
||||
*
|
||||
* @param WC_Order $wc_order The WooCommerce order.
|
||||
*
|
||||
* @return string The status or reauthorization id.
|
||||
*/
|
||||
public function reauthorize_payment( WC_Order $wc_order ): string {
|
||||
$this->reauthorization_failure_reason = '';
|
||||
|
||||
try {
|
||||
$order = $this->paypal_order_from_wc_order( $wc_order );
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( 'Could not get PayPal order from WC order: ' . $exception->getMessage() );
|
||||
if ( $exception->getCode() === 404 ) {
|
||||
return self::NOT_FOUND;
|
||||
}
|
||||
return self::INACCESSIBLE;
|
||||
}
|
||||
|
||||
$amount = $this->amount_factory->from_wc_order( $wc_order );
|
||||
|
||||
$authorizations = $this->all_authorizations( $order );
|
||||
$uncaptured_authorizations = $this->authorizations_to_capture( ...$authorizations );
|
||||
|
||||
if ( ! $uncaptured_authorizations ) {
|
||||
if ( $this->captured_authorizations( ...$authorizations ) ) {
|
||||
$this->logger->info( 'Authorizations already captured.' );
|
||||
return self::ALREADY_CAPTURED;
|
||||
}
|
||||
|
||||
$this->logger->info( 'Bad authorization.' );
|
||||
return self::BAD_AUTHORIZATION;
|
||||
}
|
||||
|
||||
$authorization = end( $uncaptured_authorizations );
|
||||
|
||||
try {
|
||||
$this->payments_endpoint->reauthorize( $authorization->id(), new Money( $amount->value(), $amount->currency_code() ) );
|
||||
} catch ( PayPalApiException $exception ) {
|
||||
$this->reauthorization_failure_reason = $exception->details()[0]->description ?? null;
|
||||
$this->logger->error( 'Reauthorization failed: ' . $exception->name() . ' | ' . $this->reauthorization_failure_reason );
|
||||
return self::FAILED;
|
||||
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( 'Failed to capture authorization: ' . $exception->getMessage() );
|
||||
return self::FAILED;
|
||||
}
|
||||
|
||||
return self::SUCCESSFUL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The reason for a failed reauthorization.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function reauthorization_failure_reason(): string {
|
||||
return $this->reauthorization_failure_reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Voids authorizations for the given PayPal order.
|
||||
*
|
||||
|
@ -392,4 +472,5 @@ class AuthorizedPaymentsProcessor {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ trait CreditCardOrderInfoHandlingTrait {
|
|||
/**
|
||||
* Fired when the 3DS information is added to WC order.
|
||||
*/
|
||||
do_action( 'woocommerce_paypal_payments_thee_d_secure_added', $wc_order, $order );
|
||||
do_action( 'woocommerce_paypal_payments_three_d_secure_added', $wc_order, $order );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,8 +96,9 @@ trait CreditCardOrderInfoHandlingTrait {
|
|||
return;
|
||||
}
|
||||
|
||||
$fraud_responses = $fraud->to_array();
|
||||
$card_brand = $payment_source->properties()->brand ?? __( 'N/A', 'woocommerce-paypal-payments' );
|
||||
$fraud_responses = $fraud->to_array();
|
||||
$card_brand = $payment_source->properties()->brand ?? __( 'N/A', 'woocommerce-paypal-payments' );
|
||||
$card_last_digits = $payment_source->properties()->last_digits ?? __( 'N/A', 'woocommerce-paypal-payments' );
|
||||
|
||||
$avs_response_order_note_title = __( 'Address Verification Result', 'woocommerce-paypal-payments' );
|
||||
/* translators: %1$s is AVS order note title, %2$s is AVS order note result markup */
|
||||
|
@ -109,6 +110,7 @@ trait CreditCardOrderInfoHandlingTrait {
|
|||
<li>%3$s</li>
|
||||
</ul>
|
||||
<li>%4$s</li>
|
||||
<li>%5$s</li>
|
||||
</ul>';
|
||||
$avs_response_order_note_result = sprintf(
|
||||
$avs_response_order_note_result_format,
|
||||
|
@ -119,7 +121,9 @@ trait CreditCardOrderInfoHandlingTrait {
|
|||
/* translators: %s is fraud AVS postal match */
|
||||
sprintf( __( 'Postal Match: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['postal_match'] ) ),
|
||||
/* translators: %s is card brand */
|
||||
sprintf( __( 'Card Brand: %s', 'woocommerce-paypal-payments' ), esc_html( $card_brand ) )
|
||||
sprintf( __( 'Card Brand: %s', 'woocommerce-paypal-payments' ), esc_html( $card_brand ) ),
|
||||
/* translators: %s card last digits */
|
||||
sprintf( __( 'Card Last Digits: %s', 'woocommerce-paypal-payments' ), esc_html( $card_last_digits ) )
|
||||
);
|
||||
$avs_response_order_note = sprintf(
|
||||
$avs_response_order_note_format,
|
||||
|
@ -136,7 +140,13 @@ trait CreditCardOrderInfoHandlingTrait {
|
|||
);
|
||||
$wc_order->add_order_note( $cvv_response_order_note );
|
||||
|
||||
$meta_details = array_merge( $fraud_responses, array( 'card_brand' => $card_brand ) );
|
||||
$meta_details = array_merge(
|
||||
$fraud_responses,
|
||||
array(
|
||||
'card_brand' => $card_brand,
|
||||
'card_last_digits' => $card_last_digits,
|
||||
)
|
||||
);
|
||||
$wc_order->update_meta_data( PayPalGateway::FRAUD_RESULT_META_KEY, $meta_details );
|
||||
$wc_order->save_meta_data();
|
||||
|
||||
|
|
|
@ -45,6 +45,18 @@ trait OrderMetaTrait {
|
|||
$wc_order->update_meta_data( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY, $payment_source );
|
||||
}
|
||||
|
||||
$payer = $order->payer();
|
||||
if (
|
||||
$payer
|
||||
&& $payment_source
|
||||
&& in_array( $payment_source, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, true )
|
||||
) {
|
||||
$payer_email = $payer->email_address();
|
||||
if ( $payer_email ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email );
|
||||
}
|
||||
}
|
||||
|
||||
$wc_order->save();
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_woocommerce_order_created', $wc_order, $order );
|
||||
|
|
|
@ -65,7 +65,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
<a href="https://woo.com/document/woocommerce-paypal-payments/#paypal-card-processing-acdc" target="_blank"><img alt="American Express" src="' . esc_url( $module_url ) . 'assets/images/amex.svg"/></a>
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#paypal-card-processing-acdc" target="_blank"><img alt="Discover" src="' . esc_url( $module_url ) . 'assets/images/discover.svg"/></a>
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#alternative-payment-methods" target="_blank"><img alt="iDEAL" src="' . esc_url( $module_url ) . 'assets/images/ideal-dark.svg"/></a>
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#alternative-payment-methods" target="_blank"><img alt="Sofort" src="' . esc_url( $module_url ) . 'assets/images/sofort.svg"/></a>
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#alternative-payment-methods" target="_blank"><img alt="BLIK" src="' . esc_url( $module_url ) . 'assets/images/blik.svg"/></a>
|
||||
</div>
|
||||
<div class="ppcp-onboarding-header-apm-logos">
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#apple-pay" target="_blank"><img alt="Apple Pay" src="' . esc_url( $module_url ) . 'assets/images/button-Apple-Pay.png"/></a>
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
|
@ -447,6 +448,53 @@ class WCGatewayModule implements ModuleInterface {
|
|||
delete_transient( 'ppcp_reference_transaction_enabled' );
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Param types removed to avoid third-party issues.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
add_filter(
|
||||
'woocommerce_admin_billing_fields',
|
||||
function ( $fields ) {
|
||||
global $theorder;
|
||||
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_order_details_show_paypal_email', true ) ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
if ( ! is_array( $fields ) ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
if ( ! $theorder instanceof WC_Order ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$email = $theorder->get_meta( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY ) ?: '';
|
||||
|
||||
if ( ! $email ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
// Is payment source is paypal exclude all non paypal funding sources.
|
||||
$payment_source = $theorder->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) ?: '';
|
||||
$is_paypal_funding_source = ( strpos( $theorder->get_payment_method_title(), '(via PayPal)' ) === false );
|
||||
|
||||
if ( $payment_source === 'paypal' && ! $is_paypal_funding_source ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$fields['paypal_email'] = array(
|
||||
'label' => __( 'PayPal email address', 'woocommerce-paypal-payments' ),
|
||||
'value' => $email,
|
||||
'wrapper_class' => 'form-field-wide',
|
||||
'custom_attributes' => array( 'disabled' => 'disabled' ),
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -614,13 +662,18 @@ class WCGatewayModule implements ModuleInterface {
|
|||
return $order_actions;
|
||||
}
|
||||
|
||||
$render = $container->get( 'wcgateway.admin.render-authorize-action' );
|
||||
$render_reauthorize = $container->get( 'wcgateway.admin.render-reauthorize-action' );
|
||||
$render_authorize = $container->get( 'wcgateway.admin.render-authorize-action' );
|
||||
|
||||
/**
|
||||
* Renders the authorize action in the select field.
|
||||
*
|
||||
* @var RenderAuthorizeAction $render
|
||||
*/
|
||||
return $render->render( $order_actions, $theorder );
|
||||
return $render_reauthorize->render(
|
||||
$render_authorize->render( $order_actions, $theorder ),
|
||||
$theorder
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -637,6 +690,36 @@ class WCGatewayModule implements ModuleInterface {
|
|||
$authorized_payments_processor->capture_authorized_payment( $wc_order );
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_order_action_ppcp_reauthorize_order',
|
||||
static function ( WC_Order $wc_order ) use ( $container ) {
|
||||
$admin_notices = $container->get( 'admin-notices.repository' );
|
||||
assert( $admin_notices instanceof Repository );
|
||||
|
||||
/**
|
||||
* The authorized payments processor.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor $authorized_payments_processor
|
||||
*/
|
||||
$authorized_payments_processor = $container->get( 'wcgateway.processor.authorized-payments' );
|
||||
|
||||
if ( $authorized_payments_processor->reauthorize_payment( $wc_order ) !== AuthorizedPaymentsProcessor::SUCCESSFUL ) {
|
||||
$message = sprintf(
|
||||
'%1$s %2$s',
|
||||
esc_html__( 'Reauthorization with PayPal failed: ', 'woocommerce-paypal-payments' ),
|
||||
$authorized_payments_processor->reauthorization_failure_reason() ?: ''
|
||||
);
|
||||
$admin_notices->persist( new Message( $message, 'error' ) );
|
||||
} else {
|
||||
$admin_notices->persist( new Message( 'Payment reauthorized.', 'info' ) );
|
||||
|
||||
$wc_order->add_order_note(
|
||||
__( 'Payment reauthorized.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,7 +44,9 @@ return array(
|
|||
$authorized_payments_processor,
|
||||
$funding_source_renderer,
|
||||
$container->get( 'wc-subscriptions.helpers.real-time-account-updater' ),
|
||||
$container->get( 'wc-subscriptions.helper' )
|
||||
$container->get( 'wc-subscriptions.helper' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'vaulting.wc-payment-tokens' )
|
||||
);
|
||||
},
|
||||
'wc-subscriptions.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository {
|
||||
|
|
|
@ -9,10 +9,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcSubscriptions;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WC_Subscription;
|
||||
use WC_Payment_Tokens;
|
||||
use WC_Subscription;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
|
@ -25,8 +27,8 @@ use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
|||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenApplePay;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenPayPal;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenVenmo;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
|
@ -132,6 +134,20 @@ class RenewalHandler {
|
|||
*/
|
||||
private $subscription_helper;
|
||||
|
||||
/**
|
||||
* Payment tokens endpoint
|
||||
*
|
||||
* @var PaymentTokensEndpoint
|
||||
*/
|
||||
private $payment_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* WooCommerce payments tokens factory.
|
||||
*
|
||||
* @var WooCommercePaymentTokens
|
||||
*/
|
||||
private $wc_payment_tokens;
|
||||
|
||||
/**
|
||||
* RenewalHandler constructor.
|
||||
*
|
||||
|
@ -147,6 +163,8 @@ class RenewalHandler {
|
|||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param RealTimeAccountUpdaterHelper $real_time_account_updater_helper Real Time Account Updater helper.
|
||||
* @param SubscriptionHelper $subscription_helper Subscription helper.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param WooCommercePaymentTokens $wc_payment_tokens WooCommerce payments tokens factory.
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
|
@ -160,7 +178,9 @@ class RenewalHandler {
|
|||
AuthorizedPaymentsProcessor $authorized_payments_processor,
|
||||
FundingSourceRenderer $funding_source_renderer,
|
||||
RealTimeAccountUpdaterHelper $real_time_account_updater_helper,
|
||||
SubscriptionHelper $subscription_helper
|
||||
SubscriptionHelper $subscription_helper,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
WooCommercePaymentTokens $wc_payment_tokens
|
||||
) {
|
||||
|
||||
$this->logger = $logger;
|
||||
|
@ -175,6 +195,8 @@ class RenewalHandler {
|
|||
$this->funding_source_renderer = $funding_source_renderer;
|
||||
$this->real_time_account_updater_helper = $real_time_account_updater_helper;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
$this->wc_payment_tokens = $wc_payment_tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,8 +258,26 @@ class RenewalHandler {
|
|||
// Vault v3.
|
||||
$payment_source = null;
|
||||
if ( $wc_order->get_payment_method() === PayPalGateway::ID ) {
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $wc_order->get_customer_id(), PayPalGateway::ID );
|
||||
$customer_tokens = $this->wc_payment_tokens->customer_tokens( $user_id );
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, PayPalGateway::ID );
|
||||
|
||||
if ( $customer_tokens && empty( $wc_tokens ) ) {
|
||||
$this->wc_payment_tokens->create_wc_tokens( $customer_tokens, $user_id );
|
||||
}
|
||||
|
||||
$customer_token_ids = array();
|
||||
foreach ( $customer_tokens as $customer_token ) {
|
||||
$customer_token_ids[] = $customer_token['id'];
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, PayPalGateway::ID );
|
||||
foreach ( $wc_tokens as $token ) {
|
||||
if ( ! in_array( $token->get_token(), $customer_token_ids, true ) ) {
|
||||
$token->delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = 'paypal';
|
||||
$properties = array(
|
||||
'vault_id' => $token->get_token(),
|
||||
|
@ -270,7 +310,27 @@ class RenewalHandler {
|
|||
}
|
||||
|
||||
if ( $wc_order->get_payment_method() === CreditCardGateway::ID ) {
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $wc_order->get_customer_id(), CreditCardGateway::ID );
|
||||
$customer_tokens = $this->wc_payment_tokens->customer_tokens( $user_id );
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, CreditCardGateway::ID );
|
||||
|
||||
if ( $customer_tokens && empty( $wc_tokens ) ) {
|
||||
$this->wc_payment_tokens->create_wc_tokens( $customer_tokens, $user_id );
|
||||
}
|
||||
|
||||
$customer_token_ids = array();
|
||||
foreach ( $customer_tokens as $customer_token ) {
|
||||
$customer_token_ids[] = $customer_token['id'];
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, CreditCardGateway::ID );
|
||||
foreach ( $wc_tokens as $token ) {
|
||||
if ( ! in_array( $token->get_token(), $customer_token_ids, true ) ) {
|
||||
$token->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, CreditCardGateway::ID );
|
||||
$last_token = end( $wc_tokens );
|
||||
if ( $last_token ) {
|
||||
$payment_source = $this->card_payment_source( $last_token->get_token(), $wc_order );
|
||||
|
@ -295,7 +355,7 @@ class RenewalHandler {
|
|||
if ( $wc_order->get_payment_method() === CreditCardGateway::ID ) {
|
||||
$card_payment_source = $order->payment_source();
|
||||
if ( $card_payment_source ) {
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $wc_order->get_customer_id(), CreditCardGateway::ID );
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, CreditCardGateway::ID );
|
||||
$last_token = end( $wc_tokens );
|
||||
$expiry = $card_payment_source->properties()->expiry ?? '';
|
||||
$last_digits = $card_payment_source->properties()->last_digits ?? '';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "woocommerce-paypal-payments",
|
||||
"version": "2.5.4",
|
||||
"version": "2.6.1",
|
||||
"description": "WooCommerce PayPal Payments",
|
||||
"repository": "https://github.com/woocommerce/woocommerce-paypal-payments",
|
||||
"license": "GPL-2.0",
|
||||
|
|
39
readme.txt
39
readme.txt
|
@ -2,9 +2,9 @@
|
|||
Contributors: woocommerce, automattic, inpsyde
|
||||
Tags: woocommerce, paypal, payments, ecommerce, checkout, cart, pay later, apple pay, subscriptions, debit card, credit card, google pay
|
||||
Requires at least: 5.3
|
||||
Tested up to: 6.4
|
||||
Tested up to: 6.5
|
||||
Requires PHP: 7.2
|
||||
Stable tag: 2.5.4
|
||||
Stable tag: 2.6.1
|
||||
License: GPLv2
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
|
@ -179,6 +179,41 @@ If you encounter issues with the PayPal buttons not appearing after an update, p
|
|||
|
||||
== Changelog ==
|
||||
|
||||
= 2.6.1 - 2024-04-09 =
|
||||
* Fix - Payment tokens fixes and adjustments #2106
|
||||
* Fix - Pay upon Invoice: Add input validation to Experience Context fields #2092
|
||||
* Fix - Disable markup in get_plugin_data() returns to fix an issue with wptexturize() #2094
|
||||
* Fix - Problem changing the shipping option in block pages #2142
|
||||
* Fix - Saved payment token deleted after payment with another saved payment token #2146
|
||||
* Enhancement - Pay later messaging configurator improvements #2107
|
||||
* Enhancement - Replace the middleware URL from connect.woocommerce.com to api.woocommerce.com/integrations #2130
|
||||
* Enhancement - Remove all Sofort references as it has been deprecated #2124
|
||||
* Enhancement - Improve funding source names #2118
|
||||
* Enhancement - More fraud prevention capabilities by storing additional data in the order #2125
|
||||
* Enhancement - Update ACDC currency eligibility for AMEX #2129
|
||||
* Enhancement - Sync shipping options with Venmo when skipping final confirmation on Checkout #2108
|
||||
* Enhancement - Card Fields: Add a filter for the CVC field and update the placeholder to match the label #2089
|
||||
* Enhancement - Product Title: Sanitize before sending to PayPal #2090
|
||||
* Enhancement - Add filter for disabling permit_multiple_payment_tokens vault attribute #2136
|
||||
* Enhancement - Filter to hide PayPal email address not working on order detail #2137
|
||||
|
||||
= 2.6.0 - 2024-03-20 =
|
||||
* Fix - invoice_id not included in API call when creating payment with saved card #2086
|
||||
* Fix - Typo in SCA indicators for ACDC Vault transactions #2083
|
||||
* Fix - Payments with saved card tokens use Capture intent when Authorize is configured #2069
|
||||
* Fix - WooPayments multi-currency causing currency mismatch error on Block Cart & Checkout pages #2054
|
||||
* Fix - "Must pass createSubscription with intent=subscription" error with PayPal Subscriptions mode #2058
|
||||
* Fix - "Proceed to PayPal" button displayed for Free trial PayPal Subscription products when payment token is saved #2041
|
||||
* Fix - ACDC payments with new credit card may fail when debugging is enabled (JSON malformed by warning) #2051
|
||||
* Enhancement - Add Pay Later Messaging block #1897
|
||||
* Enhancement - Submit the form instead of refreshing the page to show the save notice #2081
|
||||
* Enhancement - Integrate pay later messaging block with the messaging configurator #2080
|
||||
* Enhancement - Reauthorize authorized payments #2062
|
||||
* Enhancement - Do not handle VAULT.PAYMENT-TOKEN.CREATED webhook for Vault v3 #2079
|
||||
* Enhancement - Improve the messaging configurator styles #2053
|
||||
* Enhancement - Ensure PayPal Vaulting is not selected as Subscriptions Mode when Reference Transactions are disabled #2057
|
||||
* Enhancement - Pay later messaging configurator & messaging block adjustments #2096
|
||||
|
||||
= 2.5.4 - 2024-02-27 =
|
||||
* Fix - Cannot enable Apple Pay when API credentials were manually created #2015
|
||||
* Fix - Cart simulation type error #1943
|
||||
|
|
|
@ -65,7 +65,7 @@ class FilePathPluginFactory implements FilePathPluginFactoryInterface {
|
|||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
$plugin_data = get_plugin_data( $filePath );
|
||||
$plugin_data = get_plugin_data( $filePath, false );
|
||||
if ( empty( $plugin_data ) ) {
|
||||
throw new UnexpectedValueException(
|
||||
sprintf(
|
||||
|
|
|
@ -312,11 +312,12 @@ class ItemFactoryTest extends TestCase
|
|||
|
||||
$result = $testee->from_wc_order($order);
|
||||
$item = current($result);
|
||||
|
||||
/**
|
||||
* @var Item $item
|
||||
*/
|
||||
$this->assertEquals(mb_substr($name, 0, 127), $item->name());
|
||||
$this->assertEquals(substr($description, 0, 127), $item->description());
|
||||
$this->assertEquals(substr( strip_shortcodes( wp_strip_all_tags( $name ) ), 0, 127 ), $item->name());
|
||||
$this->assertEquals(substr( strip_shortcodes( wp_strip_all_tags( $description ) ), 0, 127 ), $item->description());
|
||||
}
|
||||
|
||||
public function testFromPayPalResponse()
|
||||
|
|
|
@ -92,6 +92,8 @@ class VaultedCreditCardHandlerTest extends TestCase
|
|||
$customer = Mockery::mock(WC_Customer::class);
|
||||
|
||||
$payer = Mockery::mock(Payer::class);
|
||||
$payer->shouldReceive('email_address');
|
||||
|
||||
$this->payerFactory->shouldReceive('from_wc_order')
|
||||
->andReturn($payer);
|
||||
$this->shippingPreferenceFactory->shouldReceive('from_state')
|
||||
|
@ -100,6 +102,7 @@ class VaultedCreditCardHandlerTest extends TestCase
|
|||
$order = Mockery::mock(Order::class);
|
||||
$order->shouldReceive('id')->andReturn('1');
|
||||
$order->shouldReceive('intent')->andReturn('CAPTURE');
|
||||
$order->shouldReceive('payer')->andReturn($payer);
|
||||
|
||||
$paymentSource = Mockery::mock(PaymentSource::class);
|
||||
$paymentSource->shouldReceive('name')->andReturn('card');
|
||||
|
|
|
@ -4,21 +4,23 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Mockery;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\VaultedCreditCardHandler;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use function Brain\Monkey\Functions\when;
|
||||
|
||||
class CreditCardGatewayTest extends TestCase
|
||||
|
@ -34,6 +36,8 @@ class CreditCardGatewayTest extends TestCase
|
|||
private $subscriptionHelper;
|
||||
private $captureCardPayment;
|
||||
private $prefix;
|
||||
private $paymentTokensEndpoint;
|
||||
private $wcPaymentTokens;
|
||||
private $logger;
|
||||
private $paymentsEndpoint;
|
||||
private $vaultedCreditCardHandler;
|
||||
|
@ -56,6 +60,8 @@ class CreditCardGatewayTest extends TestCase
|
|||
$this->subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||
$this->captureCardPayment = Mockery::mock(CaptureCardPayment::class);
|
||||
$this->prefix = 'some-prefix';
|
||||
$this->paymentTokensEndpoint = Mockery::mock(PaymentTokensEndpoint::class);
|
||||
$this->wcPaymentTokens = Mockery::mock(WooCommercePaymentTokens::class);
|
||||
$this->logger = Mockery::mock(LoggerInterface::class);
|
||||
$this->paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$this->vaultedCreditCardHandler = Mockery::mock(VaultedCreditCardHandler::class);
|
||||
|
@ -84,6 +90,8 @@ class CreditCardGatewayTest extends TestCase
|
|||
$this->orderEndpoint,
|
||||
$this->captureCardPayment,
|
||||
$this->prefix,
|
||||
$this->paymentTokensEndpoint,
|
||||
$this->wcPaymentTokens,
|
||||
$this->logger
|
||||
);
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ private $testee;
|
|||
$order->shouldReceive('id')->andReturn('1');
|
||||
$order->shouldReceive('intent');
|
||||
$order->shouldReceive('payment_source');
|
||||
$order->shouldReceive('payer');
|
||||
|
||||
$this->orderEndpoint
|
||||
->shouldReceive('create')
|
||||
|
|
|
@ -6,11 +6,13 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
|||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
|
@ -44,6 +46,9 @@ class WcGatewayTest extends TestCase
|
|||
private $logger;
|
||||
private $apiShopCountry;
|
||||
private $orderEndpoint;
|
||||
private $paymentTokensEndpoint;
|
||||
private $vaultV3Enabled;
|
||||
private $wcPaymentTokens;
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
|
@ -88,6 +93,10 @@ class WcGatewayTest extends TestCase
|
|||
|
||||
$this->logger->shouldReceive('info');
|
||||
$this->logger->shouldReceive('error');
|
||||
|
||||
$this->paymentTokensEndpoint = Mockery::mock(PaymentTokensEndpoint::class);
|
||||
$this->vaultV3Enabled = true;
|
||||
$this->wcPaymentTokens = Mockery::mock(WooCommercePaymentTokens::class);
|
||||
}
|
||||
|
||||
private function createGateway()
|
||||
|
@ -111,7 +120,10 @@ class WcGatewayTest extends TestCase
|
|||
function ($id) {
|
||||
return 'checkoutnow=' . $id;
|
||||
},
|
||||
'Pay via PayPal'
|
||||
'Pay via PayPal',
|
||||
$this->paymentTokensEndpoint,
|
||||
$this->vaultV3Enabled,
|
||||
$this->wcPaymentTokens
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
|
|||
|
||||
|
||||
use Mockery\MockInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\AmountFactory;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
use WC_Order;
|
||||
|
@ -69,6 +70,7 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
|||
|
||||
$this->config = Mockery::mock(ContainerInterface::class);
|
||||
$this->subscription_helper = Mockery::mock(SubscriptionHelper::class);
|
||||
$this->amount_factory = Mockery::mock(AmountFactory::class);
|
||||
|
||||
$this->testee = new AuthorizedPaymentsProcessor(
|
||||
$this->orderEndpoint,
|
||||
|
@ -76,7 +78,8 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
|||
new NullLogger(),
|
||||
$this->notice,
|
||||
$this->config,
|
||||
$this->subscription_helper
|
||||
$this->subscription_helper,
|
||||
$this->amount_factory
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ class OrderProcessorTest extends TestCase
|
|||
$currentOrder
|
||||
->shouldReceive('payment_source')
|
||||
->andReturn(null);
|
||||
$currentOrder->shouldReceive('payer');
|
||||
|
||||
$wcOrder
|
||||
->shouldReceive('get_meta')
|
||||
|
@ -230,6 +231,7 @@ class OrderProcessorTest extends TestCase
|
|||
$currentOrder
|
||||
->shouldReceive('payment_source')
|
||||
->andReturn(null);
|
||||
$currentOrder->shouldReceive('payer');
|
||||
|
||||
$wcOrder
|
||||
->shouldReceive('get_meta')
|
||||
|
@ -357,6 +359,7 @@ class OrderProcessorTest extends TestCase
|
|||
$currentOrder
|
||||
->shouldReceive('purchase_units')
|
||||
->andReturn([$purchaseUnit]);
|
||||
$currentOrder->shouldReceive('payer');
|
||||
|
||||
$wcOrder
|
||||
->shouldReceive('get_meta')
|
||||
|
|
|
@ -13,7 +13,7 @@ PRODUCT_ID=123
|
|||
|
||||
SUBSCRIPTION_URL="/product/sub"
|
||||
|
||||
APM_ID="sofort"
|
||||
APM_ID="paypal"
|
||||
|
||||
WP_MERCHANT_USER="admin"
|
||||
WP_MERCHANT_PASSWORD="admin"
|
||||
|
|
|
@ -37,6 +37,53 @@ test('Save during purchase', async ({page}) => {
|
|||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
|
||||
test('PayPal add payment method', async ({page}) => {
|
||||
await loginAsCustomer(page);
|
||||
await page.goto('/my-account/add-payment-method');
|
||||
|
||||
const popup = await openPaypalPopup(page);
|
||||
await loginIntoPaypal(popup);
|
||||
popup.locator('#consentButton').click();
|
||||
|
||||
await page.waitForURL('/my-account/payment-methods');
|
||||
});
|
||||
|
||||
test('ACDC add payment method', async ({page}) => {
|
||||
await loginAsCustomer(page);
|
||||
await page.goto('/my-account/add-payment-method');
|
||||
|
||||
await page.click("text=Debit & Credit Cards");
|
||||
|
||||
const creditCardNumber = await page.frameLocator('[title="paypal_card_number_field"]').locator('.card-field-number');
|
||||
await creditCardNumber.fill('4005519200000004');
|
||||
|
||||
const expirationDate = await page.frameLocator('[title="paypal_card_expiry_field"]').locator('.card-field-expiry');
|
||||
await expirationDate.fill('01/25');
|
||||
|
||||
const cvv = await page.frameLocator('[title="paypal_card_cvv_field"]').locator('.card-field-cvv');
|
||||
await cvv.fill('123');
|
||||
|
||||
await page.waitForURL('/my-account/payment-methods');
|
||||
});
|
||||
|
||||
test('PayPal logged-in user free trial subscription without payment token', async ({page}) => {
|
||||
await loginAsCustomer(page);
|
||||
|
||||
await page.goto('/shop');
|
||||
await page.click("text=Sign up now");
|
||||
await page.goto('/classic-checkout');
|
||||
|
||||
const popup = await openPaypalPopup(page);
|
||||
await loginIntoPaypal(popup);
|
||||
popup.locator('#consentButton').click();
|
||||
|
||||
await page.click("text=Proceed to PayPal");
|
||||
|
||||
const title = await page.locator('.entry-title');
|
||||
await expect(title).toHaveText('Order received');
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
* Plugin Name: WooCommerce PayPal Payments
|
||||
* Plugin URI: https://woocommerce.com/products/woocommerce-paypal-payments/
|
||||
* Description: PayPal's latest complete payments processing solution. Accept PayPal, Pay Later, credit/debit cards, alternative digital wallets local payment types and bank accounts. Turn on only PayPal options or process a full suite of payment methods. Enable global transaction with extensive currency and country coverage.
|
||||
* Version: 2.5.4
|
||||
* Version: 2.6.1
|
||||
* Author: WooCommerce
|
||||
* Author URI: https://woocommerce.com/
|
||||
* License: GPL-2.0
|
||||
* Requires PHP: 7.2
|
||||
* Requires Plugins: woocommerce
|
||||
* WC requires at least: 3.9
|
||||
* WC tested up to: 8.6
|
||||
* WC tested up to: 8.7
|
||||
* Text Domain: woocommerce-paypal-payments
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce
|
||||
|
@ -25,14 +26,14 @@ define( 'PAYPAL_API_URL', 'https://api-m.paypal.com' );
|
|||
define( 'PAYPAL_URL', 'https://www.paypal.com' );
|
||||
define( 'PAYPAL_SANDBOX_API_URL', 'https://api-m.sandbox.paypal.com' );
|
||||
define( 'PAYPAL_SANDBOX_URL', 'https://www.sandbox.paypal.com' );
|
||||
define( 'PAYPAL_INTEGRATION_DATE', '2024-02-16' );
|
||||
define( 'PAYPAL_INTEGRATION_DATE', '2024-04-03' );
|
||||
|
||||
! defined( 'CONNECT_WOO_CLIENT_ID' ) && define( 'CONNECT_WOO_CLIENT_ID', 'AcCAsWta_JTL__OfpjspNyH7c1GGHH332fLwonA5CwX4Y10mhybRZmHLA0GdRbwKwjQIhpDQy0pluX_P' );
|
||||
! defined( 'CONNECT_WOO_SANDBOX_CLIENT_ID' ) && define( 'CONNECT_WOO_SANDBOX_CLIENT_ID', 'AYmOHbt1VHg-OZ_oihPdzKEVbU3qg0qXonBcAztuzniQRaKE0w1Hr762cSFwd4n8wxOl-TCWohEa0XM_' );
|
||||
! defined( 'CONNECT_WOO_MERCHANT_ID' ) && define( 'CONNECT_WOO_MERCHANT_ID', 'K8SKZ36LQBWXJ' );
|
||||
! defined( 'CONNECT_WOO_SANDBOX_MERCHANT_ID' ) && define( 'CONNECT_WOO_SANDBOX_MERCHANT_ID', 'MPMFHQTVMBZ6G' );
|
||||
! defined( 'CONNECT_WOO_URL' ) && define( 'CONNECT_WOO_URL', 'https://connect.woocommerce.com/ppc' );
|
||||
! defined( 'CONNECT_WOO_SANDBOX_URL' ) && define( 'CONNECT_WOO_SANDBOX_URL', 'https://connect.woocommerce.com/ppcsandbox' );
|
||||
! defined( 'CONNECT_WOO_URL' ) && define( 'CONNECT_WOO_URL', 'https://api.woocommerce.com/integrations/ppc' );
|
||||
! defined( 'CONNECT_WOO_SANDBOX_URL' ) && define( 'CONNECT_WOO_SANDBOX_URL', 'https://api.woocommerce.com/integrations/ppcsandbox' );
|
||||
|
||||
( function () {
|
||||
$autoload_filepath = __DIR__ . '/vendor/autoload.php';
|
||||
|
@ -97,7 +98,7 @@ define( 'PAYPAL_INTEGRATION_DATE', '2024-02-16' );
|
|||
*/
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
$plugin_data = get_plugin_data( __DIR__ . '/woocommerce-paypal-payments.php' );
|
||||
$plugin_data = get_plugin_data( __DIR__ . '/woocommerce-paypal-payments.php', false );
|
||||
$plugin_version = $plugin_data['Version'] ?? null;
|
||||
$installed_plugin_version = get_option( 'woocommerce-ppcp-version' );
|
||||
if ( $installed_plugin_version !== $plugin_version ) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue