mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-01 07:02:48 +08:00
Merge branch 'trunk' into PCP-1393-update-to-vault-v-3
This commit is contained in:
commit
cfa107b588
89 changed files with 2220 additions and 2907 deletions
|
@ -11,6 +11,9 @@ if (!defined('MONTH_IN_SECONDS')) {
|
|||
if (!defined('HOUR_IN_SECONDS')) {
|
||||
define('HOUR_IN_SECONDS', 60 * MINUTE_IN_SECONDS);
|
||||
}
|
||||
if (!defined('MINUTE_IN_SECONDS')) {
|
||||
define( 'MINUTE_IN_SECONDS', 60 );
|
||||
}
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
define('ABSPATH', '');
|
||||
|
@ -32,6 +35,17 @@ if (!defined('ABSPATH')) {
|
|||
*
|
||||
* @return string|null The scheduled action ID if a scheduled action was found, or null if no matching action found.
|
||||
*/
|
||||
function as_unschedule_action($hook, $args = array(), $group = '')
|
||||
{
|
||||
}
|
||||
function as_unschedule_action($hook, $args = array(), $group = '') {}
|
||||
|
||||
/**
|
||||
* Schedule an action to run one time
|
||||
*
|
||||
* @param int $timestamp When the job will run.
|
||||
* @param string $hook The hook to trigger.
|
||||
* @param array $args Arguments to pass when the hook triggers.
|
||||
* @param string $group The group to assign this job to.
|
||||
* @param bool $unique Whether the action should be unique.
|
||||
*
|
||||
* @return int The action ID.
|
||||
*/
|
||||
function as_schedule_single_action( $timestamp, $hook, $args = array(), $group = '', $unique = false ) {}
|
||||
|
|
|
@ -2107,3 +2107,16 @@ function wc_get_page_screen_id( $for ) {}
|
|||
*
|
||||
*/
|
||||
class WC_Product_Subscription_Variation extends WC_Product_Variation {}
|
||||
|
||||
/**
|
||||
* Variable Subscription Product Class
|
||||
*
|
||||
* This class extends the WC Variable product class to create variable products with recurring payments.
|
||||
*
|
||||
* @class WC_Product_Variable_Subscription
|
||||
* @package WooCommerce Subscriptions
|
||||
* @category Class
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3
|
||||
*
|
||||
*/
|
||||
class WC_Product_Variable_Subscription extends WC_Product_Variable {}
|
||||
|
|
|
@ -1,12 +1,23 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 2.3.0 - XXXX-XX-XX =
|
||||
= 2.3.1 - 2023-09-26 =
|
||||
* Fix - Fatal error when saving product while WooCommerce Subscriptions plugin is not active #1731
|
||||
* Fix - Validate tracking data only for add/update Package Tracking #1729
|
||||
* Fix - Disable Package Tracking for order if transaction ID doesn't exist #1727
|
||||
|
||||
= 2.3.0 - 2023-09-26 =
|
||||
* Fix - Plus sign in PayPal account email address gets converted to space #771
|
||||
* Fix - Payment method dropdown option label on edit order screen for ppcp-gateway option displaying wrong name #1639
|
||||
* Fix - WooCommerce Bookings products don't remain in Cart as a guest when PayPal button active on single product #1645
|
||||
* Fix - Since version > 2.2.0 the PayPal Checkout button on single product pages does not redirect anymore #1664
|
||||
* Fix - PayPal fee and PayPal Payout do not change on order if we do partial refund #1578
|
||||
* Fix - Order does not contain intent error when using ACDC payment token while buyer is not present #1506
|
||||
* Fix - Error when product description linked with a PayPal subscription exceeds 127 characters #1700
|
||||
* Fix - $_POST uses the wrong key to hold the shipping method #1652
|
||||
* Fix - WC Payment Token created multiple times when webhook is received #1663
|
||||
* Fix - Subtotal mismatch line name shows on Account settings page when merchant is disconnected #1702
|
||||
* Fix - Warning prevents payments on Pay for Order page when debugging is enabled #1703
|
||||
* Fix - paypal-overlay-uid_ blocks page after closing PayPal popup on Pay for Order page | Terms checkbox validation fails on Pay for Order page #1704
|
||||
* Enhancement - Add support for HPOS for tracking module #1676
|
||||
* Enhancement - Billing agreements endpoint called too frequently for Reference Transactions check #1646
|
||||
* Enhancement - Do not declare subscription support for PayPal when only ACDC vaulting #1669
|
||||
|
@ -21,6 +32,20 @@
|
|||
* Enhancement - Compatibility with WooCommerce Product Add-Ons plugin #1586
|
||||
* Enhancement - Remove "no shipment" message after adding tracking #1674
|
||||
* Enhancement - Improve error & success validation messages #1675
|
||||
* Enhancement - Compatibility with third-party "Product Add-Ons" plugins #1601
|
||||
* Enhancement - PayPal logo flashes when switching between tabs #1345
|
||||
* Enhancement - Include url & image_url in create order call #1649
|
||||
* Enhancement - Include item_url & image_url to tracking call #1712
|
||||
* Enhancement - Update strings for tracking metabox #1714
|
||||
* Enhancement - Validate email address API credentials field #1691
|
||||
* Enhancement - Set payment method title for order edit page only if our gateway #1661
|
||||
* Enhancement - Fix missing Pay Later messages in cart + refactoring #1683
|
||||
* Enhancement - Product page PP button keep loading popup - "wc_add_to_cart_params is not defined" error in WooCommerce #1655
|
||||
* Enhancement - Remove PayPal Subscriptions API feature flag #1690
|
||||
* Enhancement - Don't send image_url when it is empty #1678
|
||||
* Enhancement - Subscription support depending on Vaulting setting instead of subscription mode setting #1697
|
||||
* Enhancement - Wrong PayPal subscription id on vaulted subscriptions #1699
|
||||
* Enhancement - Remove payment vaulted checker functionality (2030) #1711
|
||||
* Feature preview - Apple Pay integration #1514
|
||||
* Feature preview - Google Pay integration #1654
|
||||
|
||||
|
|
|
@ -44,5 +44,13 @@ return function ( string $root_dir ): iterable {
|
|||
$modules[] = ( require "$modules_dir/ppcp-googlepay/module.php" )();
|
||||
}
|
||||
|
||||
if ( apply_filters(
|
||||
//phpcs:disable WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
'woocommerce.deprecated_flags.woocommerce_paypal_payments.saved_payment_checker_enabled',
|
||||
getenv( 'PCP_SAVED_PAYMENT_CHECKER_ENABLED' ) === '1'
|
||||
) ) {
|
||||
$modules[] = ( require "$modules_dir/ppcp-saved-payment-checker/module.php" )();
|
||||
}
|
||||
|
||||
return $modules;
|
||||
};
|
||||
|
|
|
@ -50,7 +50,7 @@ class ApiModule implements ModuleInterface {
|
|||
foreach ( $data['purchase_units'] as $purchase_unit_index => $purchase_unit ) {
|
||||
foreach ( $purchase_unit['items'] as $item_index => $item ) {
|
||||
$data['purchase_units'][ $purchase_unit_index ]['items'][ $item_index ]['name'] =
|
||||
apply_filters( 'woocommerce_paypal_payments_cart_line_item_name', $item['name'], $item['cart_item_key'] );
|
||||
apply_filters( 'woocommerce_paypal_payments_cart_line_item_name', $item['name'], $item['cart_item_key'] ?? null );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,13 +83,10 @@ class CatalogProducts {
|
|||
*/
|
||||
public function create( string $name, string $description ): Product {
|
||||
$data = array(
|
||||
'name' => $name,
|
||||
'name' => $name,
|
||||
'description' => $description ?: $name,
|
||||
);
|
||||
|
||||
if ( $description ) {
|
||||
$data['description'] = $description;
|
||||
}
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/catalogs/products';
|
||||
$args = array(
|
||||
|
|
|
@ -194,7 +194,7 @@ class OrderEndpoint {
|
|||
): Order {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$data = array(
|
||||
'intent' => ( $this->subscription_helper->cart_contains_subscription() || $this->subscription_helper->current_product_is_subscription() ) ? 'AUTHORIZE' : $this->intent,
|
||||
'intent' => apply_filters( 'woocommerce_paypal_payments_order_intent', $this->intent ),
|
||||
'purchase_units' => array_map(
|
||||
static function ( PurchaseUnit $item ) use ( $shipping_preference ): array {
|
||||
$data = $item->to_array();
|
||||
|
|
|
@ -214,7 +214,7 @@ class Item {
|
|||
* @return string
|
||||
*/
|
||||
public function image_url():string {
|
||||
return $this->image_url;
|
||||
return $this->validate_image_url() ? $this->image_url : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -269,4 +269,14 @@ class Item {
|
|||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the image url for PayPal request.
|
||||
*
|
||||
* @return bool true if valid, otherwise false.
|
||||
*/
|
||||
protected function validate_image_url(): bool {
|
||||
$pattern = '/^(https:)([\/|\.|\w|\s|-])*\.(?:jpg|gif|png|jpeg|JPG|GIF|PNG|JPEG)$/';
|
||||
return (bool) preg_match( $pattern, $this->image_url );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,11 +13,15 @@ use WC_Product;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ItemTrait;
|
||||
|
||||
/**
|
||||
* Class ItemFactory
|
||||
*/
|
||||
class ItemFactory {
|
||||
|
||||
use ItemTrait;
|
||||
|
||||
/**
|
||||
* 3-letter currency code of the shop.
|
||||
*
|
||||
|
@ -211,15 +215,4 @@ class ItemFactory {
|
|||
$image_url
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanups the description and prepares it for sending to PayPal.
|
||||
*
|
||||
* @param string $description Item description.
|
||||
* @return string
|
||||
*/
|
||||
protected function prepare_description( string $description ): string {
|
||||
$description = strip_shortcodes( wp_strip_all_tags( $description ) );
|
||||
return substr( $description, 0, 127 ) ?: '';
|
||||
}
|
||||
}
|
||||
|
|
24
modules/ppcp-api-client/src/Helper/ItemTrait.php
Normal file
24
modules/ppcp-api-client/src/Helper/ItemTrait.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* PayPal item helper.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
||||
|
||||
trait ItemTrait {
|
||||
|
||||
/**
|
||||
* Cleanups the description and prepares it for sending to PayPal.
|
||||
*
|
||||
* @param string $description Item description.
|
||||
* @return string
|
||||
*/
|
||||
protected function prepare_description( string $description ): string {
|
||||
$description = strip_shortcodes( wp_strip_all_tags( $description ) );
|
||||
return substr( $description, 0, 127 ) ?: '';
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Applepay;
|
|||
use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
|
||||
|
||||
return array(
|
||||
|
@ -23,12 +24,55 @@ return array(
|
|||
|
||||
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) );
|
||||
};
|
||||
$display_manager = $container->get( 'wcgateway.display-manager' );
|
||||
assert( $display_manager instanceof DisplayManager );
|
||||
|
||||
if ( ! $container->has( 'applepay.eligible' ) || ! $container->get( 'applepay.eligible' ) ) {
|
||||
$connection_url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=ppcp-connection#field-credentials_feature_onboarding_heading' );
|
||||
$connection_link = '<a href="' . $connection_url . '" target="_blank">';
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'allow_card_button_gateway',
|
||||
array(
|
||||
'applepay_button_enabled' => array(
|
||||
'title' => __( 'Apple Pay Button', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'class' => array( 'ppcp-grayed-out-text' ),
|
||||
'input_class' => array( 'ppcp-disabled-checkbox' ),
|
||||
'label' => __( 'Enable Apple Pay button', 'woocommerce-paypal-payments' )
|
||||
. '<p class="description">'
|
||||
. sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Your PayPal account %1$srequires additional permissions%2$s to enable Apple Pay.', 'woocommerce-paypal-payments' ),
|
||||
$connection_link,
|
||||
'</a>'
|
||||
)
|
||||
. '</p>',
|
||||
'default' => 'yes',
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_element( 'applepay_button_enabled', '1' )
|
||||
->action_enable( 'applepay_button_enabled' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'allow_card_button_gateway',
|
||||
array(
|
||||
'applepay_button_enabled' => array(
|
||||
'applepay_button_enabled' => array(
|
||||
'title' => __( 'Apple Pay Button', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable Apple Pay button', 'woocommerce-paypal-payments' )
|
||||
|
@ -45,40 +89,20 @@ return array(
|
|||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-handlers' => wp_json_encode(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
array(
|
||||
'handler' => 'SubElementsHandler',
|
||||
'options' => array(
|
||||
'values' => array( '1' ),
|
||||
'elements' => array( '#field-applepay_sandbox_validation_file', '#field-applepay_live_validation_file', '#field-applepay_button_color', '#field-applepay_button_type', '#field-applepay_button_language' ),
|
||||
),
|
||||
),
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_element( 'applepay_button_enabled', '1' )
|
||||
->action_visible( 'applepay_button_color' )
|
||||
->action_visible( 'applepay_button_type' )
|
||||
->action_visible( 'applepay_button_language' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
'applepay_live_validation_file' => array(
|
||||
'title' => __( 'Apple Pay Live Validation File', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Paste here the validation file content', 'woocommerce-paypal-payments' ),
|
||||
'default' => null,
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_sandbox_validation_file' => array(
|
||||
'title' => __( 'Apple Pay Sandbox Validation File', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Paste here the validation file content', 'woocommerce-paypal-payments' ),
|
||||
'default' => null,
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_button_type' => array(
|
||||
'applepay_button_type' => array(
|
||||
'title' => str_repeat( ' ', 6 ) . __( 'Button Label', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'desc_tip' => true,
|
||||
|
@ -94,7 +118,7 @@ return array(
|
|||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_button_color' => array(
|
||||
'applepay_button_color' => array(
|
||||
'title' => str_repeat( ' ', 6 ) . __( 'Button Color', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'desc_tip' => true,
|
||||
|
@ -111,7 +135,7 @@ return array(
|
|||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_button_language' => array(
|
||||
'applepay_button_language' => array(
|
||||
'title' => str_repeat( ' ', 6 ) . __( 'Button Language', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'desc_tip' => true,
|
||||
|
|
|
@ -2,6 +2,8 @@ import ContextHandlerFactory from "./Context/ContextHandlerFactory";
|
|||
import {createAppleErrors} from "./Helper/applePayError";
|
||||
import {setVisible} from '../../../ppcp-button/resources/js/modules/Helper/Hiding';
|
||||
import {setEnabled} from '../../../ppcp-button/resources/js/modules/Helper/ButtonDisabler';
|
||||
import FormValidator from "../../../ppcp-button/resources/js/modules/Helper/FormValidator";
|
||||
import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler';
|
||||
|
||||
class ApplepayButton {
|
||||
|
||||
|
@ -13,6 +15,7 @@ class ApplepayButton {
|
|||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
this.paymentsClient = null;
|
||||
this.form_saved = false;
|
||||
|
||||
this.contextHandler = ContextHandlerFactory.create(
|
||||
this.context,
|
||||
|
@ -42,14 +45,14 @@ class ApplepayButton {
|
|||
if (isEligible) {
|
||||
this.fetchTransactionInfo().then(() => {
|
||||
const isSubscriptionProduct = this.ppcpConfig.data_client_id.has_subscriptions === true;
|
||||
if(isSubscriptionProduct) {
|
||||
if (isSubscriptionProduct) {
|
||||
return;
|
||||
}
|
||||
this.addButton();
|
||||
const id_minicart = "#apple-" + this.buttonConfig.button.mini_cart_wrapper;
|
||||
const id = "#apple-" + this.buttonConfig.button.wrapper;
|
||||
|
||||
if(this.context === 'mini-cart') {
|
||||
if (this.context === 'mini-cart') {
|
||||
document.querySelector(id_minicart).addEventListener('click', (evt) => {
|
||||
evt.preventDefault();
|
||||
this.onButtonClick();
|
||||
|
@ -60,10 +63,13 @@ class ApplepayButton {
|
|||
this.onButtonClick();
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for changes on any input within the WooCommerce checkout form
|
||||
jQuery('form.checkout').on('change', 'input, select, textarea', () => {
|
||||
this.fetchTransactionInfo();
|
||||
});
|
||||
});
|
||||
}
|
||||
console.log('[ApplePayButton] init done', this.buttonConfig.ajax_url);
|
||||
|
||||
}
|
||||
async fetchTransactionInfo() {
|
||||
this.transactionInfo = await this.contextHandler.transactionInfo();
|
||||
|
@ -94,11 +100,12 @@ class ApplepayButton {
|
|||
}
|
||||
initEventHandlers() {
|
||||
const { wrapper, ppcpButtonWrapper } = this.contextConfig();
|
||||
const wrapper_id = '#' + wrapper;
|
||||
|
||||
const syncButtonVisibility = () => {
|
||||
const $ppcpButtonWrapper = jQuery(ppcpButtonWrapper);
|
||||
setVisible(wrapper, $ppcpButtonWrapper.is(':visible'));
|
||||
setEnabled(wrapper, !$ppcpButtonWrapper.hasClass('ppcp-disabled'));
|
||||
setVisible(wrapper_id, $ppcpButtonWrapper.is(':visible'));
|
||||
setEnabled(wrapper_id, !$ppcpButtonWrapper.hasClass('ppcp-disabled'));
|
||||
}
|
||||
|
||||
jQuery(document).on('ppcp-shown ppcp-hidden ppcp-enabled ppcp-disabled', (ev, data) => {
|
||||
|
@ -120,6 +127,7 @@ class ApplepayButton {
|
|||
}
|
||||
session.onvalidatemerchant = this.onvalidatemerchant(session);
|
||||
session.onpaymentauthorized = this.onpaymentauthorized(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
|
@ -129,19 +137,15 @@ class ApplepayButton {
|
|||
* Add a Apple Pay purchase button
|
||||
*/
|
||||
addButton() {
|
||||
console.log('[ApplePayButton] context', this.context);
|
||||
const wrapper =
|
||||
(this.context === 'mini-cart')
|
||||
? this.buttonConfig.button.mini_cart_wrapper
|
||||
: this.buttonConfig.button.wrapper;
|
||||
console.log('[ApplePayButton] wrapper', wrapper)
|
||||
const shape =
|
||||
(this.context === 'mini-cart')
|
||||
? this.ppcpConfig.button.mini_cart_style.shape
|
||||
: this.ppcpConfig.button.style.shape;
|
||||
const appleContainer = this.context === 'mini-cart' ? document.getElementById("applepay-container-minicart") : document.getElementById("applepay-container");
|
||||
console.log('[ApplePayButton] shape', shape)
|
||||
console.log('[ApplePayButton] container', appleContainer)
|
||||
const type = this.buttonConfig.button.type;
|
||||
const language = this.buttonConfig.button.lang;
|
||||
const color = this.buttonConfig.button.color;
|
||||
|
@ -150,7 +154,6 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
|
||||
jQuery('#' + wrapper).addClass('ppcp-button-' + shape);
|
||||
jQuery(wrapper).append(appleContainer);
|
||||
console.log('[ApplePayButton] addButton', wrapper, appleContainer);
|
||||
}
|
||||
|
||||
//------------------------
|
||||
|
@ -160,13 +163,58 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
/**
|
||||
* Show Apple Pay payment sheet when Apple Pay payment button is clicked
|
||||
*/
|
||||
onButtonClick() {
|
||||
async onButtonClick() {
|
||||
const paymentDataRequest = this.paymentDataRequest();
|
||||
console.log('[ApplePayButton] onButtonClick: paymentDataRequest', paymentDataRequest, this.context);
|
||||
|
||||
// trigger woocommerce validation if we are in the checkout page
|
||||
if (this.context === 'checkout') {
|
||||
const checkoutFormSelector = 'form.woocommerce-checkout';
|
||||
const errorHandler = new ErrorHandler(
|
||||
PayPalCommerceGateway.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
);
|
||||
try {
|
||||
const formData = new FormData(document.querySelector(checkoutFormSelector));
|
||||
this.form_saved = Object.fromEntries(formData.entries());
|
||||
this.update_request_data_with_form(paymentDataRequest);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
const session = this.applePaySession(paymentDataRequest)
|
||||
console.log("session", session)
|
||||
const formValidator = PayPalCommerceGateway.early_checkout_validation_enabled ?
|
||||
new FormValidator(
|
||||
PayPalCommerceGateway.ajax.validate_checkout.endpoint,
|
||||
PayPalCommerceGateway.ajax.validate_checkout.nonce,
|
||||
) : null;
|
||||
if (formValidator) {
|
||||
try {
|
||||
const errors = await formValidator.validate(document.querySelector(checkoutFormSelector));
|
||||
if (errors.length > 0) {
|
||||
errorHandler.messages(errors);
|
||||
// fire WC event for other plugins
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ errorHandler.currentHtml() ] );
|
||||
// stop Apple Pay payment sheet from showing
|
||||
session.abort();
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.applePaySession(paymentDataRequest)
|
||||
}
|
||||
|
||||
update_request_data_with_form(paymentDataRequest) {
|
||||
paymentDataRequest.billingContact = this.fill_billing_contact(this.form_saved);
|
||||
paymentDataRequest.applicationData = this.fill_application_data(this.form_saved);
|
||||
if (!this.buttonConfig.product.needShipping) {
|
||||
return;
|
||||
}
|
||||
paymentDataRequest.shippingContact = this.fill_shipping_contact(this.form_saved);
|
||||
}
|
||||
|
||||
paymentDataRequest() {
|
||||
const applepayConfig = this.applePayConfig
|
||||
const buttonConfig = this.buttonConfig
|
||||
|
@ -174,12 +222,9 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
countryCode: applepayConfig.countryCode,
|
||||
merchantCapabilities: applepayConfig.merchantCapabilities,
|
||||
supportedNetworks: applepayConfig.supportedNetworks,
|
||||
requiredShippingContactFields: ["name", "phone",
|
||||
"email", "postalAddress"],
|
||||
requiredBillingContactFields: ["name", "phone", "email",
|
||||
"postalAddress"]
|
||||
requiredShippingContactFields: ["postalAddress"],
|
||||
requiredBillingContactFields: ["postalAddress"]
|
||||
}
|
||||
console.log('[ApplePayButton] paymentDataRequest', applepayConfig, buttonConfig);
|
||||
const paymentDataRequest = Object.assign({}, baseRequest);
|
||||
paymentDataRequest.currencyCode = buttonConfig.shop.currencyCode;
|
||||
paymentDataRequest.total = {
|
||||
|
@ -197,6 +242,7 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
//------------------------
|
||||
|
||||
onvalidatemerchant(session) {
|
||||
console.log("onvalidatemerchant")
|
||||
return (applePayValidateMerchantEvent) => {
|
||||
paypal.Applepay().validateMerchant({
|
||||
validationUrl: applePayValidateMerchantEvent.validationURL
|
||||
|
@ -234,7 +280,6 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
onshippingmethodselected(session) {
|
||||
const ajax_url = this.buttonConfig.ajax_url
|
||||
console.log('[ApplePayButton] onshippingmethodselected');
|
||||
|
||||
return (event) => {
|
||||
const data = this.getShippingMethodData(event);
|
||||
jQuery.ajax({
|
||||
|
@ -271,7 +316,7 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
}
|
||||
onshippingcontactselected(session) {
|
||||
const ajax_url = this.buttonConfig.ajax_url
|
||||
|
||||
console.log('[ApplePayButton] onshippingcontactselected', ajax_url, session)
|
||||
return (event) => {
|
||||
const data = this.getShippingContactData(event);
|
||||
console.log('shipping contact selected', data, event)
|
||||
|
@ -514,6 +559,44 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
return response;
|
||||
}*/
|
||||
|
||||
fill_billing_contact(form_saved) {
|
||||
return {
|
||||
givenName: form_saved.billing_first_name ?? '',
|
||||
familyName: form_saved.billing_last_name ?? '',
|
||||
emailAddress: form_saved.billing_email ?? '',
|
||||
phoneNumber: form_saved.billing_phone ?? '',
|
||||
addressLines: [form_saved.billing_address_1, form_saved.billing_address_2],
|
||||
locality: form_saved.billing_city ?? '',
|
||||
postalCode: form_saved.billing_postcode ?? '',
|
||||
countryCode: form_saved.billing_country ?? '',
|
||||
administrativeArea: form_saved.billing_state ?? '',
|
||||
}
|
||||
}
|
||||
fill_shipping_contact(form_saved) {
|
||||
if (form_saved.shipping_first_name === "") {
|
||||
return this.fill_billing_contact(form_saved)
|
||||
}
|
||||
return {
|
||||
givenName: (form_saved?.shipping_first_name && form_saved.shipping_first_name !== "") ? form_saved.shipping_first_name : form_saved?.billing_first_name,
|
||||
familyName: (form_saved?.shipping_last_name && form_saved.shipping_last_name !== "") ? form_saved.shipping_last_name : form_saved?.billing_last_name,
|
||||
emailAddress: (form_saved?.shipping_email && form_saved.shipping_email !== "") ? form_saved.shipping_email : form_saved?.billing_email,
|
||||
phoneNumber: (form_saved?.shipping_phone && form_saved.shipping_phone !== "") ? form_saved.shipping_phone : form_saved?.billing_phone,
|
||||
addressLines: [form_saved.shipping_address_1 ?? '', form_saved.shipping_address_2 ?? ''],
|
||||
locality: (form_saved?.shipping_city && form_saved.shipping_city !== "") ? form_saved.shipping_city : form_saved?.billing_city,
|
||||
postalCode: (form_saved?.shipping_postcode && form_saved.shipping_postcode !== "") ? form_saved.shipping_postcode : form_saved?.billing_postcode,
|
||||
countryCode: (form_saved?.shipping_country && form_saved.shipping_country !== "") ? form_saved.shipping_country : form_saved?.billing_country,
|
||||
administrativeArea: (form_saved?.shipping_state && form_saved.shipping_state !== "") ? form_saved.shipping_state : form_saved?.billing_state,
|
||||
}
|
||||
}
|
||||
|
||||
fill_application_data(form_saved) {
|
||||
const jsonString = JSON.stringify(form_saved);
|
||||
let utf8Str = encodeURIComponent(jsonString).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
||||
return String.fromCharCode('0x' + p1);
|
||||
});
|
||||
|
||||
return btoa(utf8Str);
|
||||
}
|
||||
}
|
||||
|
||||
export default ApplepayButton;
|
||||
|
|
|
@ -15,14 +15,28 @@ use WooCommerce\PayPalCommerce\Applepay\Assets\ApplePayButton;
|
|||
use WooCommerce\PayPalCommerce\Applepay\Assets\AppleProductStatus;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Assets\DataToAppleButtonScripts;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Assets\BlocksPaymentMethod;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Helper\ApmApplies;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
return array(
|
||||
'applepay.status-cache' => static function( ContainerInterface $container ): Cache {
|
||||
'applepay.eligible' => static function ( ContainerInterface $container ): bool {
|
||||
$apm_applies = $container->get( 'applepay.helpers.apm-applies' );
|
||||
assert( $apm_applies instanceof ApmApplies );
|
||||
|
||||
return $apm_applies->for_country_currency();
|
||||
},
|
||||
'applepay.helpers.apm-applies' => static function ( ContainerInterface $container ) : ApmApplies {
|
||||
return new ApmApplies(
|
||||
$container->get( 'applepay.supported-country-currency-matrix' ),
|
||||
$container->get( 'api.shop.currency' ),
|
||||
$container->get( 'api.shop.country' )
|
||||
);
|
||||
},
|
||||
'applepay.status-cache' => static function( ContainerInterface $container ): Cache {
|
||||
return new Cache( 'ppcp-paypal-apple-status-cache' );
|
||||
},
|
||||
'applepay.apple-product-status' => static function( ContainerInterface $container ): AppleProductStatus {
|
||||
'applepay.apple-product-status' => static function( ContainerInterface $container ): AppleProductStatus {
|
||||
return new AppleProductStatus(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' ),
|
||||
|
@ -30,18 +44,21 @@ return array(
|
|||
$container->get( 'onboarding.state' )
|
||||
);
|
||||
},
|
||||
'applepay.enabled' => static function ( ContainerInterface $container ): bool {
|
||||
$status = $container->get( 'applepay.apple-product-status' );
|
||||
assert( $status instanceof AppleProductStatus );
|
||||
/**
|
||||
* If merchant isn't onboarded via /v1/customer/partner-referrals this returns false as the API call fails.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_paypal_payments_applepay_product_status', $status->apple_is_active() );
|
||||
'applepay.enabled' => static function ( ContainerInterface $container ): bool {
|
||||
if ( apply_filters( 'woocommerce_paypal_payments_applepay_validate_product_status', false ) ) {
|
||||
$status = $container->get( 'applepay.apple-product-status' );
|
||||
assert( $status instanceof AppleProductStatus );
|
||||
/**
|
||||
* If merchant isn't onboarded via /v1/customer/partner-referrals this returns false as the API call fails.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_paypal_payments_applepay_product_status', $status->apple_is_active() );
|
||||
}
|
||||
return true;
|
||||
},
|
||||
'applepay.server_supported' => static function ( ContainerInterface $container ): bool {
|
||||
'applepay.server_supported' => static function ( ContainerInterface $container ): bool {
|
||||
return ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off';
|
||||
},
|
||||
'applepay.url' => static function ( ContainerInterface $container ): string {
|
||||
'applepay.url' => static function ( ContainerInterface $container ): string {
|
||||
$path = realpath( __FILE__ );
|
||||
if ( false === $path ) {
|
||||
return '';
|
||||
|
@ -51,13 +68,13 @@ return array(
|
|||
dirname( $path, 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
},
|
||||
'applepay.sdk_script_url' => static function ( ContainerInterface $container ): string {
|
||||
'applepay.sdk_script_url' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js';
|
||||
},
|
||||
'applepay.data_to_scripts' => static function ( ContainerInterface $container ): DataToAppleButtonScripts {
|
||||
'applepay.data_to_scripts' => static function ( ContainerInterface $container ): DataToAppleButtonScripts {
|
||||
return new DataToAppleButtonScripts( $container->get( 'applepay.sdk_script_url' ), $container->get( 'wcgateway.settings' ) );
|
||||
},
|
||||
'applepay.button' => static function ( ContainerInterface $container ): ApplePayButton {
|
||||
'applepay.button' => static function ( ContainerInterface $container ): ApplePayButton {
|
||||
|
||||
return new ApplePayButton(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
|
@ -69,7 +86,7 @@ return array(
|
|||
$container->get( 'wcgateway.settings.status' )
|
||||
);
|
||||
},
|
||||
'applepay.blocks-payment-method' => static function ( ContainerInterface $container ): PaymentMethodTypeInterface {
|
||||
'applepay.blocks-payment-method' => static function ( ContainerInterface $container ): PaymentMethodTypeInterface {
|
||||
return new BlocksPaymentMethod(
|
||||
'ppcp-applepay',
|
||||
$container->get( 'applepay.url' ),
|
||||
|
@ -78,4 +95,25 @@ return array(
|
|||
$container->get( 'blocks.method' )
|
||||
);
|
||||
},
|
||||
/**
|
||||
* The matrix which countries and currency combinations can be used for ApplePay.
|
||||
*/
|
||||
'applepay.supported-country-currency-matrix' => static function ( ContainerInterface $container ) : array {
|
||||
/**
|
||||
* Returns which countries and currency combinations can be used for ApplePay.
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_applepay_supported_country_currency_matrix',
|
||||
array(
|
||||
'US' => array(
|
||||
'AUD',
|
||||
'CAD',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'JPY',
|
||||
'USD',
|
||||
),
|
||||
)
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -173,11 +173,19 @@ class DataToAppleButtonScripts {
|
|||
'<div id="applepay-container">'
|
||||
. $nonce
|
||||
. '</div>';
|
||||
$type = $this->settings->has( 'applepay_button_type' ) ? $this->settings->get( 'applepay_button_type' ) : '';
|
||||
$color = $this->settings->has( 'applepay_button_color' ) ? $this->settings->get( 'applepay_button_color' ) : '';
|
||||
$lang = $this->settings->has( 'applepay_button_language' ) ? $this->settings->get( 'applepay_button_language' ) : '';
|
||||
$lang = apply_filters( 'woocommerce_paypal_payments_applepay_button_language', $lang );
|
||||
|
||||
return array(
|
||||
'sdk_url' => $this->sdk_url,
|
||||
'button' => array(
|
||||
'wrapper' => 'applepay-container',
|
||||
'mini_cart_wrapper' => 'applepay-container-minicart',
|
||||
'type' => $type,
|
||||
'color' => $color,
|
||||
'lang' => $lang,
|
||||
),
|
||||
'product' => array(
|
||||
'needShipping' => $cart->needs_shipping(),
|
||||
|
|
67
modules/ppcp-applepay/src/Helper/ApmApplies.php
Normal file
67
modules/ppcp-applepay/src/Helper/ApmApplies.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* ApmApplies helper.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApplePay\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Applepay\Helper;
|
||||
|
||||
/**
|
||||
* Class ApmApplies
|
||||
*/
|
||||
class ApmApplies {
|
||||
|
||||
/**
|
||||
* The matrix which countries and currency combinations can be used for DCC.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $allowed_country_currency_matrix;
|
||||
|
||||
/**
|
||||
* 3-letter currency code of the shop.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $currency;
|
||||
|
||||
/**
|
||||
* 2-letter country code of the shop.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $country;
|
||||
|
||||
/**
|
||||
* ApmApplies constructor.
|
||||
*
|
||||
* @param array $allowed_country_currency_matrix The matrix which countries and currency combinations can be used for DCC.
|
||||
* @param string $currency 3-letter currency code of the shop.
|
||||
* @param string $country 2-letter country code of the shop.
|
||||
*/
|
||||
public function __construct(
|
||||
array $allowed_country_currency_matrix,
|
||||
string $currency,
|
||||
string $country
|
||||
) {
|
||||
$this->allowed_country_currency_matrix = $allowed_country_currency_matrix;
|
||||
$this->currency = $currency;
|
||||
$this->country = $country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether ApplePay can be used in the current country and the current currency used.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function for_country_currency(): bool {
|
||||
if ( ! in_array( $this->country, array_keys( $this->allowed_country_currency_matrix ), true ) ) {
|
||||
return false;
|
||||
}
|
||||
return in_array( $this->currency, $this->allowed_country_currency_matrix[ $this->country ], true );
|
||||
}
|
||||
|
||||
}
|
|
@ -19,7 +19,7 @@ const PayPalComponent = ({
|
|||
shippingData,
|
||||
isEditing,
|
||||
}) => {
|
||||
const {onPaymentSetup, onCheckoutAfterProcessingWithError} = eventRegistration;
|
||||
const {onPaymentSetup, onCheckoutAfterProcessingWithError, onCheckoutValidation} = eventRegistration;
|
||||
const {responseTypes} = emitResponse;
|
||||
|
||||
const [paypalOrder, setPaypalOrder] = useState(null);
|
||||
|
@ -79,8 +79,40 @@ const PayPalComponent = ({
|
|||
}
|
||||
};
|
||||
|
||||
const getCheckoutRedirectUrl = () => {
|
||||
const checkoutUrl = new URL(config.scriptData.redirect);
|
||||
// sometimes some browsers may load some kind of cached version of the page,
|
||||
// so adding a parameter to avoid that
|
||||
checkoutUrl.searchParams.append('ppcp-continuation-redirect', (new Date()).getTime().toString());
|
||||
return checkoutUrl.toString();
|
||||
}
|
||||
|
||||
const handleApprove = async (data, actions) => {
|
||||
try {
|
||||
const order = await actions.order.get();
|
||||
|
||||
if (order) {
|
||||
const addresses = paypalOrderToWcAddresses(order);
|
||||
|
||||
let promises = [
|
||||
// save address on server
|
||||
wp.data.dispatch('wc/store/cart').updateCustomerData({
|
||||
billing_address: addresses.billingAddress,
|
||||
shipping_address: addresses.shippingAddress,
|
||||
}),
|
||||
];
|
||||
if (!config.finalReviewEnabled) {
|
||||
// set address in UI
|
||||
promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress));
|
||||
if (shippingData.needsShipping) {
|
||||
promises.push(wp.data.dispatch('wc/store/cart').setShippingAddress(addresses.shippingAddress))
|
||||
}
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
setPaypalOrder(order);
|
||||
|
||||
const res = await fetch(config.scriptData.ajax.approve_order.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
|
@ -104,25 +136,8 @@ const PayPalComponent = ({
|
|||
throw new Error(config.scriptData.labels.error.generic)
|
||||
}
|
||||
|
||||
const order = await actions.order.get();
|
||||
|
||||
setPaypalOrder(order);
|
||||
|
||||
if (config.finalReviewEnabled) {
|
||||
if (order) {
|
||||
const addresses = paypalOrderToWcAddresses(order);
|
||||
|
||||
await wp.data.dispatch('wc/store/cart').updateCustomerData({
|
||||
billing_address: addresses.billingAddress,
|
||||
shipping_address: addresses.shippingAddress,
|
||||
});
|
||||
}
|
||||
const checkoutUrl = new URL(config.scriptData.redirect);
|
||||
// sometimes some browsers may load some kind of cached version of the page,
|
||||
// so adding a parameter to avoid that
|
||||
checkoutUrl.searchParams.append('ppcp-continuation-redirect', (new Date()).getTime().toString());
|
||||
|
||||
location.href = checkoutUrl.toString();
|
||||
location.href = getCheckoutRedirectUrl();
|
||||
} else {
|
||||
onSubmit();
|
||||
}
|
||||
|
@ -137,6 +152,21 @@ const PayPalComponent = ({
|
|||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = onCheckoutValidation(() => {
|
||||
if (config.scriptData.continuation) {
|
||||
return true;
|
||||
}
|
||||
if (wp.data.select('wc/store/validation').hasValidationErrors()) {
|
||||
location.href = getCheckoutRedirectUrl();
|
||||
return { type: responseTypes.ERROR };
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
return unsubscribe;
|
||||
}, [onCheckoutValidation] );
|
||||
|
||||
const handleClick = (data, actions) => {
|
||||
if (isEditing) {
|
||||
return actions.reject();
|
||||
|
|
|
@ -7,3 +7,7 @@
|
|||
-webkit-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.ppc-button-wrapper #ppcp-messages:first-child {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
|
|
@ -200,7 +200,6 @@ const bootstrap = () => {
|
|||
const payNowBootstrap = new PayNowBootstrap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
messageRenderer,
|
||||
spinner,
|
||||
errorHandler,
|
||||
);
|
||||
|
|
|
@ -156,8 +156,15 @@ class CheckoutBootstap {
|
|||
}
|
||||
|
||||
shouldShowMessages() {
|
||||
return getCurrentPaymentMethod() === PaymentMethods.PAYPAL
|
||||
&& !PayPalCommerceGateway.is_free_trial_cart;
|
||||
// hide when another method selected only if messages are near buttons
|
||||
const messagesWrapper = document.querySelector(this.gateway.messages.wrapper);
|
||||
if (getCurrentPaymentMethod() !== PaymentMethods.PAYPAL &&
|
||||
messagesWrapper && jQuery(messagesWrapper).closest('.ppc-button-wrapper').length
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !PayPalCommerceGateway.is_free_trial_cart;
|
||||
}
|
||||
|
||||
disableCreditCardFields() {
|
||||
|
|
|
@ -2,8 +2,8 @@ import CheckoutBootstap from './CheckoutBootstap'
|
|||
import {isChangePaymentPage} from "../Helper/Subscriptions";
|
||||
|
||||
class PayNowBootstrap extends CheckoutBootstap {
|
||||
constructor(gateway, renderer, messages, spinner, errorHandler) {
|
||||
super(gateway, renderer, messages, spinner, errorHandler)
|
||||
constructor(gateway, renderer, spinner, errorHandler) {
|
||||
super(gateway, renderer, spinner, errorHandler)
|
||||
}
|
||||
|
||||
updateUi() {
|
||||
|
|
|
@ -17,7 +17,7 @@ class SingleProductBootstap {
|
|||
this.formSelector = 'form.cart';
|
||||
|
||||
// Prevent simulate cart being called too many times in a burst.
|
||||
this.simulateCartThrottled = throttle(this.simulateCart, 5000);
|
||||
this.simulateCartThrottled = throttle(this.simulateCart, this.gateway.simulate_cart.throttling || 5000);
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
||||
this.handleChange();
|
||||
|
@ -217,6 +217,10 @@ class SingleProductBootstap {
|
|||
}
|
||||
|
||||
simulateCart() {
|
||||
if (!this.gateway.simulate_cart.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const actionHandler = new SingleProductActionHandler(
|
||||
null,
|
||||
null,
|
||||
|
|
|
@ -6,7 +6,6 @@ export default class FormSaver {
|
|||
|
||||
async save(form) {
|
||||
const formData = new FormData(form);
|
||||
const formJsonObj = Object.fromEntries(formData.entries());
|
||||
|
||||
const res = await fetch(this.url, {
|
||||
method: 'POST',
|
||||
|
@ -16,7 +15,7 @@ export default class FormSaver {
|
|||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: this.nonce,
|
||||
form: formJsonObj,
|
||||
form_encoded: new URLSearchParams(formData).toString(),
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
@ -28,15 +28,9 @@ class MessageRenderer {
|
|||
return;
|
||||
}
|
||||
|
||||
const newWrapper = document.createElement('div');
|
||||
newWrapper.setAttribute('id', this.config.wrapper.replace('#', ''));
|
||||
const wrapper = document.querySelector(this.config.wrapper);
|
||||
this.currentNumber++;
|
||||
newWrapper.setAttribute('data-render-number', this.currentNumber);
|
||||
|
||||
const oldWrapper = document.querySelector(this.config.wrapper);
|
||||
const sibling = oldWrapper.nextSibling;
|
||||
oldWrapper.parentElement.removeChild(oldWrapper);
|
||||
sibling.parentElement.insertBefore(newWrapper, sibling);
|
||||
wrapper.setAttribute('data-render-number', this.currentNumber);
|
||||
|
||||
widgetBuilder.registerMessages(this.config.wrapper, options);
|
||||
widgetBuilder.renderMessages(this.config.wrapper);
|
||||
|
|
|
@ -84,11 +84,14 @@ class WidgetBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
const entry = this.messages.get(wrapper);
|
||||
|
||||
if (this.hasRendered(wrapper)) {
|
||||
const element = document.querySelector(wrapper);
|
||||
element.setAttribute('data-pp-amount', entry.options.amount);
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = this.messages.get(wrapper);
|
||||
const btn = this.paypal.Messages(entry.options);
|
||||
|
||||
btn.render(entry.wrapper);
|
||||
|
|
|
@ -382,54 +382,48 @@ class SmartButton implements SmartButtonInterface {
|
|||
* Registers the hooks to render the credit messaging HTML depending on the settings.
|
||||
*
|
||||
* @return bool
|
||||
* @throws NotFoundException When a setting was not found.
|
||||
*/
|
||||
private function render_message_wrapper_registrar(): bool {
|
||||
if ( ! $this->settings_status->is_pay_later_messaging_enabled() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$selected_locations = $this->settings->has( 'pay_later_messaging_locations' ) ? $this->settings->get( 'pay_later_messaging_locations' ) : array();
|
||||
$location = $this->location();
|
||||
|
||||
$not_enabled_on_cart = ! in_array( 'cart', $selected_locations, true );
|
||||
if ( ! $this->settings_status->is_pay_later_messaging_enabled_for_location( $location ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$get_hook = function ( string $location ): ?array {
|
||||
switch ( $location ) {
|
||||
case 'checkout':
|
||||
return $this->messages_renderer_hook( $location, 'woocommerce_review_order_before_payment', 10 );
|
||||
case 'cart':
|
||||
return $this->messages_renderer_hook( $location, $this->proceed_to_checkout_button_renderer_hook(), 19 );
|
||||
case 'pay-now':
|
||||
return $this->messages_renderer_hook( 'pay_order', 'woocommerce_pay_order_before_submit', 10 );
|
||||
case 'product':
|
||||
return $this->messages_renderer_hook( $location, $this->single_product_renderer_hook(), 30 );
|
||||
case 'shop':
|
||||
return $this->messages_renderer_hook( $location, 'woocommerce_archive_description', 10 );
|
||||
case 'home':
|
||||
return $this->messages_renderer_hook( $location, 'loop_start', 20 );
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
$hook = $get_hook( $location );
|
||||
if ( ! $hook ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
add_action(
|
||||
$this->proceed_to_checkout_button_renderer_hook(),
|
||||
function() use ( $not_enabled_on_cart ) {
|
||||
if ( ! is_cart() || $not_enabled_on_cart ) {
|
||||
return;
|
||||
}
|
||||
$this->message_renderer();
|
||||
},
|
||||
19
|
||||
$hook['name'],
|
||||
array( $this, 'message_renderer' ),
|
||||
$hook['priority']
|
||||
);
|
||||
|
||||
$not_enabled_on_product_page = ! in_array( 'product', $selected_locations, true );
|
||||
if (
|
||||
( is_product() || wc_post_content_has_shortcode( 'product_page' ) )
|
||||
&& ! $not_enabled_on_product_page
|
||||
&& ! is_checkout()
|
||||
) {
|
||||
add_action(
|
||||
$this->single_product_renderer_hook(),
|
||||
array( $this, 'message_renderer' ),
|
||||
30
|
||||
);
|
||||
}
|
||||
|
||||
$not_enabled_on_checkout = ! in_array( 'checkout', $selected_locations, true );
|
||||
if ( ! $not_enabled_on_checkout ) {
|
||||
add_action(
|
||||
$this->checkout_dcc_button_renderer_hook(),
|
||||
array( $this, 'message_renderer' ),
|
||||
11
|
||||
);
|
||||
add_action(
|
||||
$this->pay_order_renderer_hook(),
|
||||
array( $this, 'message_renderer' ),
|
||||
15
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -482,7 +476,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
echo '<p class="woocommerce-mini-cart__buttons buttons">';
|
||||
echo '<span id="ppc-button-minicart"></span>';
|
||||
do_action( 'woocommerce_paypal_payments_minicart_button_render' );
|
||||
echo '</div>';
|
||||
echo '</p>';
|
||||
},
|
||||
30
|
||||
);
|
||||
|
@ -528,8 +522,8 @@ class SmartButton implements SmartButtonInterface {
|
|||
* Whether any of our scripts (for DCC or product, mini-cart, non-block cart/checkout) should be loaded.
|
||||
*/
|
||||
public function should_load_ppcp_script(): bool {
|
||||
$buttons_enabled = $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' );
|
||||
if ( ! $buttons_enabled ) {
|
||||
$pcp_gateway_enabled = $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' );
|
||||
if ( ! $pcp_gateway_enabled ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -537,37 +531,65 @@ class SmartButton implements SmartButtonInterface {
|
|||
return false;
|
||||
}
|
||||
|
||||
return $this->should_load_buttons() || $this->can_render_dcc();
|
||||
return $this->should_load_buttons() || $this->should_load_messages() || $this->can_render_dcc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the button component should be loaded.
|
||||
*/
|
||||
public function should_load_buttons() : bool {
|
||||
$buttons_enabled = $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' );
|
||||
if ( ! $buttons_enabled ) {
|
||||
$pcp_gateway_enabled = $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' );
|
||||
if ( ! $pcp_gateway_enabled ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$smart_button_enabled_for_current_location = $this->settings_status->is_smart_button_enabled_for_location( $this->context() );
|
||||
$smart_button_enabled_for_mini_cart = $this->settings_status->is_smart_button_enabled_for_location( 'mini-cart' );
|
||||
$messaging_enabled_for_current_location = $this->settings_status->is_pay_later_messaging_enabled_for_location( $this->context() );
|
||||
|
||||
switch ( $this->context() ) {
|
||||
case 'checkout':
|
||||
case 'cart':
|
||||
case 'pay-now':
|
||||
return $smart_button_enabled_for_current_location || $messaging_enabled_for_current_location;
|
||||
case 'checkout-block':
|
||||
case 'cart-block':
|
||||
return $smart_button_enabled_for_current_location;
|
||||
case 'product':
|
||||
return $smart_button_enabled_for_current_location || $messaging_enabled_for_current_location || $smart_button_enabled_for_mini_cart;
|
||||
return $smart_button_enabled_for_current_location || $smart_button_enabled_for_mini_cart;
|
||||
default:
|
||||
return $smart_button_enabled_for_mini_cart;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the Pay Later messages component should be loaded.
|
||||
*/
|
||||
public function should_load_messages() : bool {
|
||||
$pcp_gateway_enabled = $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' );
|
||||
if ( ! $pcp_gateway_enabled ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->messages_apply->for_country() || $this->is_free_trial_cart() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$location = $this->location();
|
||||
|
||||
$messaging_enabled_for_current_location = $this->settings_status->is_pay_later_messaging_enabled_for_location( $location );
|
||||
|
||||
switch ( $location ) {
|
||||
case 'checkout':
|
||||
case 'cart':
|
||||
case 'pay-now':
|
||||
case 'product':
|
||||
case 'shop':
|
||||
case 'home':
|
||||
return $messaging_enabled_for_current_location;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether DCC fields can be rendered.
|
||||
*/
|
||||
|
@ -630,8 +652,24 @@ class SmartButton implements SmartButtonInterface {
|
|||
// The wrapper is needed for the loading spinner,
|
||||
// otherwise jQuery block() prevents buttons rendering.
|
||||
echo '<div class="ppc-button-wrapper">';
|
||||
|
||||
$hook_gateway_id = str_replace( '-', '_', $gateway_id );
|
||||
/**
|
||||
* A hook executed after rendering of the opening tag for the PCP wrapper (before the inner wrapper for the buttons).
|
||||
*
|
||||
* For the PayPal gateway the hook name is ppcp_start_button_wrapper_ppcp_gateway.
|
||||
*/
|
||||
do_action( 'ppcp_start_button_wrapper_' . $hook_gateway_id );
|
||||
|
||||
echo '<div id="ppc-button-' . esc_attr( $gateway_id ) . '"></div>';
|
||||
|
||||
/**
|
||||
* A hook executed before rendering of the closing tag for the PCP wrapper (before the inner wrapper for the buttons).
|
||||
*
|
||||
* For the PayPal gateway the hook name is ppcp_end_button_wrapper_ppcp_gateway.
|
||||
*/
|
||||
do_action( 'ppcp_end_button_wrapper_' . $hook_gateway_id );
|
||||
|
||||
if ( null !== $action_name ) {
|
||||
do_action( $action_name );
|
||||
}
|
||||
|
@ -646,8 +684,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
$product = wc_get_product();
|
||||
|
||||
$location = $this->location();
|
||||
|
||||
if (
|
||||
! is_checkout() && is_a( $product, WC_Product::class )
|
||||
$location === 'product' && is_a( $product, WC_Product::class )
|
||||
/**
|
||||
* The filter returning true if PayPal buttons can be rendered, or false otherwise.
|
||||
*/
|
||||
|
@ -663,24 +703,47 @@ class SmartButton implements SmartButtonInterface {
|
|||
* The values for the credit messaging.
|
||||
*
|
||||
* @return array
|
||||
* @throws NotFoundException When a setting was not found.
|
||||
*/
|
||||
private function message_values(): array {
|
||||
if ( ! $this->settings_status->is_pay_later_messaging_enabled() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$placement = is_checkout() ? 'payment' : ( is_cart() ? 'cart' : 'product' );
|
||||
$product = wc_get_product();
|
||||
$amount = ( is_a( $product, WC_Product::class ) ) ? wc_get_price_including_tax( $product ) : 0;
|
||||
$location = $this->location();
|
||||
|
||||
switch ( $location ) {
|
||||
case 'checkout':
|
||||
case 'checkout-block':
|
||||
case 'pay-now':
|
||||
$placement = 'payment';
|
||||
break;
|
||||
case 'cart':
|
||||
case 'cart-block':
|
||||
$placement = 'cart';
|
||||
break;
|
||||
case 'product':
|
||||
$placement = 'product';
|
||||
break;
|
||||
case 'shop':
|
||||
$placement = 'product-list';
|
||||
break;
|
||||
case 'home':
|
||||
$placement = 'home';
|
||||
break;
|
||||
default:
|
||||
$placement = 'payment';
|
||||
break;
|
||||
}
|
||||
|
||||
$product = wc_get_product();
|
||||
$amount = ( is_a( $product, WC_Product::class ) ) ? wc_get_price_including_tax( $product ) : 0;
|
||||
|
||||
if ( is_checkout() || is_cart() ) {
|
||||
$amount = WC()->cart->get_total( 'raw' );
|
||||
}
|
||||
|
||||
$styling_per_location = $this->settings->has( 'pay_later_enable_styling_per_messaging_location' ) && $this->settings->get( 'pay_later_enable_styling_per_messaging_location' );
|
||||
$per_location = is_checkout() ? 'checkout' : ( is_cart() ? 'cart' : 'product' );
|
||||
$location = $styling_per_location ? $per_location : 'general';
|
||||
$location = $styling_per_location ? $location : 'general';
|
||||
$setting_name_prefix = "pay_later_{$location}_message";
|
||||
|
||||
$layout = $this->settings->has( "{$setting_name_prefix}_layout" ) ? $this->settings->get( "{$setting_name_prefix}_layout" ) : 'text';
|
||||
|
@ -963,6 +1026,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
// phpcs:ignore WordPress.WP.I18n
|
||||
'shipping_field' => _x( 'Shipping %s', 'checkout-validation', 'woocommerce' ),
|
||||
),
|
||||
'simulate_cart' => array(
|
||||
'enabled' => apply_filters( 'woocommerce_paypal_payments_simulate_cart_enabled', true ),
|
||||
'throttling' => apply_filters( 'woocommerce_paypal_payments_simulate_cart_throttling', 5000 ),
|
||||
),
|
||||
'order_id' => 'pay-now' === $this->context() ? $this->get_order_pay_id() : 0,
|
||||
'single_product_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'product' ),
|
||||
'mini_cart_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'mini-cart' ),
|
||||
|
@ -1159,10 +1226,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
$components[] = 'buttons';
|
||||
$components[] = 'funding-eligibility';
|
||||
}
|
||||
if (
|
||||
$this->messages_apply->for_country()
|
||||
&& ! $this->is_free_trial_cart()
|
||||
) {
|
||||
if ( $this->should_load_messages() ) {
|
||||
$components[] = 'messages';
|
||||
}
|
||||
if ( $this->dcc_is_enabled() ) {
|
||||
|
@ -1172,7 +1236,6 @@ class SmartButton implements SmartButtonInterface {
|
|||
* Filter to add further components from the extensions.
|
||||
*
|
||||
* @internal Matches filter name in APM extension.
|
||||
* @since TODO
|
||||
*
|
||||
* @param array $components The array of components already registered.
|
||||
*/
|
||||
|
@ -1296,6 +1359,35 @@ class SmartButton implements SmartButtonInterface {
|
|||
return (string) apply_filters( 'woocommerce_paypal_payments_pay_order_dcc_renderer_hook', 'woocommerce_pay_order_after_submit' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action name that will be used for rendering Pay Later messages.
|
||||
*
|
||||
* @param string $location The location name like 'checkout', 'shop'. See render_message_wrapper_registrar.
|
||||
* @param string $default_hook The default name of the hook.
|
||||
* @param int $default_priority The default priority of the hook.
|
||||
* @return array An array with 'name' and 'priority' keys.
|
||||
*/
|
||||
private function messages_renderer_hook( string $location, string $default_hook, int $default_priority ): array {
|
||||
/**
|
||||
* The filter returning the action name that will be used for rendering Pay Later messages.
|
||||
*/
|
||||
$hook = (string) apply_filters(
|
||||
"woocommerce_paypal_payments_${location}_messages_renderer_hook",
|
||||
$default_hook
|
||||
);
|
||||
/**
|
||||
* The filter returning the action priority that will be used for rendering Pay Later messages.
|
||||
*/
|
||||
$priority = (int) apply_filters(
|
||||
"woocommerce_paypal_payments_${location}_messages_renderer_priority",
|
||||
$default_priority
|
||||
);
|
||||
return array(
|
||||
'name' => $hook,
|
||||
'priority' => $priority,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns action name that PayPal button will use for rendering next to Proceed to checkout button (normally displayed in cart).
|
||||
*
|
||||
|
@ -1547,16 +1639,14 @@ class SmartButton implements SmartButtonInterface {
|
|||
* @throws NotFoundException If intent is not found.
|
||||
*/
|
||||
private function intent(): string {
|
||||
$intent = ( $this->settings->has( 'intent' ) ) ? $this->settings->get( 'intent' ) : 'capture';
|
||||
$product_intent = $this->subscription_helper->current_product_is_subscription() ? 'authorize' : $intent;
|
||||
$other_context_intent = $this->subscription_helper->cart_contains_subscription() ? 'authorize' : $intent;
|
||||
|
||||
$subscription_mode = $this->settings->has( 'subscriptions_mode' ) ? $this->settings->get( 'subscriptions_mode' ) : '';
|
||||
if ( $this->subscription_helper->need_subscription_intent( $subscription_mode ) ) {
|
||||
return 'subscription';
|
||||
}
|
||||
|
||||
return $this->context() === 'product' ? $product_intent : $other_context_intent;
|
||||
$intent = $this->settings->has( 'intent' ) ? $this->settings->get( 'intent' ) : 'capture';
|
||||
|
||||
return strtolower( apply_filters( 'woocommerce_paypal_payments_order_intent', $intent ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -151,6 +151,7 @@ class SimulateCartEndpoint extends AbstractCartEndpoint {
|
|||
|
||||
/**
|
||||
* Restores the real cart.
|
||||
* Currently, unsets the WC cart to prevent race conditions arising from it being persisted.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
@ -158,10 +159,17 @@ class SimulateCartEndpoint extends AbstractCartEndpoint {
|
|||
// Remove from cart because some plugins reserve resources internally when adding to cart.
|
||||
$this->remove_cart_items();
|
||||
|
||||
// Restore cart and unset cart clone.
|
||||
if ( null !== $this->real_cart ) {
|
||||
WC()->cart = $this->real_cart;
|
||||
if ( apply_filters( 'woocommerce_paypal_payments_simulate_cart_prevent_updates', true ) ) {
|
||||
// Removes shutdown actions to prevent persisting session, transients and save cookies.
|
||||
remove_all_actions( 'shutdown' );
|
||||
unset( WC()->cart );
|
||||
} else {
|
||||
// Restores cart, may lead to race conditions.
|
||||
if ( null !== $this->real_cart ) {
|
||||
WC()->cart = $this->real_cart;
|
||||
}
|
||||
}
|
||||
|
||||
unset( $this->cart );
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,27 @@ namespace WooCommerce\PayPalCommerce\Button\Helper;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
|
||||
trait ContextTrait {
|
||||
/**
|
||||
* Checks WC is_checkout() + WC checkout ajax requests.
|
||||
*/
|
||||
private function is_checkout(): bool {
|
||||
if ( is_checkout() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The filter returning whether to detect WC checkout ajax requests.
|
||||
*/
|
||||
if ( apply_filters( 'ppcp_check_ajax_checkout', true ) ) {
|
||||
// phpcs:ignore WordPress.Security
|
||||
$wc_ajax = $_GET['wc-ajax'] ?? '';
|
||||
if ( in_array( $wc_ajax, array( 'update_order_review' ), true ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current context.
|
||||
|
@ -23,7 +44,7 @@ trait ContextTrait {
|
|||
|
||||
// Do this check here instead of reordering outside conditions.
|
||||
// In order to have more control over the context.
|
||||
if ( ( is_checkout() ) && ! $this->is_paypal_continuation() ) {
|
||||
if ( $this->is_checkout() && ! $this->is_paypal_continuation() ) {
|
||||
return 'checkout';
|
||||
}
|
||||
|
||||
|
@ -47,13 +68,35 @@ trait ContextTrait {
|
|||
return 'checkout-block';
|
||||
}
|
||||
|
||||
if ( ( is_checkout() ) && ! $this->is_paypal_continuation() ) {
|
||||
if ( $this->is_checkout() && ! $this->is_paypal_continuation() ) {
|
||||
return 'checkout';
|
||||
}
|
||||
|
||||
return 'mini-cart';
|
||||
}
|
||||
|
||||
/**
|
||||
* The current location.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function location(): string {
|
||||
$context = $this->context();
|
||||
if ( $context !== 'mini-cart' ) {
|
||||
return $context;
|
||||
}
|
||||
|
||||
if ( is_shop() ) {
|
||||
return 'shop';
|
||||
}
|
||||
|
||||
if ( is_front_page() ) {
|
||||
return 'home';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if PayPal payment was already initiated (on the product or cart pages).
|
||||
*
|
||||
|
|
|
@ -30,7 +30,7 @@ trait AdminContextTrait {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ( ! $order->get_meta( PayPalGateway::ORDER_ID_META_KEY ) ) {
|
||||
if ( ! $order->get_meta( PayPalGateway::ORDER_ID_META_KEY ) || empty( $order->get_transaction_id() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Googlepay;
|
|||
use WooCommerce\PayPalCommerce\Googlepay\Helper\PropertiesDictionary;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
|
||||
|
||||
return array(
|
||||
|
@ -31,6 +32,9 @@ return array(
|
|||
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) );
|
||||
};
|
||||
|
||||
$display_manager = $container->get( 'wcgateway.display-manager' );
|
||||
assert( $display_manager instanceof DisplayManager );
|
||||
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'allow_card_button_gateway',
|
||||
|
@ -52,20 +56,16 @@ return array(
|
|||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-handlers' => wp_json_encode(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
array(
|
||||
'handler' => 'SubElementsHandler',
|
||||
'options' => array(
|
||||
'values' => array( '1' ),
|
||||
'elements' => array(
|
||||
'#field-googlepay_button_color',
|
||||
'#field-googlepay_button_type',
|
||||
'#field-googlepay_button_language',
|
||||
'#field-googlepay_button_shipping_enabled',
|
||||
),
|
||||
),
|
||||
),
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_element( 'googlepay_button_enabled', '1' )
|
||||
->action_visible( 'googlepay_button_type' )
|
||||
->action_visible( 'googlepay_button_color' )
|
||||
->action_visible( 'googlepay_button_language' )
|
||||
->action_visible( 'googlepay_button_shipping_enabled' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
|
|
|
@ -45,7 +45,7 @@ label.error {
|
|||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.input-text[pattern]:invalid {
|
||||
.input-text[pattern]:invalid, .input-text[type=email]:invalid {
|
||||
border: red solid 2px;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
const payLaterMessagingSelectableLocations = ['product', 'cart', 'checkout'];
|
||||
const payLaterMessagingSelectableLocations = ['product', 'cart', 'checkout', 'shop', 'home'];
|
||||
const payLaterMessagingAllLocations = payLaterMessagingSelectableLocations.concat('general');
|
||||
const payLaterMessagingLocationsSelector = '#field-pay_later_messaging_locations';
|
||||
const payLaterMessagingLocationsSelect = payLaterMessagingLocationsSelector + ' select';
|
||||
|
@ -9,7 +9,7 @@ document.addEventListener(
|
|||
|
||||
const smartButtonLocationsSelector = '#field-smart_button_locations';
|
||||
const smartButtonLocationsSelect = smartButtonLocationsSelector + ' select';
|
||||
const smartButtonSelectableLocations = payLaterMessagingSelectableLocations.concat('mini-cart');
|
||||
const smartButtonSelectableLocations = ['product', 'cart', 'checkout', 'mini-cart'];
|
||||
|
||||
const groupToggle = (selector, group) => {
|
||||
const toggleElement = document.querySelector(selector);
|
||||
|
|
|
@ -136,6 +136,7 @@ class OrderTrackingEndpoint {
|
|||
$order_id = (int) $data['order_id'];
|
||||
$action = $data['action'] ?? '';
|
||||
|
||||
$this->validate_tracking_info( $data );
|
||||
$shipment = $this->create_shipment( $order_id, $data );
|
||||
|
||||
$action === 'update'
|
||||
|
@ -381,45 +382,53 @@ class OrderTrackingEndpoint {
|
|||
$carrier = $data['carrier'] ?? '';
|
||||
|
||||
$tracking_info = array(
|
||||
'transaction_id' => $data['transaction_id'] ?? '',
|
||||
'status' => $data['status'] ?? '',
|
||||
'tracking_number' => $data['tracking_number'] ?? '',
|
||||
'carrier' => $carrier,
|
||||
'transaction_id' => $data['transaction_id'] ?? '',
|
||||
'status' => $data['status'] ?? '',
|
||||
'tracking_number' => $data['tracking_number'] ?? '',
|
||||
'carrier' => $carrier,
|
||||
'carrier_name_other' => $data['carrier_name_other'] ?? '',
|
||||
);
|
||||
|
||||
if ( ! empty( $data['items'] ) ) {
|
||||
$tracking_info['items'] = array_map( 'intval', $data['items'] );
|
||||
}
|
||||
|
||||
if ( $carrier === 'OTHER' ) {
|
||||
$tracking_info['carrier_name_other'] = $data['carrier_name_other'] ?? '';
|
||||
}
|
||||
|
||||
$this->validate_tracking_info( $tracking_info );
|
||||
|
||||
return $this->shipment_factory->create_shipment(
|
||||
$wc_order_id,
|
||||
$tracking_info['transaction_id'],
|
||||
$tracking_info['tracking_number'],
|
||||
$tracking_info['status'],
|
||||
$tracking_info['carrier'],
|
||||
$tracking_info['carrier_name_other'] ?? '',
|
||||
$tracking_info['carrier_name_other'],
|
||||
$tracking_info['items'] ?? array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the requested tracking info.
|
||||
* Validates tracking info for given request values.
|
||||
*
|
||||
* @param array<string, mixed> $tracking_info A map of tracking information keys to values.
|
||||
* @param array<string, mixed> $request_values A map of request keys to values.
|
||||
* @return void
|
||||
* @throws RuntimeException If validation failed.
|
||||
*/
|
||||
protected function validate_tracking_info( array $tracking_info ): void {
|
||||
protected function validate_tracking_info( array $request_values ): void {
|
||||
$error_message = __( 'Missing required information: ', 'woocommerce-paypal-payments' );
|
||||
$empty_keys = array();
|
||||
|
||||
foreach ( $tracking_info as $key => $value ) {
|
||||
$carrier = $request_values['carrier'] ?? '';
|
||||
|
||||
$data_to_check = array(
|
||||
'transaction_id' => $request_values['transaction_id'] ?? '',
|
||||
'status' => $request_values['status'] ?? '',
|
||||
'tracking_number' => $request_values['tracking_number'] ?? '',
|
||||
'carrier' => $carrier,
|
||||
);
|
||||
|
||||
if ( $carrier === 'OTHER' ) {
|
||||
$data_to_check['carrier_name_other'] = $request_values['carrier_name_other'] ?? '';
|
||||
}
|
||||
|
||||
foreach ( $data_to_check as $key => $value ) {
|
||||
if ( ! empty( $value ) ) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ class MetaBoxRenderer {
|
|||
?>
|
||||
<div class="ppcp-tracking-columns-wrapper">
|
||||
<div class="ppcp-tracking-column">
|
||||
<h3><?php echo esc_html__( 'Add New Shipment Tracking to PayPal order', 'woocommerce-paypal-payments' ); ?></h3>
|
||||
<h3><?php echo esc_html__( 'Share Package Tracking Data with PayPal', 'woocommerce-paypal-payments' ); ?></h3>
|
||||
<p>
|
||||
<label for="ppcp-tracking-transaction_id"><?php echo esc_html__( 'Transaction ID', 'woocommerce-paypal-payments' ); ?></label>
|
||||
<input type="text" disabled class="ppcp-tracking-transaction_id disabled" id="ppcp-tracking-transaction_id" name="ppcp-tracking[transaction_id]" value="<?php echo esc_attr( $transaction_id ); ?>" />
|
||||
|
@ -155,17 +155,25 @@ class MetaBoxRenderer {
|
|||
<input type="text" class="ppcp-tracking-carrier_name_other" id="ppcp-tracking-carrier_name_other" name="ppcp-tracking[carrier_name_other]" />
|
||||
</p>
|
||||
<input type="hidden" class="ppcp-tracking-order_id" name="ppcp-tracking[order_id]" value="<?php echo (int) $wc_order->get_id(); ?>"/>
|
||||
<p><button type="button" class="button submit_tracking_info"><?php echo esc_html__( 'Add Shipment', 'woocommerce-paypal-payments' ); ?></button></p>
|
||||
<p><button type="button" class="button submit_tracking_info"><?php echo esc_html__( 'Add Package Tracking', 'woocommerce-paypal-payments' ); ?></button></p>
|
||||
</div>
|
||||
<div class="ppcp-tracking-column shipments">
|
||||
<h3><?php echo esc_html__( 'Shipments', 'woocommerce-paypal-payments' ); ?></h3>
|
||||
<h3><?php echo esc_html__( 'PayPal Package Tracking Status', 'woocommerce-paypal-payments' ); ?></h3>
|
||||
<?php
|
||||
foreach ( $shipments as $shipment ) {
|
||||
$shipment->render( $this->allowed_statuses );
|
||||
}
|
||||
?>
|
||||
<?php if ( empty( $shipments ) ) : ?>
|
||||
<p class="ppcp-tracking-no-shipments"><?php echo esc_html__( 'No PayPal Shipment Tracking added to this order yet. Add new Shipment Tracking or reload the page to refresh', 'woocommerce-paypal-payments' ); ?></p>
|
||||
<p class="ppcp-tracking-no-shipments">
|
||||
<?php echo esc_html__( 'Package Tracking data has not been shared with PayPal on this order.', 'woocommerce-paypal-payments' ); ?><br>
|
||||
<?php echo esc_html__( 'Add tracking details on this order to qualify for PayPal Seller Protection, faster holds release and automated dispute resolution.', 'woocommerce-paypal-payments' ); ?>
|
||||
<p class="ppcp-tracking-link-to-docs">
|
||||
<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#package-tracking" target="_blank">
|
||||
<?php echo esc_html__( 'Discover full benefits of PayPal Package Tracking here.', 'woocommerce-paypal-payments' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="blockUI blockOverlay ppcp-tracking-loader"></div>
|
||||
|
|
|
@ -99,7 +99,7 @@ class OrderTrackingModule implements ModuleInterface {
|
|||
|
||||
add_meta_box(
|
||||
'ppcp_order-tracking',
|
||||
__( 'PayPal Shipment Tracking', 'woocommerce-paypal-payments' ),
|
||||
__( 'PayPal Package Tracking', 'woocommerce-paypal-payments' ),
|
||||
array( $meta_box_renderer, 'render' ),
|
||||
$screen,
|
||||
'normal'
|
||||
|
|
|
@ -154,20 +154,27 @@ class Shipment implements ShipmentInterface {
|
|||
continue;
|
||||
}
|
||||
|
||||
$product = $item->get_product();
|
||||
$product = $item->get_product();
|
||||
if ( ! is_a( $product, WC_Product::class ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$currency = $wc_order->get_currency();
|
||||
$quantity = (int) $item->get_quantity();
|
||||
$price_without_tax = (float) $wc_order->get_item_subtotal( $item, false );
|
||||
$price_without_tax_rounded = round( $price_without_tax, 2 );
|
||||
$image = wp_get_attachment_image_src( (int) $product->get_image_id(), 'full' );
|
||||
|
||||
$ppcp_order_item = new Item(
|
||||
mb_substr( $item->get_name(), 0, 127 ),
|
||||
new Money( $price_without_tax_rounded, $currency ),
|
||||
$quantity,
|
||||
$product instanceof WC_Product ? $this->prepare_description( $product->get_description() ) : '',
|
||||
$this->prepare_description( $product->get_description() ),
|
||||
null,
|
||||
$product instanceof WC_Product ? $product->get_sku() : '',
|
||||
( $product instanceof WC_Product && $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
|
||||
$product->get_sku(),
|
||||
$product->is_virtual() ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
$product->get_permalink(),
|
||||
$image[0] ?? ''
|
||||
);
|
||||
|
||||
$tracking_items[ $item->get_id() ] = $ppcp_order_item->to_array();
|
||||
|
|
3
modules/ppcp-saved-payment-checker/.gitignore
vendored
Normal file
3
modules/ppcp-saved-payment-checker/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
node_modules
|
||||
assets/js
|
||||
assets/css
|
17
modules/ppcp-saved-payment-checker/composer.json
Normal file
17
modules/ppcp-saved-payment-checker/composer.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "woocommerce/ppcp-saved-payment-checker",
|
||||
"type": "dhii-mod",
|
||||
"description": "Saved payments checker module",
|
||||
"license": "GPL-2.0",
|
||||
"require": {
|
||||
"php": "^7.2 | ^8.0",
|
||||
"dhii/module-interface": "^0.3.0-alpha1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"WooCommerce\\PayPalCommerce\\SavedPaymentChecker\\": "src"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
56
modules/ppcp-saved-payment-checker/extensions.php
Normal file
56
modules/ppcp-saved-payment-checker/extensions.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
/**
|
||||
* The SavedPaymentChecker module extensions.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\SavedPaymentChecker
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavedPaymentChecker;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
return array(
|
||||
'wcgateway.settings.fields' => function ( ContainerInterface $container, array $fields ): array {
|
||||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
assert( $subscription_helper instanceof SubscriptionHelper );
|
||||
|
||||
$insert_after = function( array $array, string $key, array $new ): array {
|
||||
$keys = array_keys( $array );
|
||||
$index = array_search( $key, $keys, true );
|
||||
$pos = false === $index ? count( $array ) : $index + 1;
|
||||
|
||||
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) );
|
||||
};
|
||||
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'vault_enabled',
|
||||
array(
|
||||
'subscription_behavior_when_vault_fails' => array(
|
||||
'title' => __( 'Subscription capture behavior if Vault fails', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'classes' => $subscription_helper->plugin_is_active() ? array() : array( 'hide' ),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'void_auth',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'By default, subscription payments are captured only when saving the payment method was successful. Without a saved payment method, automatic renewal payments are not possible.', 'woocommerce-paypal-payments' ),
|
||||
'description_with_tip' => __( 'Determines whether authorized payments for subscription orders are captured or voided if there is no saved payment method. This only applies when the intent Capture is used for the subscription order.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'void_auth' => __( 'Void authorization & fail the order/subscription', 'woocommerce-paypal-payments' ),
|
||||
'capture_auth' => __( 'Capture authorized payment & set subscription to Manual Renewal', 'woocommerce-paypal-payments' ),
|
||||
'capture_auth_ignore' => __( 'Capture authorized payment & disregard missing payment method', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => array( 'paypal' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
},
|
||||
);
|
16
modules/ppcp-saved-payment-checker/module.php
Normal file
16
modules/ppcp-saved-payment-checker/module.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* The SavedPaymentChecker module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\SavedPaymentChecker
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavedPaymentChecker;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
|
||||
return static function (): ModuleInterface {
|
||||
return new SavedPaymentCheckerModule();
|
||||
};
|
26
modules/ppcp-saved-payment-checker/services.php
Normal file
26
modules/ppcp-saved-payment-checker/services.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* The SavedPaymentChecker module services.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\SavedPaymentChecker
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavedPaymentChecker;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
return array(
|
||||
'saved-payment-checker.payment-token-checker' => function( ContainerInterface $container ) : PaymentTokenChecker {
|
||||
return new PaymentTokenChecker(
|
||||
$container->get( 'vaulting.repository.payment-token' ),
|
||||
$container->get( 'api.repository.order' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'wcgateway.processor.authorized-payments' ),
|
||||
$container->get( 'api.endpoint.payments' ),
|
||||
$container->get( 'api.endpoint.payment-token' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
);
|
|
@ -7,17 +7,17 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||
namespace WooCommerce\PayPalCommerce\SavedPaymentChecker;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokenEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
|
@ -203,6 +203,32 @@ class PaymentTokenChecker {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the vaulted payment check.
|
||||
*
|
||||
* @param int $wc_order_id The WC order ID.
|
||||
* @param int $customer_id The customer ID.
|
||||
*/
|
||||
public function schedule_saved_payment_check( int $wc_order_id, int $customer_id ): void {
|
||||
$timestamp = 3 * MINUTE_IN_SECONDS;
|
||||
if (
|
||||
$this->settings->has( 'subscription_behavior_when_vault_fails' )
|
||||
&& $this->settings->get( 'subscription_behavior_when_vault_fails' ) === 'capture_auth'
|
||||
) {
|
||||
$timestamp = 0;
|
||||
}
|
||||
|
||||
as_schedule_single_action(
|
||||
time() + $timestamp,
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
array(
|
||||
'order_id' => $wc_order_id,
|
||||
'customer_id' => $customer_id,
|
||||
'intent' => $this->settings->has( 'intent' ) ? $this->settings->get( 'intent' ) : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures authorized payments for the given WC order.
|
||||
*
|
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
/**
|
||||
* The SavedPaymentChecker module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\SavedPaymentChecker
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavedPaymentChecker;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class SavedPaymentCheckerModule
|
||||
*/
|
||||
class SavedPaymentCheckerModule implements ModuleInterface {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setup(): ServiceProviderInterface {
|
||||
return new ServiceProvider(
|
||||
require __DIR__ . '/../services.php',
|
||||
require __DIR__ . '/../extensions.php'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function run( ContainerInterface $c ): void {
|
||||
|
||||
/**
|
||||
* Set authorize intent for vaulted subscriptions, so we can void if payment not saved.
|
||||
*/
|
||||
add_filter(
|
||||
'woocommerce_paypal_payments_order_intent',
|
||||
function( string $intent ) use ( $c ) {
|
||||
$subscription_helper = $c->get( 'subscription.helper' );
|
||||
assert( $subscription_helper instanceof SubscriptionHelper );
|
||||
|
||||
if ( $subscription_helper->cart_contains_subscription() || $subscription_helper->current_product_is_subscription() ) {
|
||||
return 'AUTHORIZE';
|
||||
}
|
||||
|
||||
return $intent;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Schedules saved payment checker before payment success handler.
|
||||
*/
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_before_handle_payment_success',
|
||||
function( WC_Order $wc_order ) use ( $c ) {
|
||||
$subscription_helper = $c->get( 'subscription.helper' );
|
||||
assert( $subscription_helper instanceof SubscriptionHelper );
|
||||
|
||||
if ( $subscription_helper->has_subscription( $wc_order->get_id() ) ) {
|
||||
$payment_token_checker = $c->get( 'saved-payment-checker.payment-token-checker' );
|
||||
assert( $payment_token_checker instanceof PaymentTokenChecker );
|
||||
|
||||
$payment_token_checker->schedule_saved_payment_check( $wc_order->get_id(), $wc_order->get_customer_id() );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Triggers a payment token check for the given order and customer id.
|
||||
*/
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
function ( int $order_id, int $customer_id, string $intent ) use ( $c ) {
|
||||
$payment_token_checker = $c->get( 'vaulting.payment-token-checker' );
|
||||
assert( $payment_token_checker instanceof PaymentTokenChecker );
|
||||
|
||||
$payment_token_checker->check_and_update( $order_id, $customer_id, $intent );
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
|
||||
/**
|
||||
* Adds email content for vaulting failure.
|
||||
*/
|
||||
add_action(
|
||||
'woocommerce_email_before_order_table',
|
||||
function( WC_Order $order ) use ( $c ) {
|
||||
$subscription_helper = $c->get( 'subscription.helper' );
|
||||
assert( $subscription_helper instanceof SubscriptionHelper );
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
assert( $logger instanceof LoggerInterface );
|
||||
|
||||
$vault_failed = $order->get_meta( PaymentTokenChecker::VAULTING_FAILED_META_KEY );
|
||||
if ( $subscription_helper->has_subscription( $order->get_id() ) && ! empty( $vault_failed ) ) {
|
||||
$logger->info( "Adding vaulting failure info to email for order #{$order->get_id()}." );
|
||||
|
||||
if ( $vault_failed === 'void_auth' ) {
|
||||
echo wp_kses_post( '<p>' . __( 'The subscription payment failed because the payment method could not be saved. Please try again with a different payment method.', 'woocommerce-paypal-payments' ) . '</p>' );
|
||||
}
|
||||
|
||||
if ( $vault_failed === 'capture_auth' ) {
|
||||
echo wp_kses_post( '<p>' . __( 'The subscription has been activated, but the payment method could not be saved. Please contact the merchant to save a payment method for automatic subscription renewal payments.', 'woocommerce-paypal-payments' ) . '</p>' );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Adds email content for vaulting changing manual renewal order.
|
||||
*/
|
||||
add_action(
|
||||
'woocommerce_email_after_order_table',
|
||||
function( WC_Order $order ) use ( $c ) {
|
||||
$subscription_helper = $c->get( 'subscription.helper' );
|
||||
assert( $subscription_helper instanceof SubscriptionHelper );
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
assert( $logger instanceof LoggerInterface );
|
||||
|
||||
$vault_failed = $order->get_meta( PaymentTokenChecker::VAULTING_FAILED_META_KEY );
|
||||
if ( $subscription_helper->has_subscription( $order->get_id() ) && ! empty( $vault_failed ) ) {
|
||||
$logger->info( "Changing subscription auto-renewal status for order #{$order->get_id()}." );
|
||||
|
||||
if ( $vault_failed === 'capture_auth' ) {
|
||||
$subscriptions = function_exists( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order( $order->get_id() ) : array();
|
||||
foreach ( $subscriptions as $subscription ) {
|
||||
$subscription->set_requires_manual_renewal( true );
|
||||
$subscription->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ namespace WooCommerce\PayPalCommerce\Subscription\Helper;
|
|||
|
||||
use WC_Product;
|
||||
use WC_Product_Subscription_Variation;
|
||||
use WC_Subscriptions;
|
||||
use WC_Subscriptions_Product;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
|
@ -120,7 +121,7 @@ class SubscriptionHelper {
|
|||
*/
|
||||
public function plugin_is_active(): bool {
|
||||
|
||||
return class_exists( \WC_Subscriptions::class );
|
||||
return class_exists( WC_Subscriptions::class ) && class_exists( WC_Subscriptions_Product::class );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Subscription;
|
|||
use ActionScheduler_Store;
|
||||
use Exception;
|
||||
use WC_Product;
|
||||
use WC_Product_Subscription;
|
||||
use WC_Product_Subscription_Variation;
|
||||
use WC_Product_Variable;
|
||||
use WC_Product_Variable_Subscription;
|
||||
|
@ -194,7 +195,22 @@ class SubscriptionModule implements ModuleInterface {
|
|||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
$post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) );
|
||||
$product = wc_get_product( $post_id );
|
||||
if ( ! ( is_a( $product, WC_Product::class ) || is_a( $product, WC_Product_Subscription_Variation::class ) ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) {
|
||||
if ( ! ( is_a( $product, WC_Product::class ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subscriptions_helper = $c->get( 'subscription.helper' );
|
||||
assert( $subscriptions_helper instanceof SubscriptionHelper );
|
||||
|
||||
if (
|
||||
! $subscriptions_helper->plugin_is_active()
|
||||
|| ! (
|
||||
is_a( $product, WC_Product_Subscription::class )
|
||||
|| is_a( $product, WC_Product_Variable_Subscription::class )
|
||||
|| is_a( $product, WC_Product_Subscription_Variation::class )
|
||||
)
|
||||
|| ! WC_Subscriptions_Product::is_subscription( $product )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -210,6 +226,14 @@ class SubscriptionModule implements ModuleInterface {
|
|||
$products = array( $this->set_product_config( $product ) );
|
||||
if ( $product->get_type() === 'variable-subscription' ) {
|
||||
$products = array();
|
||||
|
||||
/**
|
||||
* Suppress pslam.
|
||||
*
|
||||
* @psalm-suppress TypeDoesNotContainType
|
||||
*
|
||||
* WC_Product_Variable_Subscription extends WC_Product_Variable.
|
||||
*/
|
||||
assert( $product instanceof WC_Product_Variable );
|
||||
$available_variations = $product->get_available_variations();
|
||||
foreach ( $available_variations as $variation ) {
|
||||
|
@ -541,8 +565,13 @@ class SubscriptionModule implements ModuleInterface {
|
|||
*/
|
||||
function( $variation_id ) use ( $c ) {
|
||||
$wcsnonce_save_variations = wc_clean( wp_unslash( $_POST['_wcsnonce_save_variations'] ?? '' ) );
|
||||
|
||||
$subscriptions_helper = $c->get( 'subscription.helper' );
|
||||
assert( $subscriptions_helper instanceof SubscriptionHelper );
|
||||
|
||||
if (
|
||||
! WC_Subscriptions_Product::is_subscription( $variation_id )
|
||||
! $subscriptions_helper->plugin_is_active()
|
||||
|| ! WC_Subscriptions_Product::is_subscription( $variation_id )
|
||||
|| ! is_string( $wcsnonce_save_variations )
|
||||
|| ! wp_verify_nonce( $wcsnonce_save_variations, 'wcs_subscription_variations' )
|
||||
) {
|
||||
|
@ -568,55 +597,60 @@ class SubscriptionModule implements ModuleInterface {
|
|||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function( $id, $subscription ) use ( $c ) {
|
||||
function( $id, $post ) use ( $c ) {
|
||||
$subscription = wcs_get_subscription( $id );
|
||||
if ( ! is_a( $subscription, WC_Subscription::class ) ) {
|
||||
return;
|
||||
}
|
||||
$subscription_id = $subscription->get_meta( 'ppcp_subscription' ) ?? '';
|
||||
if ( $subscription_id ) {
|
||||
$subscriptions_endpoint = $c->get( 'api.endpoint.billing-subscriptions' );
|
||||
assert( $subscriptions_endpoint instanceof BillingSubscriptions );
|
||||
if ( ! $subscription_id ) {
|
||||
return;
|
||||
}
|
||||
$subscriptions_endpoint = $c->get( 'api.endpoint.billing-subscriptions' );
|
||||
assert( $subscriptions_endpoint instanceof BillingSubscriptions );
|
||||
|
||||
if ( $subscription->get_status() === 'cancelled' ) {
|
||||
try {
|
||||
$subscriptions_endpoint->cancel( $subscription_id );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$error = $exception->getMessage();
|
||||
if ( is_a( $exception, PayPalApiException::class ) ) {
|
||||
$error = $exception->get_details( $error );
|
||||
}
|
||||
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
$logger->error( 'Could not cancel subscription product on PayPal. ' . $error );
|
||||
if ( $subscription->get_status() === 'cancelled' ) {
|
||||
try {
|
||||
$subscriptions_endpoint->cancel( $subscription_id );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$error = $exception->getMessage();
|
||||
if ( is_a( $exception, PayPalApiException::class ) ) {
|
||||
$error = $exception->get_details( $error );
|
||||
}
|
||||
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
$logger->error( 'Could not cancel subscription product on PayPal. ' . $error );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $subscription->get_status() === 'pending-cancel' ) {
|
||||
try {
|
||||
$subscriptions_endpoint->suspend( $subscription_id );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$error = $exception->getMessage();
|
||||
if ( is_a( $exception, PayPalApiException::class ) ) {
|
||||
$error = $exception->get_details( $error );
|
||||
}
|
||||
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
$logger->error( 'Could not suspend subscription product on PayPal. ' . $error );
|
||||
if ( $subscription->get_status() === 'pending-cancel' ) {
|
||||
try {
|
||||
$subscriptions_endpoint->suspend( $subscription_id );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$error = $exception->getMessage();
|
||||
if ( is_a( $exception, PayPalApiException::class ) ) {
|
||||
$error = $exception->get_details( $error );
|
||||
}
|
||||
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
$logger->error( 'Could not suspend subscription product on PayPal. ' . $error );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $subscription->get_status() === 'active' ) {
|
||||
try {
|
||||
$current_subscription = $subscriptions_endpoint->subscription( $subscription_id );
|
||||
if ( $current_subscription->status === 'SUSPENDED' ) {
|
||||
$subscriptions_endpoint->activate( $subscription_id );
|
||||
}
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$error = $exception->getMessage();
|
||||
if ( is_a( $exception, PayPalApiException::class ) ) {
|
||||
$error = $exception->get_details( $error );
|
||||
}
|
||||
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
$logger->error( 'Could not reactivate subscription product on PayPal. ' . $error );
|
||||
if ( $subscription->get_status() === 'active' ) {
|
||||
try {
|
||||
$current_subscription = $subscriptions_endpoint->subscription( $subscription_id );
|
||||
if ( $current_subscription->status === 'SUSPENDED' ) {
|
||||
$subscriptions_endpoint->activate( $subscription_id );
|
||||
}
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$error = $exception->getMessage();
|
||||
if ( is_a( $exception, PayPalApiException::class ) ) {
|
||||
$error = $exception->get_details( $error );
|
||||
}
|
||||
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
$logger->error( 'Could not reactivate subscription product on PayPal. ' . $error );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -632,7 +666,7 @@ class SubscriptionModule implements ModuleInterface {
|
|||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function( $actions, $subscription ): array {
|
||||
if ( ! is_a( $subscription, WC_Subscription::class ) ) {
|
||||
if ( ! is_array( $actions ) || ! is_a( $subscription, WC_Subscription::class ) ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,12 +19,15 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\BillingCycleFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentPreferencesFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ProductFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ItemTrait;
|
||||
|
||||
/**
|
||||
* Class SubscriptionsApiHandler
|
||||
*/
|
||||
class SubscriptionsApiHandler {
|
||||
|
||||
use ItemTrait;
|
||||
|
||||
/**
|
||||
* Catalog products.
|
||||
*
|
||||
|
@ -111,7 +114,7 @@ class SubscriptionsApiHandler {
|
|||
*/
|
||||
public function create_product( WC_Product $product ) {
|
||||
try {
|
||||
$subscription_product = $this->products_endpoint->create( $product->get_title(), $product->get_description() );
|
||||
$subscription_product = $this->products_endpoint->create( $product->get_title(), $this->prepare_description( $product->get_description() ) );
|
||||
$product->update_meta_data( 'ppcp_subscription_product', $subscription_product->to_array() );
|
||||
$product->save();
|
||||
} catch ( RuntimeException $exception ) {
|
||||
|
@ -134,7 +137,7 @@ class SubscriptionsApiHandler {
|
|||
public function create_plan( string $plan_name, WC_Product $product ): void {
|
||||
try {
|
||||
$subscription_plan = $this->billing_plans_endpoint->create(
|
||||
$plan_name,
|
||||
$plan_name ?: $product->get_title(),
|
||||
$product->get_meta( 'ppcp_subscription_product' )['id'] ?? '',
|
||||
$this->billing_cycles( $product ),
|
||||
$this->payment_preferences_factory->from_wc_product( $product )->to_array()
|
||||
|
@ -165,7 +168,10 @@ class SubscriptionsApiHandler {
|
|||
$catalog_product = $this->products_endpoint->product( $catalog_product_id );
|
||||
$catalog_product_name = $catalog_product->name() ?: '';
|
||||
$catalog_product_description = $catalog_product->description() ?: '';
|
||||
if ( $catalog_product_name !== $product->get_title() || $catalog_product_description !== $product->get_description() ) {
|
||||
|
||||
$wc_product_description = $this->prepare_description( $product->get_description() ) ?: $product->get_title();
|
||||
|
||||
if ( $catalog_product_name !== $product->get_title() || $catalog_product_description !== $wc_product_description ) {
|
||||
$data = array();
|
||||
if ( $catalog_product_name !== $product->get_title() ) {
|
||||
$data[] = (object) array(
|
||||
|
@ -174,11 +180,11 @@ class SubscriptionsApiHandler {
|
|||
'value' => $product->get_title(),
|
||||
);
|
||||
}
|
||||
if ( $catalog_product_description !== $product->get_description() ) {
|
||||
if ( $catalog_product_description !== $wc_product_description ) {
|
||||
$data[] = (object) array(
|
||||
'op' => 'replace',
|
||||
'path' => '/description',
|
||||
'value' => $product->get_description(),
|
||||
'value' => $wc_product_description,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -208,7 +214,7 @@ class SubscriptionsApiHandler {
|
|||
$subscription_plan = $this->billing_plans_endpoint->plan( $subscription_plan_id );
|
||||
|
||||
$price = $subscription_plan->billing_cycles()[0]->pricing_scheme()['fixed_price']['value'] ?? '';
|
||||
if ( $price && round( $price, 2 ) !== round( (float) $product->get_price(), 2 ) ) {
|
||||
if ( $price && round( (float) $price, 2 ) !== round( (float) $product->get_price(), 2 ) ) {
|
||||
$this->billing_plans_endpoint->update_pricing(
|
||||
$subscription_plan_id,
|
||||
$this->billing_cycle_factory->from_wc_product( $product )
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
File diff suppressed because one or more lines are too long
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"name": "ppcp-vaulting",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"main": "resources/js/myaccount-payments.js",
|
||||
"browserslist": [
|
||||
"> 0.5%",
|
||||
"Safari >= 8",
|
||||
"Chrome >= 41",
|
||||
"Firefox >= 43",
|
||||
"Edge >= 14"
|
||||
],
|
||||
"dependencies": {
|
||||
"core-js": "^3.25.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19",
|
||||
"@babel/preset-env": "^7.19",
|
||||
"babel-loader": "^8.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"sass": "^1.42.1",
|
||||
"sass-loader": "^12.1.0",
|
||||
"webpack": "^5.76",
|
||||
"webpack-cli": "^4.10"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
||||
"watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch",
|
||||
"dev": "cross-env BABEL_ENV=default webpack --watch"
|
||||
}
|
||||
}
|
|
@ -23,17 +23,6 @@ return array(
|
|||
$endpoint = $container->get( 'api.endpoint.payment-token' );
|
||||
return new PaymentTokenRepository( $factory, $endpoint );
|
||||
},
|
||||
'vaulting.payment-token-checker' => function( ContainerInterface $container ) : PaymentTokenChecker {
|
||||
return new PaymentTokenChecker(
|
||||
$container->get( 'vaulting.repository.payment-token' ),
|
||||
$container->get( 'api.repository.order' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'wcgateway.processor.authorized-payments' ),
|
||||
$container->get( 'api.endpoint.payments' ),
|
||||
$container->get( 'api.endpoint.payment-token' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'vaulting.customer-approval-listener' => function( ContainerInterface $container ) : CustomerApprovalListener {
|
||||
return new CustomerApprovalListener(
|
||||
$container->get( 'api.endpoint.payment-token' ),
|
||||
|
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use WC_Payment_Token;
|
||||
use WC_Payment_Tokens;
|
||||
|
@ -16,9 +17,6 @@ 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 Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
@ -68,19 +66,6 @@ class VaultingModule implements ModuleInterface {
|
|||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
function ( int $order_id, int $customer_id, string $intent ) use ( $container ) {
|
||||
$payment_token_checker = $container->get( 'vaulting.payment-token-checker' );
|
||||
assert( $payment_token_checker instanceof PaymentTokenChecker );
|
||||
$payment_token_checker->check_and_update( $order_id, $customer_id, $intent );
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
|
||||
$this->filterFailedVaultingEmailsForSubscriptionOrders( $container );
|
||||
|
||||
add_filter(
|
||||
'woocommerce_payment_token_class',
|
||||
/**
|
||||
|
@ -285,95 +270,8 @@ class VaultingModule implements ModuleInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the emails when vaulting is failed for subscription orders.
|
||||
*
|
||||
* @param ContainerInterface $container A services container instance.
|
||||
* @throws NotFoundException When service could not be found.
|
||||
*/
|
||||
protected function filterFailedVaultingEmailsForSubscriptionOrders( ContainerInterface $container ):void {
|
||||
add_action(
|
||||
'woocommerce_email_before_order_table',
|
||||
function( WC_Order $order ) use ( $container ) {
|
||||
/**
|
||||
* The SubscriptionHelper.
|
||||
*
|
||||
* @var SubscriptionHelper $subscription_helper
|
||||
*/
|
||||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface $logger
|
||||
*/
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
|
||||
$vault_failed = $order->get_meta( PaymentTokenChecker::VAULTING_FAILED_META_KEY );
|
||||
if ( $subscription_helper->has_subscription( $order->get_id() ) && ! empty( $vault_failed ) ) {
|
||||
$logger->info( "Adding vaulting failure info to email for order #{$order->get_id()}." );
|
||||
|
||||
if ( $vault_failed === 'void_auth' ) {
|
||||
echo wp_kses_post( '<p>' . __( 'The subscription payment failed because the payment method could not be saved. Please try again with a different payment method.', 'woocommerce-paypal-payments' ) . '</p>' );
|
||||
}
|
||||
|
||||
if ( $vault_failed === 'capture_auth' ) {
|
||||
echo wp_kses_post( '<p>' . __( 'The subscription has been activated, but the payment method could not be saved. Please contact the merchant to save a payment method for automatic subscription renewal payments.', 'woocommerce-paypal-payments' ) . '</p>' );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_email_after_order_table',
|
||||
function( WC_Order $order ) use ( $container ) {
|
||||
/**
|
||||
* The SubscriptionHelper.
|
||||
*
|
||||
* @var SubscriptionHelper $subscription_helper
|
||||
*/
|
||||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface $logger
|
||||
*/
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
|
||||
$vault_failed = $order->get_meta( PaymentTokenChecker::VAULTING_FAILED_META_KEY );
|
||||
if ( $subscription_helper->has_subscription( $order->get_id() ) && ! empty( $vault_failed ) ) {
|
||||
$logger->info( "Changing subscription auto-renewal status for order #{$order->get_id()}." );
|
||||
|
||||
if ( $vault_failed === 'capture_auth' ) {
|
||||
$subscriptions = function_exists( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order( $order->get_id() ) : array();
|
||||
foreach ( $subscriptions as $subscription ) {
|
||||
$subscription->set_requires_manual_renewal( true );
|
||||
$subscription->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getKey() { }
|
||||
|
||||
/**
|
||||
* Check if is payments page.
|
||||
*
|
||||
* @return bool Whethen page is payments or not.
|
||||
*/
|
||||
private function is_payments_page(): bool {
|
||||
global $wp;
|
||||
$request = explode( '/', wp_parse_url( $wp->request, PHP_URL_PATH ) );
|
||||
if ( end( $request ) === 'ppcp-paypal-payment-tokens' ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
11
modules/ppcp-wc-gateway/resources/css/common.scss
Normal file
11
modules/ppcp-wc-gateway/resources/css/common.scss
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
.ppcp-field-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ppcp-field-disabled {
|
||||
cursor: not-allowed;
|
||||
-webkit-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.5;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
|
||||
class SubElementsHandler {
|
||||
constructor(element, options) {
|
||||
const fieldSelector = 'input, select, textarea';
|
||||
|
||||
this.element = element;
|
||||
this.values = options.values;
|
||||
this.elements = options.elements;
|
||||
|
||||
this.elementsSelector = this.elements.join(',');
|
||||
|
||||
this.input = jQuery(this.element).is(fieldSelector)
|
||||
? this.element
|
||||
: jQuery(this.element).find(fieldSelector).get(0);
|
||||
|
||||
this.updateElementsVisibility();
|
||||
|
||||
jQuery(this.input).change(() => {
|
||||
this.updateElementsVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
updateElementsVisibility() {
|
||||
const $elements = jQuery(this.elementsSelector);
|
||||
|
||||
let value = this.getValue(this.input);
|
||||
value = (value !== null ? value.toString() : value);
|
||||
|
||||
if (this.values.indexOf(value) !== -1) {
|
||||
$elements.show();
|
||||
} else {
|
||||
$elements.hide();
|
||||
}
|
||||
}
|
||||
|
||||
getValue(element) {
|
||||
const $el = jQuery(element);
|
||||
|
||||
if ($el.is(':checkbox') || $el.is(':radio')) {
|
||||
if ($el.is(':checked')) {
|
||||
return $el.val();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return $el.val();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SubElementsHandler;
|
|
@ -1,10 +1,28 @@
|
|||
import DisplayManager from "./common/display-manager/DisplayManager";
|
||||
import moveWrappedElements from "./common/wrapped-elements";
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
|
||||
// Wait for current execution context to end.
|
||||
setTimeout(function () {
|
||||
moveWrappedElements();
|
||||
}, 0);
|
||||
|
||||
// Initialize DisplayManager.
|
||||
const displayManager = new DisplayManager();
|
||||
|
||||
jQuery( '*[data-ppcp-display]' ).each( (index, el) => {
|
||||
const rules = jQuery(el).data('ppcpDisplay');
|
||||
|
||||
console.log('rules', rules);
|
||||
|
||||
for (const rule of rules) {
|
||||
displayManager.addRule(rule);
|
||||
}
|
||||
});
|
||||
|
||||
displayManager.register();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import ElementAction from "./action/ElementAction";
|
||||
|
||||
class ActionFactory {
|
||||
static make(actionConfig) {
|
||||
switch (actionConfig.type) {
|
||||
case 'element':
|
||||
return new ElementAction(actionConfig);
|
||||
}
|
||||
|
||||
throw new Error('[ActionFactory] Unknown action: ' + actionConfig.type);
|
||||
}
|
||||
}
|
||||
|
||||
export default ActionFactory;
|
|
@ -0,0 +1,17 @@
|
|||
import ElementCondition from "./condition/ElementCondition";
|
||||
import BoolCondition from "./condition/BoolCondition";
|
||||
|
||||
class ConditionFactory {
|
||||
static make(conditionConfig, triggerUpdate) {
|
||||
switch (conditionConfig.type) {
|
||||
case 'element':
|
||||
return new ElementCondition(conditionConfig, triggerUpdate);
|
||||
case 'bool':
|
||||
return new BoolCondition(conditionConfig, triggerUpdate);
|
||||
}
|
||||
|
||||
throw new Error('[ConditionFactory] Unknown condition: ' + conditionConfig.type);
|
||||
}
|
||||
}
|
||||
|
||||
export default ConditionFactory;
|
|
@ -0,0 +1,32 @@
|
|||
import Rule from "./Rule";
|
||||
|
||||
class DisplayManager {
|
||||
|
||||
constructor() {
|
||||
this.rules = {};
|
||||
this.ruleStatus = {}; // The current status for each rule. Maybe not necessary, for now just for logging.
|
||||
|
||||
document.ppcpDisplayManagerLog = () => {
|
||||
console.log('DisplayManager', this);
|
||||
}
|
||||
}
|
||||
|
||||
addRule(ruleConfig) {
|
||||
const updateStatus = () => {
|
||||
this.ruleStatus[ruleConfig.key] = this.rules[ruleConfig.key].status;
|
||||
console.log('ruleStatus', this.ruleStatus);
|
||||
}
|
||||
|
||||
this.rules[ruleConfig.key] = new Rule(ruleConfig, updateStatus.bind(this));
|
||||
console.log('Rule', this.rules[ruleConfig.key]);
|
||||
}
|
||||
|
||||
register() {
|
||||
this.ruleStatus = {};
|
||||
for (const [key, rule] of Object.entries(this.rules)) {
|
||||
rule.register();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DisplayManager;
|
|
@ -0,0 +1,68 @@
|
|||
import ConditionFactory from "./ConditionFactory";
|
||||
import ActionFactory from "./ActionFactory";
|
||||
|
||||
class Rule {
|
||||
|
||||
constructor(config, triggerUpdate) {
|
||||
this.config = config;
|
||||
this.conditions = {};
|
||||
this.actions = {};
|
||||
this.triggerUpdate = triggerUpdate;
|
||||
this.status = null;
|
||||
|
||||
const updateStatus = this.updateStatus.bind(this);
|
||||
for (const conditionConfig of this.config.conditions) {
|
||||
const condition = ConditionFactory.make(conditionConfig, updateStatus);
|
||||
this.conditions[condition.key] = condition;
|
||||
|
||||
console.log('Condition', condition);
|
||||
}
|
||||
|
||||
for (const actionConfig of this.config.actions) {
|
||||
const action = ActionFactory.make(actionConfig);
|
||||
this.actions[action.key] = action;
|
||||
|
||||
console.log('Action', action);
|
||||
}
|
||||
}
|
||||
|
||||
get key() {
|
||||
return this.config.key;
|
||||
}
|
||||
|
||||
updateStatus(forceRunActions = false) {
|
||||
let status = true;
|
||||
|
||||
for (const [key, condition] of Object.entries(this.conditions)) {
|
||||
status &= condition.status;
|
||||
}
|
||||
|
||||
if (status !== this.status) {
|
||||
this.status = status;
|
||||
this.triggerUpdate();
|
||||
this.runActions();
|
||||
} else if (forceRunActions) {
|
||||
this.runActions();
|
||||
}
|
||||
}
|
||||
|
||||
runActions() {
|
||||
for (const [key, action] of Object.entries(this.actions)) {
|
||||
action.run(this.status);
|
||||
}
|
||||
}
|
||||
|
||||
register() {
|
||||
for (const [key, condition] of Object.entries(this.conditions)) {
|
||||
condition.register(this.updateStatus.bind(this));
|
||||
}
|
||||
for (const [key, action] of Object.entries(this.actions)) {
|
||||
action.register();
|
||||
}
|
||||
|
||||
this.updateStatus(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Rule;
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
class BaseAction {
|
||||
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
get key() {
|
||||
return this.config.key;
|
||||
}
|
||||
|
||||
register() {
|
||||
// To override.
|
||||
}
|
||||
|
||||
run(status) {
|
||||
// To override.
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseAction;
|
|
@ -0,0 +1,35 @@
|
|||
import BaseAction from "./BaseAction";
|
||||
|
||||
class ElementAction extends BaseAction {
|
||||
|
||||
run(status) {
|
||||
|
||||
if (status) {
|
||||
if (this.config.action === 'visible') {
|
||||
jQuery(this.config.selector).removeClass('ppcp-field-hidden');
|
||||
}
|
||||
if (this.config.action === 'enable') {
|
||||
jQuery(this.config.selector).removeClass('ppcp-field-disabled')
|
||||
.off('mouseup')
|
||||
.find('> *')
|
||||
.css('pointer-events', '');
|
||||
}
|
||||
} else {
|
||||
if (this.config.action === 'visible') {
|
||||
jQuery(this.config.selector).addClass('ppcp-field-hidden');
|
||||
}
|
||||
if (this.config.action === 'enable') {
|
||||
jQuery(this.config.selector).addClass('ppcp-field-disabled')
|
||||
.on('mouseup', function(event) {
|
||||
event.stopImmediatePropagation();
|
||||
})
|
||||
.find('> *')
|
||||
.css('pointer-events', 'none');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ElementAction;
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
class BaseCondition {
|
||||
|
||||
constructor(config, triggerUpdate) {
|
||||
this.config = config;
|
||||
this.status = false;
|
||||
this.triggerUpdate = triggerUpdate;
|
||||
}
|
||||
|
||||
get key() {
|
||||
return this.config.key;
|
||||
}
|
||||
|
||||
register() {
|
||||
// To override.
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseCondition;
|
|
@ -0,0 +1,15 @@
|
|||
import BaseCondition from "./BaseCondition";
|
||||
|
||||
class BoolCondition extends BaseCondition {
|
||||
|
||||
register() {
|
||||
this.status = this.check();
|
||||
}
|
||||
|
||||
check() {
|
||||
return !! this.config.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BoolCondition;
|
|
@ -0,0 +1,27 @@
|
|||
import BaseCondition from "./BaseCondition";
|
||||
import {inputValue} from "../../../helper/form";
|
||||
|
||||
class ElementCondition extends BaseCondition {
|
||||
|
||||
register() {
|
||||
jQuery(document).on('change', this.config.selector, () => {
|
||||
const status = this.check();
|
||||
if (status !== this.status) {
|
||||
this.status = status;
|
||||
this.triggerUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
this.status = this.check();
|
||||
}
|
||||
|
||||
check() {
|
||||
let value = inputValue(this.config.selector);
|
||||
value = (value !== null ? value.toString() : value);
|
||||
|
||||
return this.config.value === value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ElementCondition;
|
|
@ -4,7 +4,6 @@ import Renderer from '../../../ppcp-button/resources/js/modules/Renderer/Rendere
|
|||
import MessageRenderer from "../../../ppcp-button/resources/js/modules/Renderer/MessageRenderer";
|
||||
import {setVisibleByClass, isVisible} from "../../../ppcp-button/resources/js/modules/Helper/Hiding";
|
||||
import widgetBuilder from "../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder";
|
||||
import SubElementsHandler from "./SettingsHandler/SubElementsHandler";
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
|
@ -173,11 +172,16 @@ document.addEventListener(
|
|||
|
||||
function createMessagesPreview(settingsCallback) {
|
||||
const render = (settings) => {
|
||||
const wrapper = document.querySelector(settings.wrapper);
|
||||
let wrapper = document.querySelector(settings.wrapper);
|
||||
if (!wrapper) {
|
||||
return;
|
||||
}
|
||||
wrapper.innerHTML = '';
|
||||
// looks like .innerHTML = '' is not enough, PayPal somehow renders with old style
|
||||
const parent = wrapper.parentElement;
|
||||
parent.removeChild(wrapper);
|
||||
wrapper = document.createElement('div');
|
||||
wrapper.setAttribute('id', settings.wrapper.replace('#', ''));
|
||||
parent.appendChild(wrapper);
|
||||
|
||||
const messageRenderer = new MessageRenderer(settings);
|
||||
|
||||
|
@ -270,7 +274,7 @@ document.addEventListener(
|
|||
}, 1000));
|
||||
|
||||
loadPaypalScript(oldScriptSettings, () => {
|
||||
const payLaterMessagingLocations = ['product', 'cart', 'checkout', 'general'];
|
||||
const payLaterMessagingLocations = ['product', 'cart', 'checkout', 'shop', 'home', 'general'];
|
||||
const paypalButtonLocations = ['product', 'cart', 'checkout', 'mini-cart', 'general'];
|
||||
|
||||
paypalButtonLocations.forEach((location) => {
|
||||
|
@ -308,16 +312,5 @@ document.addEventListener(
|
|||
createButtonPreview(() => getButtonDefaultSettings('#ppcpPayLaterButtonPreview'));
|
||||
});
|
||||
}
|
||||
|
||||
// Generic behaviours, can be moved to common.js once it's on trunk branch.
|
||||
jQuery( '*[data-ppcp-handlers]' ).each( (index, el) => {
|
||||
const handlers = jQuery(el).data('ppcpHandlers');
|
||||
for (const handlerConfig of handlers) {
|
||||
new {
|
||||
SubElementsHandler: SubElementsHandler
|
||||
}[handlerConfig.handler](el, handlerConfig.options)
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
|
|
13
modules/ppcp-wc-gateway/resources/js/helper/form.js
Normal file
13
modules/ppcp-wc-gateway/resources/js/helper/form.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export const inputValue = (element) => {
|
||||
const $el = jQuery(element);
|
||||
|
||||
if ($el.is(':checkbox') || $el.is(':radio')) {
|
||||
if ($el.is(':checked')) {
|
||||
return $el.val();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return $el.val();
|
||||
}
|
||||
}
|
|
@ -11,21 +11,18 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingAgreementsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesDisclaimers;
|
||||
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\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Admin\FeesRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Admin\OrderTablePaymentStatusColumn;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Admin\PaymentStatusOrderDetail;
|
||||
|
@ -35,6 +32,9 @@ use WooCommerce\PayPalCommerce\WcGateway\Checkout\CheckoutPayPalAddressPreset;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Checkout\DisableGateways;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Cli\SettingsCommand;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSessionId;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSourceWebsiteId;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
|
@ -42,15 +42,13 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\GatewayRepository;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXO;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSessionId;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSourceWebsiteId;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSourceFactory;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\RefundFeesUpdater;
|
||||
|
@ -202,10 +200,14 @@ return array(
|
|||
return $ppcp_tab ? $ppcp_tab : $section;
|
||||
},
|
||||
|
||||
'wcgateway.settings' => static function ( ContainerInterface $container ): Settings {
|
||||
$default_button_locations = $container->get( 'wcgateway.button.default-locations' );
|
||||
return new Settings( $default_button_locations );
|
||||
},
|
||||
'wcgateway.settings' => SingletonDecorator::make(
|
||||
static function ( ContainerInterface $container ): Settings {
|
||||
return new Settings(
|
||||
$container->get( 'wcgateway.button.default-locations' ),
|
||||
$container->get( 'wcgateway.settings.dcc-gateway-title.default' )
|
||||
);
|
||||
}
|
||||
),
|
||||
'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice {
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
|
@ -441,7 +443,7 @@ return array(
|
|||
assert( $subscription_helper instanceof SubscriptionHelper );
|
||||
|
||||
$fields = array(
|
||||
'checkout_settings_heading' => array(
|
||||
'checkout_settings_heading' => array(
|
||||
'heading' => __( 'Standard Payments Settings', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'ppcp-heading',
|
||||
'screens' => array(
|
||||
|
@ -451,7 +453,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'title' => array(
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'description' => __(
|
||||
|
@ -467,7 +469,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'dcc_enabled' => array(
|
||||
'dcc_enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Once enabled, the Credit Card option will show up in the checkout.', 'woocommerce-paypal-payments' ),
|
||||
|
@ -482,14 +484,14 @@ return array(
|
|||
State::STATE_ONBOARDED,
|
||||
),
|
||||
),
|
||||
'dcc_gateway_title' => array(
|
||||
'dcc_gateway_title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'description' => __(
|
||||
'This controls the title which the user sees during checkout.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'default' => __( 'Credit Cards', 'woocommerce-paypal-payments' ),
|
||||
'default' => $container->get( 'wcgateway.settings.dcc-gateway-title.default' ),
|
||||
'desc_tip' => true,
|
||||
'screens' => array(
|
||||
State::STATE_ONBOARDED,
|
||||
|
@ -499,7 +501,7 @@ return array(
|
|||
),
|
||||
'gateway' => 'dcc',
|
||||
),
|
||||
'description' => array(
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
|
@ -518,7 +520,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'intent' => array(
|
||||
'intent' => array(
|
||||
'title' => __( 'Intent', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
|
@ -540,7 +542,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'capture_on_status_change' => array(
|
||||
'capture_on_status_change' => array(
|
||||
'title' => __( 'Capture On Status Change', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'default' => false,
|
||||
|
@ -557,7 +559,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'capture_for_virtual_only' => array(
|
||||
'capture_for_virtual_only' => array(
|
||||
'title' => __( 'Capture Virtual-Only Orders ', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'default' => false,
|
||||
|
@ -574,7 +576,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'payee_preferred' => array(
|
||||
'payee_preferred' => array(
|
||||
'title' => __( 'Instant Payments ', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'default' => false,
|
||||
|
@ -591,7 +593,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'brand_name' => array(
|
||||
'brand_name' => array(
|
||||
'title' => __( 'Brand Name', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => get_bloginfo( 'name' ),
|
||||
|
@ -607,7 +609,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'landing_page' => array(
|
||||
'landing_page' => array(
|
||||
'title' => __( 'Landing Page', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
|
@ -629,7 +631,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'alternative_payment_methods' => array(
|
||||
'alternative_payment_methods' => array(
|
||||
'heading' => __( 'Alternative Payment Methods', 'woocommerce-paypal-payments' ),
|
||||
'description' => sprintf(
|
||||
// translators: %1$s, %2$s, %3$s and %4$s are a link tags.
|
||||
|
@ -645,7 +647,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'disable_funding' => array(
|
||||
'disable_funding' => array(
|
||||
'title' => __( 'Disable Alternative Payment Methods', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'ppcp-multiselect',
|
||||
'class' => array(),
|
||||
|
@ -669,7 +671,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'card_billing_data_mode' => array(
|
||||
'card_billing_data_mode' => array(
|
||||
'title' => __( 'Send checkout billing data to card fields', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
|
@ -689,7 +691,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => array( 'paypal', CardButtonGateway::ID ),
|
||||
),
|
||||
'allow_card_button_gateway' => array(
|
||||
'allow_card_button_gateway' => array(
|
||||
'title' => __( 'Create gateway for Standard Card Button', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'desc_tip' => true,
|
||||
|
@ -703,7 +705,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'disable_cards' => array(
|
||||
'disable_cards' => array(
|
||||
'title' => __( 'Disable specific credit cards', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'ppcp-multiselect',
|
||||
'class' => array(),
|
||||
|
@ -731,7 +733,7 @@ return array(
|
|||
),
|
||||
'gateway' => 'dcc',
|
||||
),
|
||||
'card_icons' => array(
|
||||
'card_icons' => array(
|
||||
'title' => __( 'Show logo of the following credit cards', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'ppcp-multiselect',
|
||||
'class' => array(),
|
||||
|
@ -761,7 +763,7 @@ return array(
|
|||
),
|
||||
'gateway' => 'dcc',
|
||||
),
|
||||
'vault_enabled_dcc' => array(
|
||||
'vault_enabled_dcc' => array(
|
||||
'title' => __( 'Vaulting', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'desc_tip' => true,
|
||||
|
@ -780,7 +782,7 @@ return array(
|
|||
'gateway' => 'dcc',
|
||||
'input_class' => $container->get( 'wcgateway.helper.vaulting-scope' ) ? array() : array( 'ppcp-disabled-checkbox' ),
|
||||
),
|
||||
'3d_secure_heading' => array(
|
||||
'3d_secure_heading' => array(
|
||||
'heading' => __( '3D Secure', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'ppcp-heading',
|
||||
'description' => wp_kses_post(
|
||||
|
@ -808,7 +810,7 @@ return array(
|
|||
),
|
||||
'gateway' => 'dcc',
|
||||
),
|
||||
'3d_secure_contingency' => array(
|
||||
'3d_secure_contingency' => array(
|
||||
'title' => __( 'Contingency for 3D Secure', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'description' => sprintf(
|
||||
|
@ -836,7 +838,7 @@ return array(
|
|||
),
|
||||
'gateway' => 'dcc',
|
||||
),
|
||||
'paypal_saved_payments' => array(
|
||||
'paypal_saved_payments' => array(
|
||||
'heading' => __( 'Saved payments', 'woocommerce-paypal-payments' ),
|
||||
'description' => sprintf(
|
||||
// translators: %1$s, %2$s, %3$s and %4$s are a link tags.
|
||||
|
@ -854,8 +856,8 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'subscriptions_mode' => $container->get( 'wcgateway.settings.fields.subscriptions_mode' ),
|
||||
'vault_enabled' => array(
|
||||
'subscriptions_mode' => $container->get( 'wcgateway.settings.fields.subscriptions_mode' ),
|
||||
'vault_enabled' => array(
|
||||
'title' => __( 'Vaulting', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'desc_tip' => true,
|
||||
|
@ -874,26 +876,6 @@ return array(
|
|||
'gateway' => 'paypal',
|
||||
'input_class' => $container->get( 'wcgateway.helper.vaulting-scope' ) ? array() : array( 'ppcp-disabled-checkbox' ),
|
||||
),
|
||||
'subscription_behavior_when_vault_fails' => array(
|
||||
'title' => __( 'Subscription capture behavior if Vault fails', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'classes' => $subscription_helper->plugin_is_active() ? array() : array( 'hide' ),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'void_auth',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'By default, subscription payments are captured only when saving the payment method was successful. Without a saved payment method, automatic renewal payments are not possible.', 'woocommerce-paypal-payments' ),
|
||||
'description_with_tip' => __( 'Determines whether authorized payments for subscription orders are captured or voided if there is no saved payment method. This only applies when the intent Capture is used for the subscription order.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'void_auth' => __( 'Void authorization & fail the order/subscription', 'woocommerce-paypal-payments' ),
|
||||
'capture_auth' => __( 'Capture authorized payment & set subscription to Manual Renewal', 'woocommerce-paypal-payments' ),
|
||||
'capture_auth_ignore' => __( 'Capture authorized payment & disregard missing payment method', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => array( 'paypal' ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( ! $subscription_helper->plugin_is_active() ) {
|
||||
|
@ -953,6 +935,7 @@ return array(
|
|||
'wcgateway.extra-funding-sources' => static function( ContainerInterface $container ): array {
|
||||
return array(
|
||||
'googlepay' => _x( 'Google Pay', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'applepay' => _x( 'Apple Pay', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -1207,6 +1190,10 @@ return array(
|
|||
return $vaulting_label;
|
||||
},
|
||||
|
||||
'wcgateway.settings.dcc-gateway-title.default' => static function ( ContainerInterface $container ): string {
|
||||
return __( 'Debit & Credit Cards', 'woocommerce-paypal-payments' );
|
||||
},
|
||||
|
||||
'wcgateway.settings.card_billing_data_mode.default' => static function ( ContainerInterface $container ): string {
|
||||
return $container->get( 'api.shop.is-latin-america' ) ? CardBillingMode::MINIMAL_INPUT : CardBillingMode::USE_WC;
|
||||
},
|
||||
|
@ -1367,7 +1354,13 @@ return array(
|
|||
'wcgateway.settings.pay-later.messaging-locations' => static function( ContainerInterface $container ): array {
|
||||
$button_locations = $container->get( 'wcgateway.button.locations' );
|
||||
unset( $button_locations['mini-cart'] );
|
||||
return $button_locations;
|
||||
return array_merge(
|
||||
$button_locations,
|
||||
array(
|
||||
'shop' => __( 'Shop', 'woocommerce-paypal-payments' ),
|
||||
'home' => __( 'Home', 'woocommerce-paypal-payments' ),
|
||||
)
|
||||
);
|
||||
},
|
||||
'wcgateway.button.default-locations' => static function( ContainerInterface $container ): array {
|
||||
return array_keys( $container->get( 'wcgateway.settings.pay-later.messaging-locations' ) );
|
||||
|
@ -1419,4 +1412,10 @@ return array(
|
|||
$container->get( 'wcgateway.settings' )
|
||||
);
|
||||
},
|
||||
'wcgateway.display-manager' => SingletonDecorator::make(
|
||||
static function( ContainerInterface $container ): DisplayManager {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new DisplayManager( $settings );
|
||||
}
|
||||
),
|
||||
);
|
||||
|
|
|
@ -229,6 +229,13 @@ class SettingsPageAssets {
|
|||
* Register assets for PayPal admin pages.
|
||||
*/
|
||||
private function register_admin_assets(): void {
|
||||
wp_enqueue_style(
|
||||
'ppcp-admin-common',
|
||||
trailingslashit( $this->module_url ) . 'assets/css/common.css',
|
||||
array(),
|
||||
$this->version
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'ppcp-admin-common',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/common.js',
|
||||
|
|
|
@ -299,9 +299,7 @@ class CardButtonGateway extends \WC_Payment_Gateway {
|
|||
);
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
||||
}
|
||||
do_action( 'woocommerce_paypal_payments_before_handle_payment_success', $wc_order );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalApiException $error ) {
|
||||
|
|
|
@ -180,10 +180,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
'products',
|
||||
);
|
||||
|
||||
if (
|
||||
( $this->config->has( 'vault_enabled_dcc' ) && $this->config->get( 'vault_enabled_dcc' ) )
|
||||
|| ( $this->config->has( 'subscriptions_mode' ) && $this->config->get( 'subscriptions_mode' ) === 'subscriptions_api' )
|
||||
) {
|
||||
if ( $this->config->has( 'vault_enabled_dcc' ) && $this->config->get( 'vault_enabled_dcc' ) ) {
|
||||
array_push(
|
||||
$this->supports,
|
||||
'subscriptions',
|
||||
|
@ -399,9 +396,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
);
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
||||
}
|
||||
do_action( 'woocommerce_paypal_payments_before_handle_payment_success', $wc_order );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalApiException $error ) {
|
||||
|
|
|
@ -543,6 +543,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
|
@ -555,9 +556,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
);
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
||||
}
|
||||
do_action( 'woocommerce_paypal_payments_before_handle_payment_success', $wc_order );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalApiException $error ) {
|
||||
|
|
|
@ -33,32 +33,6 @@ trait ProcessPaymentTrait {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled the vaulted payment check.
|
||||
*
|
||||
* @param int $wc_order_id The WC order ID.
|
||||
* @param int $customer_id The customer ID.
|
||||
*/
|
||||
protected function schedule_saved_payment_check( int $wc_order_id, int $customer_id ): void {
|
||||
$timestamp = 3 * MINUTE_IN_SECONDS;
|
||||
if (
|
||||
$this->config->has( 'subscription_behavior_when_vault_fails' )
|
||||
&& $this->config->get( 'subscription_behavior_when_vault_fails' ) === 'capture_auth'
|
||||
) {
|
||||
$timestamp = 0;
|
||||
}
|
||||
|
||||
as_schedule_single_action(
|
||||
time() + $timestamp,
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
array(
|
||||
'order_id' => $wc_order_id,
|
||||
'customer_id' => $customer_id,
|
||||
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the payment failure.
|
||||
*
|
||||
|
@ -77,6 +51,7 @@ trait ProcessPaymentTrait {
|
|||
}
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
WC()->session->set( 'ppcp_subscription_id', '' );
|
||||
|
||||
wc_add_notice( $error->getMessage(), 'error' );
|
||||
|
||||
|
@ -100,6 +75,7 @@ trait ProcessPaymentTrait {
|
|||
}
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
WC()->session->set( 'ppcp_subscription_id', '' );
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
|
|
60
modules/ppcp-wc-gateway/src/Helper/DisplayManager.php
Normal file
60
modules/ppcp-wc-gateway/src/Helper/DisplayManager.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
/**
|
||||
* Helper to manage the field display behaviour.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* DisplayManager class.
|
||||
*/
|
||||
class DisplayManager {
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The rules.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rules = array();
|
||||
|
||||
/**
|
||||
* FieldDisplayManager constructor.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( Settings $settings ) {
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a rule.
|
||||
*
|
||||
* @param string|null $key The rule key.
|
||||
* @return DisplayRule
|
||||
*/
|
||||
public function rule( string $key = null ): DisplayRule {
|
||||
if ( null === $key ) {
|
||||
$key = '_rule_' . ( (string) count( $this->rules ) );
|
||||
}
|
||||
|
||||
$rule = new DisplayRule( $key, $this->settings );
|
||||
|
||||
$this->rules[ $key ] = $rule;
|
||||
return $rule;
|
||||
}
|
||||
|
||||
}
|
262
modules/ppcp-wc-gateway/src/Helper/DisplayRule.php
Normal file
262
modules/ppcp-wc-gateway/src/Helper/DisplayRule.php
Normal file
|
@ -0,0 +1,262 @@
|
|||
<?php
|
||||
/**
|
||||
* Element used by field display manager.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* DisplayRule class.
|
||||
*/
|
||||
class DisplayRule {
|
||||
|
||||
const CONDITION_TYPE_ELEMENT = 'element';
|
||||
const CONDITION_TYPE_BOOL = 'bool';
|
||||
|
||||
const CONDITION_OPERATION_EQUALS = 'equals';
|
||||
const CONDITION_OPERATION_NOT_EQUALS = 'not_equals';
|
||||
const CONDITION_OPERATION_IN = 'in';
|
||||
const CONDITION_OPERATION_NOT_IN = 'not_in';
|
||||
const CONDITION_OPERATION_EMPTY = 'empty';
|
||||
const CONDITION_OPERATION_NOT_EMPTY = 'not_empty';
|
||||
|
||||
const ACTION_TYPE_ELEMENT = 'element';
|
||||
|
||||
const ACTION_VISIBLE = 'visible';
|
||||
const ACTION_ENABLE = 'enable';
|
||||
|
||||
/**
|
||||
* The element selector.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $key;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The conditions of this rule.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $conditions = array();
|
||||
|
||||
/**
|
||||
* The actions of this rule.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $actions = array();
|
||||
|
||||
/**
|
||||
* Indicates if this class should add selector prefixes.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $add_selector_prefixes = true;
|
||||
|
||||
/**
|
||||
* FieldDisplayElement constructor.
|
||||
*
|
||||
* @param string $key The rule key.
|
||||
* @param Settings $settings The settings.
|
||||
*/
|
||||
public function __construct( string $key, Settings $settings ) {
|
||||
$this->key = $key;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition related to an HTML element.
|
||||
*
|
||||
* @param string $selector The condition selector.
|
||||
* @param mixed $value The value to compare against.
|
||||
* @param string $operation The condition operation (ex: equals, differs, in, not_empty, empty).
|
||||
* @return self
|
||||
*/
|
||||
public function condition_element( string $selector, $value, string $operation = self::CONDITION_OPERATION_EQUALS ): self {
|
||||
$this->add_condition(
|
||||
array(
|
||||
'type' => self::CONDITION_TYPE_ELEMENT,
|
||||
'selector' => $selector,
|
||||
'operation' => $operation,
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition related to a bool check.
|
||||
*
|
||||
* @param bool $value The value to enable / disable the condition.
|
||||
* @return self
|
||||
*/
|
||||
public function condition_is_true( bool $value ): self {
|
||||
$this->add_condition(
|
||||
array(
|
||||
'type' => self::CONDITION_TYPE_BOOL,
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition related to the settings.
|
||||
*
|
||||
* @param string $settings_key The settings key.
|
||||
* @param mixed $value The value to compare against.
|
||||
* @param string $operation The condition operation (ex: equals, differs, in, not_empty, empty).
|
||||
* @return self
|
||||
*/
|
||||
public function condition_is_settings( string $settings_key, $value, string $operation = self::CONDITION_OPERATION_EQUALS ): self {
|
||||
$settings_value = null;
|
||||
|
||||
if ( $this->settings->has( $settings_key ) ) {
|
||||
$settings_value = $this->settings->get( $settings_key );
|
||||
}
|
||||
|
||||
$this->condition_is_true( $this->resolve_operation( $settings_value, $value, $operation ) );
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition to show/hide the element.
|
||||
*
|
||||
* @param string $selector The condition selector.
|
||||
*/
|
||||
public function action_visible( string $selector ): self {
|
||||
$this->add_action(
|
||||
array(
|
||||
'type' => self::ACTION_TYPE_ELEMENT,
|
||||
'selector' => $selector,
|
||||
'action' => self::ACTION_VISIBLE,
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition to enable/disable the element.
|
||||
*
|
||||
* @param string $selector The condition selector.
|
||||
*/
|
||||
public function action_enable( string $selector ): self {
|
||||
$this->add_action(
|
||||
array(
|
||||
'type' => self::ACTION_TYPE_ELEMENT,
|
||||
'selector' => $selector,
|
||||
'action' => self::ACTION_ENABLE,
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition to the rule.
|
||||
*
|
||||
* @param array $options The condition options.
|
||||
* @return void
|
||||
*/
|
||||
private function add_condition( array $options ): void {
|
||||
if ( $this->add_selector_prefixes && isset( $options['selector'] ) ) {
|
||||
$options['selector'] = '#ppcp-' . $options['selector']; // Refers to the input.
|
||||
}
|
||||
|
||||
if ( ! isset( $options['key'] ) ) {
|
||||
$options['key'] = '_condition_' . ( (string) count( $this->conditions ) );
|
||||
}
|
||||
|
||||
$this->conditions[] = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an action to do.
|
||||
*
|
||||
* @param array $options The action options.
|
||||
* @return void
|
||||
*/
|
||||
private function add_action( array $options ): void {
|
||||
if ( $this->add_selector_prefixes && isset( $options['selector'] ) ) {
|
||||
$options['selector'] = '#field-' . $options['selector']; // Refers to the whole field.
|
||||
}
|
||||
|
||||
if ( ! isset( $options['key'] ) ) {
|
||||
$options['key'] = '_action_' . ( (string) count( $this->actions ) );
|
||||
}
|
||||
|
||||
$this->actions[] = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if selector prefixes like, "#ppcp-" or "#field-" should be added to condition or action selectors.
|
||||
*
|
||||
* @param bool $add_selector_prefixes If should add prefixes.
|
||||
* @return self
|
||||
*/
|
||||
public function should_add_selector_prefixes( bool $add_selector_prefixes = true ): self {
|
||||
$this->add_selector_prefixes = $add_selector_prefixes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition related to the settings.
|
||||
*
|
||||
* @param mixed $value_1 The value 1.
|
||||
* @param mixed $value_2 The value 2.
|
||||
* @param string $operation The condition operation (ex: equals, differs, in, not_empty, empty).
|
||||
* @return bool
|
||||
*/
|
||||
private function resolve_operation( $value_1, $value_2, string $operation ): bool {
|
||||
switch ( $operation ) {
|
||||
case self::CONDITION_OPERATION_EQUALS:
|
||||
return $value_1 === $value_2;
|
||||
case self::CONDITION_OPERATION_NOT_EQUALS:
|
||||
return $value_1 !== $value_2;
|
||||
case self::CONDITION_OPERATION_IN:
|
||||
return in_array( $value_1, $value_2, true );
|
||||
case self::CONDITION_OPERATION_NOT_IN:
|
||||
return ! in_array( $value_1, $value_2, true );
|
||||
case self::CONDITION_OPERATION_EMPTY:
|
||||
return empty( $value_1 );
|
||||
case self::CONDITION_OPERATION_NOT_EMPTY:
|
||||
return ! empty( $value_1 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array representation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'key' => $this->key,
|
||||
'conditions' => $this->conditions,
|
||||
'actions' => $this->actions,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JSON representation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function json(): string {
|
||||
return wp_json_encode( $this->to_array() ) ?: '';
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
|||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
|
||||
return function ( ContainerInterface $container, array $fields ): array {
|
||||
|
||||
|
@ -39,6 +40,9 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
|
||||
$module_url = $container->get( 'wcgateway.url' );
|
||||
|
||||
$display_manager = $container->get( 'wcgateway.display-manager' );
|
||||
assert( $display_manager instanceof DisplayManager );
|
||||
|
||||
$connection_fields = array(
|
||||
'ppcp_onboarading_header' => array(
|
||||
'type' => 'ppcp-text',
|
||||
|
@ -238,7 +242,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'merchant_email_production' => array(
|
||||
'title' => __( 'Live Email address', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'text',
|
||||
'type' => 'email',
|
||||
'required' => true,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The email address of your PayPal account.', 'woocommerce-paypal-payments' ),
|
||||
|
@ -304,7 +308,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'merchant_email_sandbox' => array(
|
||||
'title' => __( 'Sandbox Email address', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'text',
|
||||
'type' => 'email',
|
||||
'required' => true,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The email address of your PayPal account.', 'woocommerce-paypal-payments' ),
|
||||
|
@ -504,15 +508,13 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-handlers' => wp_json_encode(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
array(
|
||||
'handler' => 'SubElementsHandler',
|
||||
'options' => array(
|
||||
'values' => array( PurchaseUnitSanitizer::MODE_EXTRA_LINE ),
|
||||
'elements' => array( '#field-subtotal_mismatch_line_name' ),
|
||||
),
|
||||
),
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_element( 'subtotal_mismatch_behavior', PurchaseUnitSanitizer::MODE_EXTRA_LINE )
|
||||
->action_visible( 'subtotal_mismatch_line_name' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
|
|
|
@ -623,6 +623,254 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
|
||||
// Shop.
|
||||
'pay_later_shop_messaging_heading' => array(
|
||||
'heading' => __( 'Pay Later Messaging on the Shop page', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'ppcp-heading',
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_shop_message_layout' => array(
|
||||
'title' => __( 'Shop Messaging Layout', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The layout of the message.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'text' => __( 'Text', 'woocommerce-paypal-payments' ),
|
||||
'flex' => __( 'Banner', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_shop_message_logo' => array(
|
||||
'title' => __( 'Shop Messaging Logo', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'inline',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'What logo the text message contains. Only applicable, when the layout style Text is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'primary' => __( 'Primary', 'woocommerce-paypal-payments' ),
|
||||
'alternative' => __( 'Alternative', 'woocommerce-paypal-payments' ),
|
||||
'inline' => __( 'Inline', 'woocommerce-paypal-payments' ),
|
||||
'none' => __( 'None', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_shop_message_position' => array(
|
||||
'title' => __( 'Shop Messaging Logo Position', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'left',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The position of the logo. Only applicable, when the layout style Text is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'left' => __( 'Left', 'woocommerce-paypal-payments' ),
|
||||
'right' => __( 'Right', 'woocommerce-paypal-payments' ),
|
||||
'top' => __( 'Top', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_shop_message_color' => array(
|
||||
'title' => __( 'Shop Messaging Text Color', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'black',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The color of the text. Only applicable, when the layout style Text is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
'monochrome' => __( 'Monochrome', 'woocommerce-paypal-payments' ),
|
||||
'grayscale' => __( 'Grayscale', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_shop_message_flex_color' => array(
|
||||
'title' => __( 'Shop Messaging Color', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => $default_messaging_flex_color,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The color of the text. Only applicable, when the layout style Banner is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'blue' => __( 'Blue', 'woocommerce-paypal-payments' ),
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
'white-no-border' => __( 'White no border', 'woocommerce-paypal-payments' ),
|
||||
'gray' => __( 'Gray', 'woocommerce-paypal-payments' ),
|
||||
'monochrome' => __( 'Monochrome', 'woocommerce-paypal-payments' ),
|
||||
'grayscale' => __( 'Grayscale', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_shop_message_flex_ratio' => array(
|
||||
'title' => __( 'Shop Messaging Ratio', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => '8x1',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The width/height ratio of the banner. Only applicable, when the layout style Banner is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'1x1' => __( '1x1', 'woocommerce-paypal-payments' ),
|
||||
'1x4' => __( '1x4', 'woocommerce-paypal-payments' ),
|
||||
'8x1' => __( '8x1', 'woocommerce-paypal-payments' ),
|
||||
'20x1' => __( '20x1', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_shop_message_preview' => array(
|
||||
'type' => 'ppcp-text',
|
||||
'text' => $render_preview_element( 'ppcpShopMessagePreview', 'message', $messaging_message ),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
|
||||
// Home.
|
||||
'pay_later_home_messaging_heading' => array(
|
||||
'heading' => __( 'Pay Later Messaging on the Home page', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'ppcp-heading',
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_home_message_layout' => array(
|
||||
'title' => __( 'Home Messaging Layout', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The layout of the message.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'text' => __( 'Text', 'woocommerce-paypal-payments' ),
|
||||
'flex' => __( 'Banner', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_home_message_logo' => array(
|
||||
'title' => __( 'Home Messaging Logo', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'inline',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'What logo the text message contains. Only applicable, when the layout style Text is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'primary' => __( 'Primary', 'woocommerce-paypal-payments' ),
|
||||
'alternative' => __( 'Alternative', 'woocommerce-paypal-payments' ),
|
||||
'inline' => __( 'Inline', 'woocommerce-paypal-payments' ),
|
||||
'none' => __( 'None', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_home_message_position' => array(
|
||||
'title' => __( 'Home Messaging Logo Position', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'left',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The position of the logo. Only applicable, when the layout style Text is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'left' => __( 'Left', 'woocommerce-paypal-payments' ),
|
||||
'right' => __( 'Right', 'woocommerce-paypal-payments' ),
|
||||
'top' => __( 'Top', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_home_message_color' => array(
|
||||
'title' => __( 'Home Messaging Text Color', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'black',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The color of the text. Only applicable, when the layout style Text is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
'monochrome' => __( 'Monochrome', 'woocommerce-paypal-payments' ),
|
||||
'grayscale' => __( 'Grayscale', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_home_message_flex_color' => array(
|
||||
'title' => __( 'Home Messaging Color', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => $default_messaging_flex_color,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The color of the text. Only applicable, when the layout style Banner is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'blue' => __( 'Blue', 'woocommerce-paypal-payments' ),
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
'white-no-border' => __( 'White no border', 'woocommerce-paypal-payments' ),
|
||||
'gray' => __( 'Gray', 'woocommerce-paypal-payments' ),
|
||||
'monochrome' => __( 'Monochrome', 'woocommerce-paypal-payments' ),
|
||||
'grayscale' => __( 'Grayscale', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_home_message_flex_ratio' => array(
|
||||
'title' => __( 'Home Messaging Ratio', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => '8x1',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The width/height ratio of the banner. Only applicable, when the layout style Banner is used.', 'woocommerce-paypal-payments' ),
|
||||
'options' => array(
|
||||
'1x1' => __( '1x1', 'woocommerce-paypal-payments' ),
|
||||
'1x4' => __( '1x4', 'woocommerce-paypal-payments' ),
|
||||
'8x1' => __( '8x1', 'woocommerce-paypal-payments' ),
|
||||
'20x1' => __( '20x1', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
'pay_later_home_message_preview' => array(
|
||||
'type' => 'ppcp-text',
|
||||
'text' => $render_preview_element( 'ppcpHomeMessagePreview', 'message', $messaging_message ),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'requirements' => array( 'messages' ),
|
||||
'gateway' => Settings::PAY_LATER_TAB_ID,
|
||||
),
|
||||
);
|
||||
|
||||
return array_merge( $fields, $pay_later_fields );
|
||||
|
|
|
@ -60,7 +60,7 @@ class HeaderRenderer {
|
|||
|
||||
return '
|
||||
<div class="ppcp-settings-page-header">
|
||||
<img alt="PayPal" src="' . esc_url( $this->module_url ) . 'assets/images/paypal.png"/>
|
||||
<img alt="PayPal" src="' . esc_url( $this->module_url ) . 'assets/images/paypal.png" style="max-height: 30px" />
|
||||
<h4> <span class="ppcp-inline-only">-</span> ' . __( 'The all-in-one checkout solution for WooCommerce', 'woocommerce-paypal-payments' ) . '</h4>
|
||||
<a class="button" target="_blank" href="https://woocommerce.com/document/woocommerce-paypal-payments/">'
|
||||
. __( 'Documentation', 'woocommerce-paypal-payments' ) .
|
||||
|
|
|
@ -35,13 +35,22 @@ class Settings implements ContainerInterface {
|
|||
*/
|
||||
protected $default_button_locations;
|
||||
|
||||
/**
|
||||
* The default ACDC gateway title.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $default_dcc_gateway_title;
|
||||
|
||||
/**
|
||||
* Settings constructor.
|
||||
*
|
||||
* @param string[] $default_button_locations The list of selected default button locations.
|
||||
* @param string $default_dcc_gateway_title The default ACDC gateway title.
|
||||
*/
|
||||
public function __construct( array $default_button_locations ) {
|
||||
$this->default_button_locations = $default_button_locations;
|
||||
public function __construct( array $default_button_locations, string $default_dcc_gateway_title ) {
|
||||
$this->default_button_locations = $default_button_locations;
|
||||
$this->default_dcc_gateway_title = $default_dcc_gateway_title;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,7 +125,7 @@ class Settings implements ContainerInterface {
|
|||
'pay_later_button_locations' => $this->default_button_locations,
|
||||
'pay_later_messaging_locations' => $this->default_button_locations,
|
||||
'brand_name' => get_bloginfo( 'name' ),
|
||||
'dcc_gateway_title' => __( 'Credit Cards', 'woocommerce-paypal-payments' ),
|
||||
'dcc_gateway_title' => $this->default_dcc_gateway_title,
|
||||
'dcc_gateway_description' => __(
|
||||
'Pay with your credit card.',
|
||||
'woocommerce-paypal-payments'
|
||||
|
|
|
@ -340,7 +340,20 @@ class SettingsListener {
|
|||
* phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
* phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
*/
|
||||
if ( ! isset( $_POST['ppcp']['vault_enabled'] ) ) {
|
||||
$vault_enabled = wc_clean( wp_unslash( $_POST['ppcp']['vault_enabled'] ?? '' ) );
|
||||
$subscription_mode = wc_clean( wp_unslash( $_POST['ppcp']['subscriptions_mode'] ?? '' ) );
|
||||
|
||||
if ( $subscription_mode === 'vaulting_api' && $vault_enabled !== '1' ) {
|
||||
$this->settings->set( 'vault_enabled', true );
|
||||
$this->settings->persist();
|
||||
}
|
||||
|
||||
if ( $subscription_mode === 'disable_paypal_subscriptions' && $vault_enabled === '1' ) {
|
||||
$this->settings->set( 'vault_enabled', false );
|
||||
$this->settings->persist();
|
||||
}
|
||||
|
||||
if ( $vault_enabled !== '1' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -555,6 +568,7 @@ class SettingsListener {
|
|||
break;
|
||||
case 'text':
|
||||
case 'number':
|
||||
case 'email':
|
||||
$settings[ $key ] = isset( $raw_data[ $key ] ) ? wp_kses_post( $raw_data[ $key ] ) : '';
|
||||
break;
|
||||
case 'ppcp-password':
|
||||
|
|
|
@ -11,6 +11,7 @@ module.exports = {
|
|||
'fraudnet': path.resolve('./resources/js/fraudnet.js'),
|
||||
'oxxo': path.resolve('./resources/js/oxxo.js'),
|
||||
'gateway-settings-style': path.resolve('./resources/css/gateway-settings.scss'),
|
||||
'common-style': path.resolve('./resources/css/common.scss'),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'assets/'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "woocommerce-paypal-payments",
|
||||
"version": "2.3.0",
|
||||
"version": "2.3.1",
|
||||
"description": "WooCommerce PayPal Payments",
|
||||
"repository": "https://github.com/woocommerce/woocommerce-paypal-payments",
|
||||
"license": "GPL-2.0",
|
||||
|
|
29
readme.txt
29
readme.txt
|
@ -4,7 +4,7 @@ Tags: woocommerce, paypal, payments, ecommerce, checkout, cart, pay later, apple
|
|||
Requires at least: 5.3
|
||||
Tested up to: 6.3
|
||||
Requires PHP: 7.2
|
||||
Stable tag: 2.3.0
|
||||
Stable tag: 2.3.1
|
||||
License: GPLv2
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
|
@ -180,13 +180,24 @@ If you encounter issues with the PayPal buttons not appearing after an update, p
|
|||
|
||||
== Changelog ==
|
||||
|
||||
= 2.3.0 - XXXX-XX-XX =
|
||||
= 2.3.1 - 2023-09-26 =
|
||||
* Fix - Fatal error when saving product while WooCommerce Subscriptions plugin is not active #1731
|
||||
* Fix - Validate tracking data only for add/update Package Tracking #1729
|
||||
* Fix - Disable Package Tracking for order if transaction ID doesn't exist #1727
|
||||
|
||||
= 2.3.0 - 2023-09-26 =
|
||||
* Fix - Plus sign in PayPal account email address gets converted to space #771
|
||||
* Fix - Payment method dropdown option label on edit order screen for ppcp-gateway option displaying wrong name #1639
|
||||
* Fix - WooCommerce Bookings products don't remain in Cart as a guest when PayPal button active on single product #1645
|
||||
* Fix - Since version > 2.2.0 the PayPal Checkout button on single product pages does not redirect anymore #1664
|
||||
* Fix - PayPal fee and PayPal Payout do not change on order if we do partial refund #1578
|
||||
* Fix - Order does not contain intent error when using ACDC payment token while buyer is not present #1506
|
||||
* Fix - Error when product description linked with a PayPal subscription exceeds 127 characters #1700
|
||||
* Fix - $_POST uses the wrong key to hold the shipping method #1652
|
||||
* Fix - WC Payment Token created multiple times when webhook is received #1663
|
||||
* Fix - Subtotal mismatch line name shows on Account settings page when merchant is disconnected #1702
|
||||
* Fix - Warning prevents payments on Pay for Order page when debugging is enabled #1703
|
||||
* Fix - paypal-overlay-uid_ blocks page after closing PayPal popup on Pay for Order page | Terms checkbox validation fails on Pay for Order page #1704
|
||||
* Enhancement - Add support for HPOS for tracking module #1676
|
||||
* Enhancement - Billing agreements endpoint called too frequently for Reference Transactions check #1646
|
||||
* Enhancement - Do not declare subscription support for PayPal when only ACDC vaulting #1669
|
||||
|
@ -201,6 +212,20 @@ If you encounter issues with the PayPal buttons not appearing after an update, p
|
|||
* Enhancement - Compatibility with WooCommerce Product Add-Ons plugin #1586
|
||||
* Enhancement - Remove "no shipment" message after adding tracking #1674
|
||||
* Enhancement - Improve error & success validation messages #1675
|
||||
* Enhancement - Compatibility with third-party "Product Add-Ons" plugins #1601
|
||||
* Enhancement - PayPal logo flashes when switching between tabs #1345
|
||||
* Enhancement - Include url & image_url in create order call #1649
|
||||
* Enhancement - Include item_url & image_url to tracking call #1712
|
||||
* Enhancement - Update strings for tracking metabox #1714
|
||||
* Enhancement - Validate email address API credentials field #1691
|
||||
* Enhancement - Set payment method title for order edit page only if our gateway #1661
|
||||
* Enhancement - Fix missing Pay Later messages in cart + refactoring #1683
|
||||
* Enhancement - Product page PP button keep loading popup - "wc_add_to_cart_params is not defined" error in WooCommerce #1655
|
||||
* Enhancement - Remove PayPal Subscriptions API feature flag #1690
|
||||
* Enhancement - Don't send image_url when it is empty #1678
|
||||
* Enhancement - Subscription support depending on Vaulting setting instead of subscription mode setting #1697
|
||||
* Enhancement - Wrong PayPal subscription id on vaulted subscriptions #1699
|
||||
* Enhancement - Remove payment vaulted checker functionality (2030) #1711
|
||||
* Feature preview - Apple Pay integration #1514
|
||||
* Feature preview - Google Pay integration #1654
|
||||
|
||||
|
|
|
@ -59,6 +59,9 @@ class ItemTest extends TestCase
|
|||
$tax
|
||||
->expects('to_array')
|
||||
->andReturn([2]);
|
||||
|
||||
$image_url = 'https://example.com/wp-content/uploads/2023/06/beanie-2.jpg';
|
||||
|
||||
$testee = new Item(
|
||||
'name',
|
||||
$unitAmount,
|
||||
|
@ -68,7 +71,7 @@ class ItemTest extends TestCase
|
|||
'sku',
|
||||
'PHYSICAL_GOODS',
|
||||
'url',
|
||||
'image_url'
|
||||
$image_url
|
||||
);
|
||||
|
||||
$expected = [
|
||||
|
@ -79,7 +82,7 @@ class ItemTest extends TestCase
|
|||
'sku' => 'sku',
|
||||
'category' => 'PHYSICAL_GOODS',
|
||||
'url' => 'url',
|
||||
'image_url' => 'image_url',
|
||||
'image_url' => $image_url,
|
||||
'tax' => [2],
|
||||
];
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ class ModularTestCase extends TestCase
|
|||
$wpdb->posts = '';
|
||||
$wpdb->postmeta = '';
|
||||
|
||||
!defined('PAYPAL_API_URL') && define('PAYPAL_API_URL', 'https://api.paypal.com');
|
||||
!defined('PAYPAL_SANDBOX_API_URL') && define('PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com');
|
||||
!defined('PAYPAL_API_URL') && define('PAYPAL_API_URL', 'https://api-m.paypal.com');
|
||||
!defined('PAYPAL_SANDBOX_API_URL') && define('PAYPAL_SANDBOX_API_URL', 'https://api-m.sandbox.paypal.com');
|
||||
!defined('PAYPAL_INTEGRATION_DATE') && define('PAYPAL_INTEGRATION_DATE', '2020-10-15');
|
||||
|
||||
!defined('PPCP_FLAG_SUBSCRIPTION') && define('PPCP_FLAG_SUBSCRIPTION', true);
|
||||
|
|
|
@ -78,6 +78,12 @@ class CreditCardGatewayTest extends TestCase
|
|||
$wc_order = Mockery::mock(WC_Order::class);
|
||||
when('wc_get_order')->justReturn($wc_order);
|
||||
|
||||
$woocommerce = Mockery::mock(\WooCommerce::class);
|
||||
$session = Mockery::mock(\WC_Session::class);
|
||||
when('WC')->justReturn($woocommerce);
|
||||
$woocommerce->session = $session;
|
||||
$session->shouldReceive('set')->andReturn([]);
|
||||
|
||||
$this->orderProcessor->shouldReceive('process')
|
||||
->with($wc_order)
|
||||
->andReturn(true);
|
||||
|
@ -95,6 +101,12 @@ class CreditCardGatewayTest extends TestCase
|
|||
$wc_order->shouldReceive('get_customer_id')->andReturn(1);
|
||||
when('wc_get_order')->justReturn($wc_order);
|
||||
|
||||
$woocommerce = Mockery::mock(\WooCommerce::class);
|
||||
$session = Mockery::mock(\WC_Session::class);
|
||||
when('WC')->justReturn($woocommerce);
|
||||
$woocommerce->session = $session;
|
||||
$session->shouldReceive('set')->andReturn([]);
|
||||
|
||||
$savedCreditCard = 'abc123';
|
||||
$_POST['saved_credit_card'] = $savedCreditCard;
|
||||
|
||||
|
|
|
@ -147,9 +147,11 @@ class WcGatewayTest extends TestCase
|
|||
when('WC')->justReturn($woocommerce);
|
||||
$woocommerce->cart = $cart;
|
||||
$cart->shouldReceive('empty_cart');
|
||||
|
||||
$session = Mockery::mock(\WC_Session::class);
|
||||
$woocommerce->session = $session;
|
||||
$session->shouldReceive('get');
|
||||
$session->shouldReceive('set');
|
||||
|
||||
$result = $testee->process_payment($orderId);
|
||||
|
||||
|
@ -164,6 +166,12 @@ class WcGatewayTest extends TestCase
|
|||
|
||||
$testee = $this->createGateway();
|
||||
|
||||
$woocommerce = Mockery::mock(\WooCommerce::class);
|
||||
$session = Mockery::mock(\WC_Session::class);
|
||||
when('WC')->justReturn($woocommerce);
|
||||
$woocommerce->session = $session;
|
||||
$session->shouldReceive('set')->andReturn([]);
|
||||
|
||||
expect('wc_get_order')
|
||||
->with($orderId)
|
||||
->andReturn(false);
|
||||
|
@ -227,6 +235,7 @@ class WcGatewayTest extends TestCase
|
|||
$session = Mockery::mock(\WC_Session::class);
|
||||
$woocommerce->session = $session;
|
||||
$session->shouldReceive('get');
|
||||
$session->shouldReceive('set');
|
||||
|
||||
$result = $testee->process_payment($orderId);
|
||||
|
||||
|
|
|
@ -11,6 +11,16 @@ const {
|
|||
CART_URL,
|
||||
} = process.env;
|
||||
|
||||
const longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ultricies integer quis auctor elit sed vulputate mi. Aliquam sem et tortor consequat id porta nibh venenatis cras. Massa enim nec dui nunc. Nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus. Eu lobortis elementum nibh tellus molestie nunc. Euismod nisi porta lorem mollis aliquam ut porttitor. Ultrices tincidunt arcu non sodales neque sodales ut etiam. Urna cursus eget nunc scelerisque. Pulvinar sapien et ligula ullamcorper malesuada proin libero. Convallis a cras semper auctor neque vitae tempus quam pellentesque. Phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam. Cras tincidunt lobortis feugiat vivamus. Nec ultrices dui sapien eget mi proin sed libero enim. Neque gravida in fermentum et sollicitudin ac orci phasellus egestas. Aliquam faucibus purus in massa. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. At augue eget arcu dictum varius duis. Commodo ullamcorper a lacus vestibulum sed arcu non odio.\n' +
|
||||
'\n' +
|
||||
'Id cursus metus aliquam eleifend mi in nulla. A diam sollicitudin tempor id eu nisl. Faucibus purus in massa tempor. Lacus luctus accumsan tortor posuere ac ut consequat. Mauris augue neque gravida in fermentum et sollicitudin ac. Venenatis tellus in metus vulputate. Consectetur libero id faucibus nisl tincidunt eget. Pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio. Dolor sed viverra ipsum nunc aliquet bibendum. Turpis in eu mi bibendum neque. Ac tincidunt vitae semper quis lectus nulla at volutpat. Felis imperdiet proin fermentum leo vel orci porta. Sed sed risus pretium quam vulputate dignissim.\n' +
|
||||
'\n' +
|
||||
'Urna et pharetra pharetra massa massa ultricies mi quis. Egestas purus viverra accumsan in nisl nisi. Elit sed vulputate mi sit amet mauris commodo. Cras fermentum odio eu feugiat pretium nibh ipsum consequat. Justo laoreet sit amet cursus sit amet dictum. Nunc id cursus metus aliquam. Tortor at auctor urna nunc id. Quis lectus nulla at volutpat diam ut. Lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque. Tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius.\n' +
|
||||
'\n' +
|
||||
'Mattis nunc sed blandit libero. Vitae ultricies leo integer malesuada nunc vel risus. Dapibus ultrices in iaculis nunc. Interdum varius sit amet mattis. Tortor vitae purus faucibus ornare. Netus et malesuada fames ac turpis. Elit duis tristique sollicitudin nibh sit amet. Lacus suspendisse faucibus interdum posuere lorem. In pellentesque massa placerat duis. Fusce ut placerat orci nulla pellentesque dignissim. Dictum fusce ut placerat orci nulla pellentesque dignissim enim. Nibh sit amet commodo nulla facilisi. Maecenas sed enim ut sem. Non consectetur a erat nam at lectus urna duis convallis. Diam phasellus vestibulum lorem sed risus ultricies tristique nulla. Nunc congue nisi vitae suscipit. Tortor condimentum lacinia quis vel eros donec ac. Eleifend mi in nulla posuere.\n' +
|
||||
'\n' +
|
||||
'Vestibulum lectus mauris ultrices eros. Massa sed elementum tempus egestas sed sed risus. Ut placerat orci nulla pellentesque dignissim enim sit. Duis ut diam quam nulla porttitor. Morbi tincidunt ornare massa eget egestas purus. Commodo sed egestas egestas fringilla phasellus faucibus scelerisque eleifend donec. Arcu odio ut sem nulla pharetra diam sit. Risus sed vulputate odio ut enim. Faucibus et molestie ac feugiat. A scelerisque purus semper eget. Odio facilisis mauris sit amet massa vitae tortor. Condimentum vitae sapien pellentesque habitant morbi tristique senectus. Nec feugiat in fermentum posuere urna. Volutpat est velit egestas dui id ornare arcu odio ut. Ullamcorper malesuada proin libero nunc consequat interdum. Suspendisse in est ante in nibh mauris cursus mattis molestie. Vel eros donec ac odio tempor orci dapibus. Et tortor at risus viverra adipiscing at in tellus. Metus aliquam eleifend mi in.'
|
||||
|
||||
async function purchaseSubscriptionFromCart(page) {
|
||||
await loginAsCustomer(page);
|
||||
await page.goto(SUBSCRIPTION_URL);
|
||||
|
@ -57,7 +67,7 @@ test.describe.serial('Subscriptions Merchant', () => {
|
|||
const message = await page.locator('.notice-success');
|
||||
await expect(message).toContainText('Product published.');
|
||||
|
||||
const products = await request.get('https://api.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', {
|
||||
const products = await request.get('https://api-m.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -73,7 +83,7 @@ test.describe.serial('Subscriptions Merchant', () => {
|
|||
|
||||
product_id = product.id;
|
||||
|
||||
const plans = await request.get(`https://api.sandbox.paypal.com/v1/billing/plans?product_id=${product_id}&page_size=10&page=1&total_required=true`, {
|
||||
const plans = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/plans?product_id=${product_id}&page_size=10&page=1&total_required=true`, {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -98,6 +108,7 @@ test.describe.serial('Subscriptions Merchant', () => {
|
|||
|
||||
await page.fill('#title', `Updated ${productTitle}`);
|
||||
await page.fill('#_subscription_price', '20');
|
||||
await page.fill('#content', longText)
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
|
@ -107,7 +118,7 @@ test.describe.serial('Subscriptions Merchant', () => {
|
|||
const message = await page.locator('.notice-success');
|
||||
await expect(message).toContainText('Product updated.');
|
||||
|
||||
const products = await request.get('https://api.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', {
|
||||
const products = await request.get('https://api-m.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -121,7 +132,7 @@ test.describe.serial('Subscriptions Merchant', () => {
|
|||
});
|
||||
await expect(product.id).toBeTruthy;
|
||||
|
||||
const plan = await request.get(`https://api.sandbox.paypal.com/v1/billing/plans/${plan_id}`, {
|
||||
const plan = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/plans/${plan_id}`, {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -156,7 +167,7 @@ test('Create new free trial subscription product', async ({page, request}) => {
|
|||
const message = await page.locator('.notice-success');
|
||||
await expect(message).toContainText('Product published.');
|
||||
|
||||
const products = await request.get('https://api.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', {
|
||||
const products = await request.get('https://api-m.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -170,7 +181,7 @@ test('Create new free trial subscription product', async ({page, request}) => {
|
|||
});
|
||||
await expect(product.id).toBeTruthy;
|
||||
|
||||
const plans = await request.get(`https://api.sandbox.paypal.com/v1/billing/plans?product_id=${product.id}&page_size=10&page=1&total_required=true`, {
|
||||
const plans = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/plans?product_id=${product.id}&page_size=10&page=1&total_required=true`, {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -184,7 +195,7 @@ test('Create new free trial subscription product', async ({page, request}) => {
|
|||
});
|
||||
await expect(plan.id).toBeTruthy;
|
||||
|
||||
const planDetail = await request.get(`https://api.sandbox.paypal.com/v1/billing/plans/${plan.id}`, {
|
||||
const planDetail = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/plans/${plan.id}`, {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -253,7 +264,7 @@ test.describe('Subscriber my account actions', () => {
|
|||
await page.locator('text=View').first().click();
|
||||
|
||||
const subscriptionId = await page.locator('#ppcp-subscription-id').textContent();
|
||||
let subscription = await request.get(`https://api.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, {
|
||||
let subscription = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -267,7 +278,7 @@ test.describe('Subscriber my account actions', () => {
|
|||
const title = page.locator('.woocommerce-message');
|
||||
await expect(title).toHaveText('Your subscription has been cancelled.');
|
||||
|
||||
subscription = await request.get(`https://api.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, {
|
||||
subscription = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -285,7 +296,7 @@ test.describe('Subscriber my account actions', () => {
|
|||
await page.locator('text=View').first().click();
|
||||
|
||||
const subscriptionId = await page.locator('#ppcp-subscription-id').textContent();
|
||||
let subscription = await request.get(`https://api.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, {
|
||||
let subscription = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -299,7 +310,7 @@ test.describe('Subscriber my account actions', () => {
|
|||
const title = page.locator('.woocommerce-message');
|
||||
await expect(title).toHaveText('Your subscription has been cancelled.');
|
||||
|
||||
subscription = await request.get(`https://api.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, {
|
||||
subscription = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, {
|
||||
headers: {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'Content-Type': 'application/json'
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* 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.3.0
|
||||
* Version: 2.3.1
|
||||
* Author: WooCommerce
|
||||
* Author URI: https://woocommerce.com/
|
||||
* License: GPL-2.0
|
||||
|
@ -21,9 +21,9 @@ namespace WooCommerce\PayPalCommerce;
|
|||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
define( 'PAYPAL_API_URL', 'https://api.paypal.com' );
|
||||
define( 'PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com' );
|
||||
define( 'PAYPAL_INTEGRATION_DATE', '2023-09-13' );
|
||||
define( 'PAYPAL_API_URL', 'https://api-m.paypal.com' );
|
||||
define( 'PAYPAL_SANDBOX_API_URL', 'https://api-m.sandbox.paypal.com' );
|
||||
define( 'PAYPAL_INTEGRATION_DATE', '2023-09-26' );
|
||||
|
||||
! 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_' );
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue