mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-03 08:37:53 +08:00
Merge branch 'fastlane' of github.com:woocommerce/woocommerce-paypal-payments into PCP-3110-fastlane-improve-ryan-icon-display
This commit is contained in:
commit
8ff548c556
36 changed files with 1264 additions and 322 deletions
|
@ -6,6 +6,10 @@
|
|||
* Fix - Allow PUI Gateway for refund processor #2192
|
||||
* Fix - Notice on newly created block cart checkout #2211
|
||||
* Fix - Apple Pay button in the editor #2177
|
||||
* Fix - Allow shipping callback and skipping confirmation page from any express button #2236
|
||||
* Fix - Pay Later messaging configurator sometimes displays old settings after saving #2249
|
||||
* Fix - Update the apple-developer-merchantid-domain-association validation strings for Apple Pay #2251
|
||||
* Enhancement - Use admin theme color #1602
|
||||
|
||||
= 2.7.0 - 2024-04-30 =
|
||||
* Fix - Zero sum subscriptions cause CANNOT_BE_ZERO_OR_NEGATIVE when using Vault v3 #2152
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"phpunit/phpunit": "^7.0 | ^8.0 | ^9.0",
|
||||
"brain/monkey": "^2.4",
|
||||
"php-stubs/wordpress-stubs": "^5.0@stable",
|
||||
"php-stubs/woocommerce-stubs": "^5.0@stable",
|
||||
"php-stubs/woocommerce-stubs": "^8.0@stable",
|
||||
"vimeo/psalm": "^4.0",
|
||||
"vlucas/phpdotenv": "^5"
|
||||
},
|
||||
|
|
440
composer.lock
generated
440
composer.lock
generated
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -620,13 +620,18 @@ class ApplePayButton implements ButtonInterface {
|
|||
): array {
|
||||
|
||||
$shipping_methods_array = array();
|
||||
$shipping_methods = WC()->shipping->calculate_shipping(
|
||||
/**
|
||||
* The argument is defined only in docblock.
|
||||
*
|
||||
* @psalm-suppress InvalidScalarArgument
|
||||
*/
|
||||
$shipping_methods = WC()->shipping->calculate_shipping(
|
||||
$this->getShippingPackages(
|
||||
$customer_address,
|
||||
$cart->get_total( 'edit' )
|
||||
)
|
||||
);
|
||||
$done = false;
|
||||
$done = false;
|
||||
foreach ( $shipping_methods[0]['rates'] as $rate ) {
|
||||
$shipping_methods_array[] = array(
|
||||
'label' => $rate->get_label(),
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
.ppcp-axo-watermark-container {
|
||||
max-width: 200px;
|
||||
margin-top: 10px;
|
||||
position: relative;
|
||||
|
||||
&.loader:before {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
margin-left: -6px;
|
||||
margin-top: -6px;
|
||||
left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.ppcp-axo-payment-container {
|
||||
|
@ -28,6 +37,7 @@
|
|||
|
||||
.ppcp-axo-customer-details {
|
||||
margin-bottom: 40px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.axo-checkout-header-section {
|
||||
|
@ -44,6 +54,31 @@
|
|||
padding: 0.6em 1em;
|
||||
}
|
||||
|
||||
.ppcp-axo-watermark-loading {
|
||||
min-height: 12px;
|
||||
}
|
||||
|
||||
.ppcp-axo-overlay,
|
||||
.ppcp-axo-watermark-loading:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 999;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.ppcp-axo-loading .col-1 {
|
||||
position: relative;
|
||||
opacity: 0.9;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
#payment .payment_methods li label[for="payment_method_ppcp-axo-gateway"] {
|
||||
img {
|
||||
float: none;
|
||||
|
|
|
@ -24,7 +24,8 @@ class AxoManager {
|
|||
active: false,
|
||||
validEmail: false,
|
||||
hasProfile: false,
|
||||
useEmailWidget: this.useEmailWidget()
|
||||
useEmailWidget: this.useEmailWidget(),
|
||||
hasCard: false,
|
||||
};
|
||||
|
||||
this.data = {
|
||||
|
@ -156,6 +157,7 @@ class AxoManager {
|
|||
this.el.showGatewaySelectionLink.on('click', async () => {
|
||||
this.hideGatewaySelection = false;
|
||||
this.$('.wc_payment_methods label').show();
|
||||
this.$('.wc_payment_methods input').show();
|
||||
this.cardView.refresh();
|
||||
});
|
||||
|
||||
|
@ -231,6 +233,7 @@ class AxoManager {
|
|||
|
||||
if (scenario.defaultFormFields) {
|
||||
this.el.customerDetails.show();
|
||||
this.toggleLoaderAndOverlay(this.el.customerDetails, 'loader', 'ppcp-axo-overlay');
|
||||
} else {
|
||||
this.el.customerDetails.hide();
|
||||
}
|
||||
|
@ -248,7 +251,6 @@ class AxoManager {
|
|||
this.$(this.el.fieldBillingEmail.selector).append(
|
||||
this.$(this.el.watermarkContainer.selector)
|
||||
);
|
||||
|
||||
} else {
|
||||
this.el.emailWidgetContainer.hide();
|
||||
if (!scenario.defaultEmailField) {
|
||||
|
@ -257,11 +259,12 @@ class AxoManager {
|
|||
}
|
||||
|
||||
if (scenario.axoProfileViews) {
|
||||
this.el.billingAddressContainer.hide();
|
||||
|
||||
this.shippingView.activate();
|
||||
this.billingView.activate();
|
||||
this.cardView.activate();
|
||||
|
||||
if (this.status.hasCard) {
|
||||
this.cardView.activate();
|
||||
}
|
||||
|
||||
// Move watermark to after shipping.
|
||||
this.$(this.el.shippingAddressContainer.selector).after(
|
||||
|
@ -496,6 +499,8 @@ class AxoManager {
|
|||
(await this.fastlane.FastlaneWatermarkComponent({
|
||||
includeAdditionalInfo
|
||||
})).render(this.el.watermarkContainer.selector);
|
||||
|
||||
this.toggleWatermarkLoading(this.el.watermarkContainer, 'ppcp-axo-watermark-loading', 'loader');
|
||||
}
|
||||
|
||||
watchEmail() {
|
||||
|
@ -584,12 +589,20 @@ class AxoManager {
|
|||
log(JSON.stringify(authResponse));
|
||||
|
||||
const shippingData = authResponse.profileData.shippingAddress;
|
||||
if(shippingData) {
|
||||
if (shippingData) {
|
||||
this.setShipping(shippingData);
|
||||
}
|
||||
|
||||
if (authResponse.profileData.card) {
|
||||
this.setStatus('hasCard', true);
|
||||
} else {
|
||||
this.cardComponent = (await this.fastlane.FastlaneCardComponent(
|
||||
this.cardComponentData()
|
||||
)).render(this.el.paymentContainer.selector + '-form');
|
||||
}
|
||||
|
||||
const cardBillingAddress = authResponse.profileData?.card?.paymentSource?.card?.billingAddress;
|
||||
if(cardBillingAddress) {
|
||||
if (cardBillingAddress) {
|
||||
this.setCard(authResponse.profileData.card);
|
||||
|
||||
const billingData = {
|
||||
|
@ -608,6 +621,7 @@ class AxoManager {
|
|||
|
||||
this.hideGatewaySelection = true;
|
||||
this.$('.wc_payment_methods label').hide();
|
||||
this.$('.wc_payment_methods input').hide();
|
||||
|
||||
await this.renderWatermark(false);
|
||||
|
||||
|
@ -840,6 +854,28 @@ class AxoManager {
|
|||
data.billing_phone = phone;
|
||||
}
|
||||
}
|
||||
|
||||
toggleLoaderAndOverlay(element, loaderClass, overlayClass) {
|
||||
const loader = document.querySelector(`${element.selector} .${loaderClass}`);
|
||||
const overlay = document.querySelector(`${element.selector} .${overlayClass}`);
|
||||
if (loader) {
|
||||
loader.classList.toggle(loaderClass);
|
||||
}
|
||||
if (overlay) {
|
||||
overlay.classList.toggle(overlayClass);
|
||||
}
|
||||
}
|
||||
|
||||
toggleWatermarkLoading(container, loadingClass, loaderClass) {
|
||||
const watermarkLoading = document.querySelector(`${container.selector}.${loadingClass}`);
|
||||
const watermarkLoader = document.querySelector(`${container.selector}.${loaderClass}`);
|
||||
if (watermarkLoading) {
|
||||
watermarkLoading.classList.toggle(loadingClass);
|
||||
}
|
||||
if (watermarkLoader) {
|
||||
watermarkLoader.classList.toggle(loaderClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default AxoManager;
|
||||
|
|
|
@ -20,7 +20,7 @@ class DomElementCollection {
|
|||
this.watermarkContainer = new DomElement({
|
||||
id: 'ppcp-axo-watermark-container',
|
||||
selector: '#ppcp-axo-watermark-container',
|
||||
className: 'ppcp-axo-watermark-container'
|
||||
className: 'ppcp-axo-watermark-container ppcp-axo-watermark-loading loader'
|
||||
});
|
||||
|
||||
this.customerDetails = new DomElement({
|
||||
|
|
|
@ -110,14 +110,14 @@ class AxoManager {
|
|||
string $wcgateway_module_url
|
||||
) {
|
||||
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->settings = $settings;
|
||||
$this->environment = $environment;
|
||||
$this->settings_status = $settings_status;
|
||||
$this->currency = $currency;
|
||||
$this->logger = $logger;
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->settings = $settings;
|
||||
$this->environment = $environment;
|
||||
$this->settings_status = $settings_status;
|
||||
$this->currency = $currency;
|
||||
$this->logger = $logger;
|
||||
$this->wcgateway_module_url = $wcgateway_module_url;
|
||||
}
|
||||
|
||||
|
@ -161,13 +161,13 @@ class AxoManager {
|
|||
*/
|
||||
private function script_data() {
|
||||
return array(
|
||||
'environment' => array(
|
||||
'environment' => array(
|
||||
'is_sandbox' => $this->environment->current_environment() === 'sandbox',
|
||||
),
|
||||
'widgets' => array(
|
||||
'widgets' => array(
|
||||
'email' => 'render',
|
||||
),
|
||||
'insights' => array(
|
||||
'insights' => array(
|
||||
'enabled' => true,
|
||||
'client_id' => ( $this->settings->has( 'client_id' ) ? $this->settings->get( 'client_id' ) : null ),
|
||||
'session_id' =>
|
||||
|
@ -181,7 +181,7 @@ class AxoManager {
|
|||
'value' => WC()->cart->get_total( 'numeric' ),
|
||||
),
|
||||
),
|
||||
'style_options' => array(
|
||||
'style_options' => array(
|
||||
'root' => array(
|
||||
'backgroundColor' => $this->settings->has( 'axo_style_root_bg_color' ) ? $this->settings->get( 'axo_style_root_bg_color' ) : '',
|
||||
'errorColor' => $this->settings->has( 'axo_style_root_error_color' ) ? $this->settings->get( 'axo_style_root_error_color' ) : '',
|
||||
|
@ -200,14 +200,15 @@ class AxoManager {
|
|||
'focusBorderColor' => $this->settings->has( 'axo_style_input_focus_border_color' ) ? $this->settings->get( 'axo_style_input_focus_border_color' ) : '',
|
||||
),
|
||||
),
|
||||
'name_on_card' => $this->settings->has( 'axo_name_on_card' ) ? $this->settings->get( 'axo_name_on_card' ) : '',
|
||||
'woocommerce' => array(
|
||||
'name_on_card' => $this->settings->has( 'axo_name_on_card' ) ? $this->settings->get( 'axo_name_on_card' ) : '',
|
||||
'woocommerce' => array(
|
||||
'states' => array(
|
||||
'US' => WC()->countries->get_states( 'US' ),
|
||||
'CA' => WC()->countries->get_states( 'CA' ),
|
||||
),
|
||||
),
|
||||
'icons_directory' => esc_url( $this->wcgateway_module_url ) . 'assets/images/axo/',
|
||||
'module_url' => untrailingslashit( $this->module_url ),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -217,6 +217,8 @@ class AxoModule implements ModuleInterface {
|
|||
1
|
||||
);
|
||||
|
||||
// Add the markup necessary for displaying overlays and loaders for Axo on the checkout page.
|
||||
$this->add_checkout_loader_markup( $c );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -292,4 +294,47 @@ class AxoModule implements ModuleInterface {
|
|||
&& CartCheckoutDetector::has_classic_checkout()
|
||||
&& $is_axo_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the markup necessary for displaying overlays and loaders for Axo on the checkout page.
|
||||
*
|
||||
* @param ContainerInterface $c The container.
|
||||
* @return void
|
||||
*/
|
||||
private function add_checkout_loader_markup( ContainerInterface $c ): void {
|
||||
$settings = $c->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
|
||||
if ( $this->should_render_fastlane( $settings ) ) {
|
||||
add_action(
|
||||
'woocommerce_checkout_before_customer_details',
|
||||
function () {
|
||||
echo '<div class="ppcp-axo-loading">';
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_checkout_after_customer_details',
|
||||
function () {
|
||||
echo '</div>';
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_checkout_billing',
|
||||
function () {
|
||||
echo '<div class="loader"><div class="ppcp-axo-overlay"></div>';
|
||||
},
|
||||
8
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_checkout_billing',
|
||||
function () {
|
||||
echo '</div>';
|
||||
},
|
||||
12
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,32 @@ return array(
|
|||
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) );
|
||||
};
|
||||
|
||||
$label = __(
|
||||
'Enable this option to require customers to manually confirm express payments on the checkout page.
|
||||
<p class="description">This ensures they can review the order, update shipping options, and fill in eventual custom fields necessary for the transaction.</p>
|
||||
<p class="description">If this is disabled, the system will automatically synchronize shipping options with PayPal and bypass the final checkout confirmation. This expedites the checkout process but prevents buyers from filling in eventual custom fields and reviewing final details before finalizing the payment.</p>',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
|
||||
if ( wc_terms_and_conditions_page_id() > 0 ) {
|
||||
$label .= __(
|
||||
'<div class="ppcp-notice ppcp-notice-warning"><p><span class="highlight">Important:</span> Your store has a <a href="/wp-admin/admin.php?page=wc-settings&tab=advanced" target="_blank">Terms and Conditions</a> page configured. Buyers who use a PayPal express payment method will not be able to consent to the terms on the <code>Classic Checkout</code>, as the final checkout confirmation will be skipped.</p></div>',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
}
|
||||
|
||||
$subscription_helper = $container->get( 'wc-subscriptions.helper' );
|
||||
|
||||
if ( $subscription_helper->plugin_is_active() ) {
|
||||
$notice_content = __(
|
||||
'<span class="highlight">Important:</span> Cannot be deactivated while the WooCommerce Subscriptions plugin is active.',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
$label .= '<div class="ppcp-notice ppcp-notice-warning"><p>' . $notice_content . '</p></div>';
|
||||
}
|
||||
|
||||
$should_disable_checkbox = $subscription_helper->plugin_is_active() || apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false );
|
||||
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'smart_button_locations',
|
||||
|
@ -44,16 +70,13 @@ return array(
|
|||
'blocks_final_review_enabled' => array(
|
||||
'title' => __( 'Require final confirmation on checkout', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __(
|
||||
'Require customers to confirm express payments from the Cart and Express Checkout on the checkout page.
|
||||
<p class="description">If this setting is not enabled, <a href="https://woocommerce.com/document/woocommerce-paypal-payments/#blocks-faq" target="_blank">payment confirmation on the checkout will be skipped</a>.
|
||||
Skipping the final confirmation on the checkout page may impact the buyer experience during the PayPal payment process.</p>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'default' => true,
|
||||
'label' => $label,
|
||||
'default' => false,
|
||||
'screens' => array( State::STATE_START, State::STATE_ONBOARDED ),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
'class' => array( 'ppcp-grayed-out-text' ),
|
||||
'input_class' => $should_disable_checkbox ? array( 'ppcp-disabled-checkbox' ) : array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
|
|
@ -139,7 +139,17 @@ export const paypalOrderToWcAddresses = (order) => {
|
|||
billingAddress = paypalPayerToWc(order.payer);
|
||||
// no billing address, such as if billing address retrieval is not allowed in the merchant account
|
||||
if (!billingAddress.address_line_1) {
|
||||
billingAddress = {...shippingAddress, ...paypalPayerToWc(order.payer)};
|
||||
// use only non empty values from payer address, otherwise it will override shipping address
|
||||
let payerAddress = Object.fromEntries(
|
||||
Object.entries(billingAddress).filter(
|
||||
([key, value]) => value !== '' && key !== 'country'
|
||||
)
|
||||
);
|
||||
|
||||
billingAddress = {
|
||||
...shippingAddress,
|
||||
...payerAddress
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ const PayPalComponent = ({
|
|||
window.ppcpContinuationFilled = true;
|
||||
}, [])
|
||||
|
||||
const createOrder = async () => {
|
||||
const createOrder = async (data, actions) => {
|
||||
try {
|
||||
const res = await fetch(config.scriptData.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
|
@ -93,7 +93,8 @@ const PayPalComponent = ({
|
|||
context: config.scriptData.context,
|
||||
payment_method: 'ppcp-gateway',
|
||||
funding_source: window.ppcpFundingSource ?? 'paypal',
|
||||
createaccount: false
|
||||
createaccount: false,
|
||||
payment_source: data.paymentSource
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -296,10 +297,15 @@ const PayPalComponent = ({
|
|||
onClick();
|
||||
};
|
||||
|
||||
const isVenmoAndVaultingEnabled = () => {
|
||||
return window.ppcpFundingSource === 'venmo' && config.scriptData.vaultingEnabled;
|
||||
}
|
||||
|
||||
let handleShippingOptionsChange = null;
|
||||
let handleShippingAddressChange = null;
|
||||
let handleSubscriptionShippingOptionsChange = null;
|
||||
let handleSubscriptionShippingAddressChange = null;
|
||||
|
||||
if (shippingData.needsShipping && !config.finalReviewEnabled) {
|
||||
handleShippingOptionsChange = async (data, actions) => {
|
||||
try {
|
||||
|
|
|
@ -60,7 +60,8 @@ class CartActionHandler {
|
|||
funding_source: window.ppcpFundingSource,
|
||||
bn_code:bnCode,
|
||||
payer,
|
||||
context:this.config.context
|
||||
context:this.config.context,
|
||||
payment_source: data.paymentSource
|
||||
}),
|
||||
}).then(function(res) {
|
||||
return res.json();
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
import {paypalAddressToWc} from "../../../../../ppcp-blocks/resources/js/Helper/Address.js";
|
||||
import {convertKeysToSnakeCase} from "../../../../../ppcp-blocks/resources/js/Helper/Helper.js";
|
||||
|
||||
/**
|
||||
* Handles the shipping option change in PayPal.
|
||||
*
|
||||
* @param data
|
||||
* @param actions
|
||||
* @param config
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const handleShippingOptionsChange = async (data, actions, config) => {
|
||||
try {
|
||||
const shippingOptionId = data.selectedShippingOption?.id;
|
||||
|
||||
if (shippingOptionId) {
|
||||
await fetch(config.ajax.update_customer_shipping.shipping_options.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-WC-Store-API-Nonce': config.ajax.update_customer_shipping.wp_rest_nonce,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
rate_id: shippingOptionId,
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
return response.json();
|
||||
})
|
||||
.then(cardData => {
|
||||
const shippingMethods = document.querySelectorAll('.shipping_method');
|
||||
|
||||
shippingMethods.forEach(function(method) {
|
||||
if (method.value === shippingOptionId) {
|
||||
method.checked = true;
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
const res = await fetch(config.ajax.update_shipping.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
actions.reject();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the shipping address change in PayPal.
|
||||
*
|
||||
* @param data
|
||||
* @param actions
|
||||
* @param config
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const handleShippingAddressChange = async (data, actions, config) => {
|
||||
try {
|
||||
const address = paypalAddressToWc(convertKeysToSnakeCase(data.shippingAddress));
|
||||
|
||||
// Retrieve current cart contents
|
||||
await fetch(config.ajax.update_customer_shipping.shipping_address.cart_endpoint)
|
||||
.then(response => {
|
||||
return response.json();
|
||||
})
|
||||
.then(cartData => {
|
||||
// Update shipping address in the cart data
|
||||
cartData.shipping_address.address_1 = address.address_1;
|
||||
cartData.shipping_address.address_2 = address.address_2;
|
||||
cartData.shipping_address.city = address.city;
|
||||
cartData.shipping_address.state = address.state;
|
||||
cartData.shipping_address.postcode = address.postcode;
|
||||
cartData.shipping_address.country = address.country;
|
||||
|
||||
// Send update request
|
||||
return fetch(config.ajax.update_customer_shipping.shipping_address.update_customer_endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-WC-Store-API-Nonce': config.ajax.update_customer_shipping.wp_rest_nonce,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
shipping_address: cartData.shipping_address,
|
||||
})
|
||||
}).then(function (res) {
|
||||
return res.json();
|
||||
}).then(function (customerData) {
|
||||
jQuery(".cart_totals .shop_table").load(location.href + " " + ".cart_totals .shop_table" + ">*", "");
|
||||
})
|
||||
})
|
||||
|
||||
const res = await fetch(config.ajax.update_shipping.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
actions.reject();
|
||||
}
|
||||
};
|
|
@ -10,6 +10,7 @@ const onApprove = (context, errorHandler) => {
|
|||
nonce: context.config.ajax.approve_order.nonce,
|
||||
order_id:data.orderID,
|
||||
funding_source: window.ppcpFundingSource,
|
||||
should_create_wc_order: !context.config.vaultingEnabled || data.paymentSource !== 'venmo'
|
||||
})
|
||||
}).then((res)=>{
|
||||
return res.json();
|
||||
|
@ -20,7 +21,11 @@ const onApprove = (context, errorHandler) => {
|
|||
errorHandler.genericError();
|
||||
});
|
||||
}
|
||||
location.href = context.config.redirect;
|
||||
|
||||
let orderReceivedUrl = data.data?.order_received_url
|
||||
|
||||
location.href = orderReceivedUrl ? orderReceivedUrl : context.config.redirect;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@ import {loadScript} from "@paypal/paypal-js";
|
|||
import {keysToCamelCase} from "../Helper/Utils";
|
||||
import widgetBuilder from "./WidgetBuilder";
|
||||
import {normalizeStyleForFundingSource} from "../Helper/Style";
|
||||
import {
|
||||
handleShippingOptionsChange,
|
||||
handleShippingAddressChange,
|
||||
} from "../Helper/ShippingHandler.js";
|
||||
|
||||
class Renderer {
|
||||
constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit) {
|
||||
|
@ -64,6 +68,14 @@ class Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
shouldHandleShippingInPaypal = (venmoButtonClicked) => {
|
||||
if (!this.defaultSettings.should_handle_shipping_in_paypal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !venmoButtonClicked || !this.defaultSettings.vaultingEnabled;
|
||||
}
|
||||
|
||||
renderButtons(wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource = null) {
|
||||
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) ) {
|
||||
// Try to render registered buttons again in case they were removed from the DOM by an external source.
|
||||
|
@ -75,8 +87,10 @@ class Renderer {
|
|||
contextConfig.fundingSource = fundingSource;
|
||||
}
|
||||
|
||||
let venmoButtonClicked = false;
|
||||
|
||||
const buttonsOptions = () => {
|
||||
return {
|
||||
const options = {
|
||||
style,
|
||||
...contextConfig,
|
||||
onClick: this.onSmartButtonClick,
|
||||
|
@ -86,8 +100,16 @@ class Renderer {
|
|||
}
|
||||
this.handleOnButtonsInit(wrapper, data, actions);
|
||||
},
|
||||
};
|
||||
|
||||
// Check the condition and add the onShippingOptionsChange handler if needed
|
||||
if (this.shouldHandleShippingInPaypal(venmoButtonClicked)) {
|
||||
options.onShippingOptionsChange = (data, actions) => null;
|
||||
options.onShippingAddressChange = (data, actions) => null;
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
jQuery(document)
|
||||
.off(this.reloadEventName, wrapper)
|
||||
|
|
|
@ -16,6 +16,7 @@ use WooCommerce\PayPalCommerce\Button\Helper\CartProductsHelper;
|
|||
use WooCommerce\PayPalCommerce\Button\Helper\CheckoutFormSaver;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\SaveCheckoutFormEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\WooCommerceOrderCreator;
|
||||
use WooCommerce\PayPalCommerce\Button\Validation\CheckoutFormValidator;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\ValidateCheckoutEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
|
@ -147,7 +148,8 @@ return array(
|
|||
$container->get( 'wcgateway.funding-sources-without-redirect' ),
|
||||
$container->get( 'vaulting.vault-v3-enabled' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
$container->get( 'woocommerce.logger.woocommerce' ),
|
||||
$container->get( 'button.handle-shipping-in-paypal' )
|
||||
);
|
||||
},
|
||||
'button.url' => static function ( ContainerInterface $container ): string {
|
||||
|
@ -157,7 +159,13 @@ return array(
|
|||
);
|
||||
},
|
||||
'button.pay-now-contexts' => static function ( ContainerInterface $container ): array {
|
||||
return array( 'checkout', 'pay-now' );
|
||||
$defaults = array( 'checkout', 'pay-now' );
|
||||
|
||||
if ( $container->get( 'button.handle-shipping-in-paypal' ) ) {
|
||||
return array_merge( $defaults, array( 'cart', 'product', 'mini-cart' ) );
|
||||
}
|
||||
|
||||
return $defaults;
|
||||
},
|
||||
'button.request-data' => static function ( ContainerInterface $container ): RequestData {
|
||||
return new RequestData();
|
||||
|
@ -221,14 +229,18 @@ return array(
|
|||
return new EarlyOrderHandler( $state, $order_processor, $session_handler );
|
||||
},
|
||||
'button.endpoint.approve-order' => static function ( ContainerInterface $container ): ApproveOrderEndpoint {
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$three_d_secure = $container->get( 'button.helper.three-d-secure' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
|
||||
$order_helper = $container->get( 'api.order-helper' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$three_d_secure = $container->get( 'button.helper.three-d-secure' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
|
||||
$order_helper = $container->get( 'api.order-helper' );
|
||||
$final_review_enabled = $container->get( 'blocks.settings.final_review_enabled' );
|
||||
$wc_order_creator = $container->get( 'button.helper.wc-order-creator' );
|
||||
$gateway = $container->get( 'wcgateway.paypal-gateway' );
|
||||
$subscription_helper = $container->get( 'wc-subscriptions.helper' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
return new ApproveOrderEndpoint(
|
||||
$request_data,
|
||||
$order_endpoint,
|
||||
|
@ -237,6 +249,10 @@ return array(
|
|||
$settings,
|
||||
$dcc_applies,
|
||||
$order_helper,
|
||||
$final_review_enabled,
|
||||
$gateway,
|
||||
$wc_order_creator,
|
||||
$subscription_helper,
|
||||
$logger
|
||||
);
|
||||
},
|
||||
|
@ -342,6 +358,10 @@ return array(
|
|||
* May result in slower popup performance, additional loading.
|
||||
*/
|
||||
'button.handle-shipping-in-paypal' => static function ( ContainerInterface $container ): bool {
|
||||
return false;
|
||||
return ! $container->get( 'blocks.settings.final_review_enabled' );
|
||||
},
|
||||
|
||||
'button.helper.wc-order-creator' => static function ( ContainerInterface $container ): WooCommerceOrderCreator {
|
||||
return new WooCommerceOrderCreator( $container->get( 'wcgateway.funding-source.renderer' ), $container->get( 'session.handler' ) );
|
||||
},
|
||||
);
|
||||
|
|
|
@ -19,6 +19,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
use WooCommerce\PayPalCommerce\Blocks\Endpoint\UpdateShippingEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\ApproveSubscriptionEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\CartScriptParamsEndpoint;
|
||||
|
@ -217,6 +218,13 @@ class SmartButton implements SmartButtonInterface {
|
|||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Whether the shipping should be handled in PayPal.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $should_handle_shipping_in_paypal;
|
||||
|
||||
/**
|
||||
* SmartButton constructor.
|
||||
*
|
||||
|
@ -242,6 +250,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
* @param bool $vault_v3_enabled Whether Vault v3 module is enabled.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param bool $should_handle_shipping_in_paypal Whether the shipping should be handled in PayPal.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
|
@ -265,7 +274,8 @@ class SmartButton implements SmartButtonInterface {
|
|||
array $funding_sources_without_redirect,
|
||||
bool $vault_v3_enabled,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
LoggerInterface $logger
|
||||
LoggerInterface $logger,
|
||||
bool $should_handle_shipping_in_paypal
|
||||
) {
|
||||
|
||||
$this->module_url = $module_url;
|
||||
|
@ -290,6 +300,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
$this->vault_v3_enabled = $vault_v3_enabled;
|
||||
$this->logger = $logger;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
$this->should_handle_shipping_in_paypal = $should_handle_shipping_in_paypal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1133,6 +1144,21 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentTokenForGuest::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CreatePaymentTokenForGuest::nonce() ),
|
||||
),
|
||||
'update_shipping' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( UpdateShippingEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( UpdateShippingEndpoint::nonce() ),
|
||||
),
|
||||
'update_customer_shipping' => array(
|
||||
'shipping_options' => array(
|
||||
'endpoint' => '/wp-json/wc/store/cart/select-shipping-rate',
|
||||
),
|
||||
'shipping_address' => array(
|
||||
'cart_endpoint' => '/wp-json/wc/store/cart/',
|
||||
'update_customer_endpoint' => '/wp-json/wc/store/v1/cart/update-customer/',
|
||||
),
|
||||
'wp_rest_nonce' => wp_create_nonce( 'wc_store_api' ),
|
||||
'update_shipping_method' => \WC_AJAX::get_endpoint( 'update_shipping_method' ),
|
||||
),
|
||||
),
|
||||
'cart_contains_subscription' => $this->subscription_helper->cart_contains_subscription(),
|
||||
'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(),
|
||||
|
@ -1253,6 +1279,8 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
'user' => array(
|
||||
'is_logged' => is_user_logged_in(),
|
||||
),
|
||||
'should_handle_shipping_in_paypal' => $this->should_handle_shipping_in_paypal && ! $this->is_checkout(),
|
||||
'vaultingEnabled' => $this->settings->has( 'vault_enabled' ) && $this->settings->get( 'vault_enabled' ),
|
||||
);
|
||||
|
||||
if ( 'pay-now' === $this->context() ) {
|
||||
|
|
|
@ -14,20 +14,25 @@ use Exception;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\WooCommerceOrderCreator;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
|
||||
/**
|
||||
* Class ApproveOrderEndpoint
|
||||
*/
|
||||
class ApproveOrderEndpoint implements EndpointInterface {
|
||||
|
||||
use ContextTrait;
|
||||
|
||||
const ENDPOINT = 'ppc-approve-order';
|
||||
|
||||
/**
|
||||
|
@ -79,6 +84,34 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
*/
|
||||
protected $order_helper;
|
||||
|
||||
/**
|
||||
* Whether the final review is enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $final_review_enabled;
|
||||
|
||||
/**
|
||||
* The WC gateway.
|
||||
*
|
||||
* @var PayPalGateway
|
||||
*/
|
||||
protected $gateway;
|
||||
|
||||
/**
|
||||
* The WooCommerce order creator.
|
||||
*
|
||||
* @var WooCommerceOrderCreator
|
||||
*/
|
||||
protected $wc_order_creator;
|
||||
|
||||
/**
|
||||
* The Subscription Helper.
|
||||
*
|
||||
* @var SubscriptionHelper
|
||||
*/
|
||||
protected $subscription_helper;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -89,14 +122,18 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
/**
|
||||
* ApproveOrderEndpoint constructor.
|
||||
*
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
* @param ThreeDSecure $three_d_secure The 3d secure helper object.
|
||||
* @param Settings $settings The settings.
|
||||
* @param DccApplies $dcc_applies The DCC applies object.
|
||||
* @param OrderHelper $order_helper The order helper.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
* @param ThreeDSecure $three_d_secure The 3d secure helper object.
|
||||
* @param Settings $settings The settings.
|
||||
* @param DccApplies $dcc_applies The DCC applies object.
|
||||
* @param OrderHelper $order_helper The order helper.
|
||||
* @param bool $final_review_enabled Whether the final review is enabled.
|
||||
* @param PayPalGateway $gateway The WC gateway.
|
||||
* @param WooCommerceOrderCreator $wc_order_creator The WooCommerce order creator.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
|
@ -106,17 +143,25 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
Settings $settings,
|
||||
DccApplies $dcc_applies,
|
||||
OrderHelper $order_helper,
|
||||
bool $final_review_enabled,
|
||||
PayPalGateway $gateway,
|
||||
WooCommerceOrderCreator $wc_order_creator,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
$this->request_data = $request_data;
|
||||
$this->api_endpoint = $order_endpoint;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->threed_secure = $three_d_secure;
|
||||
$this->settings = $settings;
|
||||
$this->dcc_applies = $dcc_applies;
|
||||
$this->order_helper = $order_helper;
|
||||
$this->logger = $logger;
|
||||
$this->request_data = $request_data;
|
||||
$this->api_endpoint = $order_endpoint;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->threed_secure = $three_d_secure;
|
||||
$this->settings = $settings;
|
||||
$this->dcc_applies = $dcc_applies;
|
||||
$this->order_helper = $order_helper;
|
||||
$this->final_review_enabled = $final_review_enabled;
|
||||
$this->gateway = $gateway;
|
||||
$this->wc_order_creator = $wc_order_creator;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,6 +227,7 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
);
|
||||
}
|
||||
$this->session_handler->replace_order( $order );
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
|
@ -200,6 +246,19 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
$this->session_handler->replace_funding_source( $funding_source );
|
||||
|
||||
$this->session_handler->replace_order( $order );
|
||||
|
||||
if ( ! $this->subscription_helper->plugin_is_active() && apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ) ) {
|
||||
$this->toggle_final_review_enabled_setting();
|
||||
}
|
||||
|
||||
$should_create_wc_order = $data['should_create_wc_order'] ?? false;
|
||||
if ( ! $this->final_review_enabled && ! $this->is_checkout() && $should_create_wc_order ) {
|
||||
$wc_order = $this->wc_order_creator->create_from_paypal_order( $order, WC()->cart );
|
||||
$this->gateway->process_payment( $wc_order->get_id() );
|
||||
$order_received_url = $wc_order->get_checkout_order_received_url();
|
||||
|
||||
wp_send_json_success( array( 'order_received_url' => $order_received_url ) );
|
||||
}
|
||||
wp_send_json_success();
|
||||
return true;
|
||||
} catch ( Exception $error ) {
|
||||
|
@ -216,4 +275,15 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will toggle the "final confirmation" checkbox.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function toggle_final_review_enabled_setting(): void {
|
||||
$final_review_enabled_setting = $this->settings->has( 'blocks_final_review_enabled' ) && $this->settings->get( 'blocks_final_review_enabled' );
|
||||
$final_review_enabled_setting ? $this->settings->set( 'blocks_final_review_enabled', false ) : $this->settings->set( 'blocks_final_review_enabled', true );
|
||||
$this->settings->persist();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,6 +246,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
$this->parsed_request_data = $data;
|
||||
$payment_method = $data['payment_method'] ?? '';
|
||||
$funding_source = $data['funding_source'] ?? '';
|
||||
$payment_source = $data['payment_source'] ?? '';
|
||||
$wc_order = null;
|
||||
if ( 'pay-now' === $data['context'] ) {
|
||||
$wc_order = wc_get_order( (int) $data['order_id'] );
|
||||
|
@ -261,7 +262,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
}
|
||||
$this->purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
} else {
|
||||
$this->purchase_unit = $this->purchase_unit_factory->from_wc_cart( null, $this->handle_shipping_in_paypal );
|
||||
$this->purchase_unit = $this->purchase_unit_factory->from_wc_cart( null, $this->should_handle_shipping_in_paypal( $payment_source ) );
|
||||
|
||||
// Do not allow completion by webhooks when started via non-checkout buttons,
|
||||
// it is needed only for some APMs in checkout.
|
||||
|
@ -610,4 +611,20 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
'custom_id' => $order->purchase_units()[0]->custom_id(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the shipping should be handled in PayPal popup.
|
||||
*
|
||||
* @param string $payment_source The payment source.
|
||||
* @return bool true if the shipping should be handled in PayPal popup, otherwise false.
|
||||
*/
|
||||
protected function should_handle_shipping_in_paypal( string $payment_source ): bool {
|
||||
$is_vaulting_enabled = $this->settings->has( 'vault_enabled' ) && $this->settings->get( 'vault_enabled' );
|
||||
|
||||
if ( ! $this->handle_shipping_in_paypal ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! $is_vaulting_enabled || $payment_source !== 'venmo';
|
||||
}
|
||||
}
|
||||
|
|
228
modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php
Normal file
228
modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php
Normal file
|
@ -0,0 +1,228 @@
|
|||
<?php
|
||||
/**
|
||||
* Can create WC orders.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Button\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
||||
|
||||
use RuntimeException;
|
||||
use WC_Cart;
|
||||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Order_Item_Shipping;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
||||
/**
|
||||
* Class WooCommerceOrderCreator
|
||||
*/
|
||||
class WooCommerceOrderCreator {
|
||||
|
||||
/**
|
||||
* The funding source renderer.
|
||||
*
|
||||
* @var FundingSourceRenderer
|
||||
*/
|
||||
protected $funding_source_renderer;
|
||||
|
||||
/**
|
||||
* The Session handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
protected $session_handler;
|
||||
|
||||
/**
|
||||
* WooCommerceOrderCreator constructor.
|
||||
*
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
*/
|
||||
public function __construct(
|
||||
FundingSourceRenderer $funding_source_renderer,
|
||||
SessionHandler $session_handler
|
||||
) {
|
||||
$this->funding_source_renderer = $funding_source_renderer;
|
||||
$this->session_handler = $session_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates WC order based on given PayPal order.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
* @param WC_Cart $wc_cart The Cart.
|
||||
* @return WC_Order The WC order.
|
||||
* @throws RuntimeException If problem creating.
|
||||
*/
|
||||
public function create_from_paypal_order( Order $order, WC_Cart $wc_cart ): WC_Order {
|
||||
$wc_order = wc_create_order();
|
||||
|
||||
if ( ! $wc_order instanceof WC_Order ) {
|
||||
throw new RuntimeException( 'Problem creating WC order.' );
|
||||
}
|
||||
|
||||
$this->configure_line_items( $wc_order, $wc_cart );
|
||||
$this->configure_shipping( $wc_order, $order->payer(), $order->purchase_units()[0]->shipping() );
|
||||
$this->configure_payment_source( $wc_order );
|
||||
$this->configure_customer( $wc_order );
|
||||
$this->configure_coupons( $wc_order, $wc_cart->get_applied_coupons() );
|
||||
|
||||
$wc_order->calculate_totals();
|
||||
$wc_order->save();
|
||||
|
||||
return $wc_order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the line items.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @param WC_Cart $wc_cart The Cart.
|
||||
* @return void
|
||||
*/
|
||||
protected function configure_line_items( WC_Order $wc_order, WC_Cart $wc_cart ): void {
|
||||
$cart_contents = $wc_cart->get_cart();
|
||||
|
||||
foreach ( $cart_contents as $cart_item ) {
|
||||
$product_id = $cart_item['product_id'] ?? 0;
|
||||
$variation_id = $cart_item['variation_id'] ?? 0;
|
||||
$quantity = $cart_item['quantity'] ?? 0;
|
||||
$variation_attributes = $cart_item['variation'];
|
||||
|
||||
$item = new WC_Order_Item_Product();
|
||||
$item->set_product_id( $product_id );
|
||||
$item->set_quantity( $quantity );
|
||||
|
||||
if ( $variation_id ) {
|
||||
$item->set_variation_id( $variation_id );
|
||||
$item->set_variation( $variation_attributes );
|
||||
}
|
||||
|
||||
$product = wc_get_product( $variation_id ?: $product_id );
|
||||
if ( ! $product ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item->set_name( $product->get_name() );
|
||||
$item->set_subtotal( $product->get_price() * $quantity );
|
||||
$item->set_total( $product->get_price() * $quantity );
|
||||
|
||||
$wc_order->add_item( $item );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the shipping & billing addresses for WC order from given payer.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @param Payer|null $payer The payer.
|
||||
* @param Shipping|null $shipping The shipping.
|
||||
* @return void
|
||||
*/
|
||||
protected function configure_shipping( WC_Order $wc_order, ?Payer $payer, ?Shipping $shipping ): void {
|
||||
$shipping_address = null;
|
||||
$billing_address = null;
|
||||
$shipping_options = null;
|
||||
|
||||
if ( $payer ) {
|
||||
$address = $payer->address();
|
||||
$payer_name = $payer->name();
|
||||
|
||||
$billing_address = array(
|
||||
'first_name' => $payer_name ? $payer_name->given_name() : '',
|
||||
'last_name' => $payer_name ? $payer_name->surname() : '',
|
||||
'address_1' => $address ? $address->address_line_1() : '',
|
||||
'address_2' => $address ? $address->address_line_2() : '',
|
||||
'city' => $address ? $address->admin_area_2() : '',
|
||||
'state' => $address ? $address->admin_area_1() : '',
|
||||
'postcode' => $address ? $address->postal_code() : '',
|
||||
'country' => $address ? $address->country_code() : '',
|
||||
);
|
||||
}
|
||||
|
||||
if ( $shipping ) {
|
||||
$address = $shipping->address();
|
||||
|
||||
$shipping_address = array(
|
||||
'first_name' => $shipping->name(),
|
||||
'last_name' => '',
|
||||
'address_1' => $address->address_line_1(),
|
||||
'address_2' => $address->address_line_2(),
|
||||
'city' => $address->admin_area_2(),
|
||||
'state' => $address->admin_area_1(),
|
||||
'postcode' => $address->postal_code(),
|
||||
'country' => $address->country_code(),
|
||||
);
|
||||
|
||||
$shipping_options = $shipping->options()[0] ?? '';
|
||||
}
|
||||
|
||||
if ( $shipping_address ) {
|
||||
$wc_order->set_shipping_address( $shipping_address );
|
||||
}
|
||||
|
||||
if ( $billing_address || $shipping_address ) {
|
||||
$wc_order->set_billing_address( $billing_address ?: $shipping_address );
|
||||
}
|
||||
|
||||
if ( $shipping_options ) {
|
||||
$shipping = new WC_Order_Item_Shipping();
|
||||
$shipping->set_method_title( $shipping_options->label() );
|
||||
$shipping->set_method_id( $shipping_options->id() );
|
||||
$shipping->set_total( $shipping_options->amount()->value_str() );
|
||||
|
||||
$wc_order->add_item( $shipping );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the payment source.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @return void
|
||||
*/
|
||||
protected function configure_payment_source( WC_Order $wc_order ): void {
|
||||
$funding_source = $this->session_handler->funding_source();
|
||||
$wc_order->set_payment_method( PayPalGateway::ID );
|
||||
|
||||
if ( $funding_source ) {
|
||||
$wc_order->set_payment_method_title( $this->funding_source_renderer->render_name( $funding_source ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the customer ID.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @return void
|
||||
*/
|
||||
protected function configure_customer( WC_Order $wc_order ): void {
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
if ( $current_user->ID !== 0 ) {
|
||||
$wc_order->set_customer_id( $current_user->ID );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the applied coupons.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @param string[] $coupons The list of applied coupons.
|
||||
* @return void
|
||||
*/
|
||||
protected function configure_coupons( WC_Order $wc_order, array $coupons ): void {
|
||||
foreach ( $coupons as $coupon_code ) {
|
||||
$wc_order->apply_coupon( $coupon_code );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -28,13 +28,18 @@ class DeactivateNote {
|
|||
/**
|
||||
* Note initialization.
|
||||
*/
|
||||
public static function init() {
|
||||
public static function init(): void {
|
||||
if ( ! PPECHelper::is_plugin_active() ) {
|
||||
self::maybe_mark_note_as_actioned();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
/**
|
||||
* The method exists in the NoteTraits trait.
|
||||
*
|
||||
* @psalm-suppress UndefinedMethod
|
||||
*/
|
||||
self::possibly_add_note();
|
||||
} catch ( \Exception $e ) {
|
||||
return;
|
||||
|
@ -44,7 +49,7 @@ class DeactivateNote {
|
|||
/**
|
||||
* Get the note.
|
||||
*
|
||||
* @return Automatic\WooCommerce\Admin\Notes\Note
|
||||
* @return Note
|
||||
*/
|
||||
public static function get_note() {
|
||||
if ( PPECHelper::site_has_ppec_subscriptions() ) {
|
||||
|
@ -87,7 +92,7 @@ class DeactivateNote {
|
|||
/**
|
||||
* Marks the inbox note as actioned so that it doesn't re-appear.
|
||||
*/
|
||||
private static function maybe_mark_note_as_actioned() {
|
||||
private static function maybe_mark_note_as_actioned(): void {
|
||||
try {
|
||||
$data_store = \WC_Data_Store::load( 'admin-note' );
|
||||
} catch ( \Exception $e ) {
|
||||
|
@ -106,7 +111,7 @@ class DeactivateNote {
|
|||
|
||||
$note = Notes::get_note( $note_ids[0] );
|
||||
|
||||
if ( Note::E_WC_ADMIN_NOTE_ACTIONED !== $note->get_status() ) {
|
||||
if ( $note instanceof Note && Note::E_WC_ADMIN_NOTE_ACTIONED !== $note->get_status() ) {
|
||||
$note->set_status( Note::E_WC_ADMIN_NOTE_ACTIONED );
|
||||
$note->save();
|
||||
}
|
||||
|
|
|
@ -48,6 +48,45 @@
|
|||
margin-right: 16px;
|
||||
border-top-color: #B1B7BD;
|
||||
}
|
||||
|
||||
.css-168cq4n-checkbox_input:checked + label > span > span:first-of-type {
|
||||
background-color: var(--wp-admin-theme-color);
|
||||
border-color: var(--wp-admin-theme-color);
|
||||
}
|
||||
|
||||
.css-168cq4n-checkbox_input:focus + label > span > span:first-of-type {
|
||||
outline: var(--wp-admin-theme-color);
|
||||
}
|
||||
|
||||
span[class*="-svg-size_sm-SelectedMain-selected_icon"],
|
||||
span[class*="-svg-size_xs-selected_icon"] {
|
||||
color: var(--wp-admin-theme-color);
|
||||
}
|
||||
|
||||
button[class*="-dropdown_menu_button-text_field_value_sm-active-active"] {
|
||||
outline: var(--wp-admin-theme-color) solid 0.125rem;
|
||||
}
|
||||
|
||||
button[class*="-dropdown_menu_button-text_field_value_sm-active"] {
|
||||
&:focus {
|
||||
outline: var(--wp-admin-theme-color) solid 0.125rem;
|
||||
}
|
||||
}
|
||||
|
||||
.css-gzgyp8-control:checked ~ label {
|
||||
background-color: var(--wp-admin-theme-color);
|
||||
border: var(--wp-admin-theme-color);
|
||||
outline: var(--wp-admin-theme-color) solid 0.125rem;
|
||||
}
|
||||
|
||||
.css-gzgyp8-control:focus ~ label {
|
||||
outline: var(--wp-admin-theme-color) solid 0.125rem;
|
||||
}
|
||||
|
||||
.css-gzgyp8-control:checked ~ span {
|
||||
border: 0.0625rem solid var(--wp-admin-theme-color);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#field-pay_later_messaging_heading h3{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const form = document.querySelector('#mainform');
|
||||
const table = form.querySelector('.form-table');
|
||||
const headingRow = table.querySelector('#field-pay_later_messaging_heading');
|
||||
|
@ -14,7 +14,6 @@ document.addEventListener( 'DOMContentLoaded', () => {
|
|||
// Insert the new row after the headingRow
|
||||
headingRow.parentNode.insertBefore(newRow, headingRow.nextSibling);
|
||||
|
||||
|
||||
let isSaving = false; // Flag variable to track whether saving is in progress
|
||||
|
||||
saveChangesButton.addEventListener('click', () => {
|
||||
|
@ -24,39 +23,63 @@ document.addEventListener( 'DOMContentLoaded', () => {
|
|||
|
||||
// Trigger the click event on the publish button
|
||||
form.querySelector('.' + publishButtonClassName).click();
|
||||
|
||||
// Trigger click event on saveChangesButton after a short delay
|
||||
setTimeout(() => {
|
||||
saveChangesButton.click(); // Trigger click event on saveChangesButton
|
||||
isSaving = false; // Reset flag when saving is complete
|
||||
}, 1000); // Adjust the delay as needed
|
||||
saveChangesButton.click(); // Trigger click event on saveChangesButton
|
||||
isSaving = false; // Reset flag when saving is complete
|
||||
}
|
||||
});
|
||||
|
||||
merchantConfigurators.Messaging({
|
||||
config: PcpPayLaterConfigurator.config,
|
||||
merchantClientId: PcpPayLaterConfigurator.merchantClientId,
|
||||
partnerClientId: PcpPayLaterConfigurator.partnerClientId,
|
||||
partnerName: 'WooCommerce',
|
||||
bnCode: 'Woo_PPCP',
|
||||
placements: ['cart', 'checkout', 'product', 'shop', 'home', 'custom_placement'],
|
||||
styleOverrides: {
|
||||
button: publishButtonClassName,
|
||||
header: PcpPayLaterConfigurator.headerClassName,
|
||||
subheader: PcpPayLaterConfigurator.subheaderClassName
|
||||
// Fetch the configuration settings
|
||||
fetch(PcpPayLaterConfigurator.ajax.get_config.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
onSave: data => {
|
||||
fetch(PcpPayLaterConfigurator.ajax.save_config.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: PcpPayLaterConfigurator.ajax.save_config.nonce,
|
||||
config: data,
|
||||
}),
|
||||
});
|
||||
}
|
||||
body: JSON.stringify({
|
||||
action: 'ppc-get-message-config',
|
||||
nonce: PcpPayLaterConfigurator.ajax.get_config.nonce
|
||||
}),
|
||||
})
|
||||
} );
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const config = data.data;
|
||||
|
||||
merchantConfigurators.Messaging({
|
||||
config: config,
|
||||
merchantClientId: PcpPayLaterConfigurator.merchantClientId,
|
||||
partnerClientId: PcpPayLaterConfigurator.partnerClientId,
|
||||
partnerName: 'WooCommerce',
|
||||
bnCode: 'Woo_PPCP',
|
||||
placements: ['cart', 'checkout', 'product', 'shop', 'home', 'custom_placement'],
|
||||
styleOverrides: {
|
||||
button: publishButtonClassName,
|
||||
header: PcpPayLaterConfigurator.headerClassName,
|
||||
subheader: PcpPayLaterConfigurator.subheaderClassName
|
||||
},
|
||||
onSave: data => {
|
||||
fetch(PcpPayLaterConfigurator.ajax.save_config.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: PcpPayLaterConfigurator.ajax.save_config.nonce,
|
||||
config: data,
|
||||
}),
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error('Failed to fetch configuration:', data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching configuration:', error);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\PayLaterConfigurator;
|
||||
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint\SaveConfig;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint\GetConfig;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Factory\ConfigFactory;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
|
@ -35,4 +36,10 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'paylater-configurator.endpoint.get-config' => static function ( ContainerInterface $container ): GetConfig {
|
||||
return new GetConfig(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
/**
|
||||
* The endpoint for getting the Pay Later messaging config for the configurator.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Factory\ConfigFactory;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class GetConfig.
|
||||
*/
|
||||
class GetConfig {
|
||||
const ENDPOINT = 'ppc-get-message-config';
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* GetConfig constructor.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct( Settings $settings, LoggerInterface $logger ) {
|
||||
$this->settings = $settings;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
$this->logger->error( 'User does not have permission: manage_woocommerce' );
|
||||
wp_send_json_error( 'Not admin.', 403 );
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$input = file_get_contents( 'php://input' );
|
||||
|
||||
if ( false === $input ) {
|
||||
$this->logger->error( 'Failed to get input data.' );
|
||||
wp_send_json_error( 'Failed to get input data.', 400 );
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = json_decode( $input, true );
|
||||
|
||||
if ( json_last_error() !== JSON_ERROR_NONE ) {
|
||||
$this->logger->error( 'Failed to decode JSON: ' . json_last_error_msg() );
|
||||
wp_send_json_error( 'Failed to decode JSON.', 400 );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $data['nonce'] ) || ! wp_verify_nonce( $data['nonce'], self::ENDPOINT ) ) {
|
||||
$this->logger->error( 'Invalid nonce' );
|
||||
wp_send_json_error( 'Invalid nonce.', 403 );
|
||||
return false;
|
||||
}
|
||||
|
||||
$config_factory = new ConfigFactory();
|
||||
$config = $config_factory->from_settings( $this->settings );
|
||||
wp_send_json_success( $config );
|
||||
return true;
|
||||
} catch ( Throwable $error ) {
|
||||
$this->logger->error( "GetConfig execution failed. {$error->getMessage()} {$error->getFile()}:{$error->getLine()}" );
|
||||
|
||||
wp_send_json_error( 'An error occurred while fetching the configuration.' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\PayLaterConfigurator;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint\GetConfig;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint\SaveConfig;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Factory\ConfigFactory;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
|
@ -27,7 +28,7 @@ class PayLaterConfiguratorModule implements ModuleInterface {
|
|||
*/
|
||||
public static function is_enabled(): bool {
|
||||
return apply_filters(
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
'woocommerce.feature-flags.woocommerce_paypal_payments.paylater_configurator_enabled',
|
||||
getenv( 'PCP_PAYLATER_CONFIGURATOR' ) !== '0'
|
||||
);
|
||||
|
@ -68,6 +69,15 @@ class PayLaterConfiguratorModule implements ModuleInterface {
|
|||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . GetConfig::ENDPOINT,
|
||||
static function () use ( $c ) {
|
||||
$endpoint = $c->get( 'paylater-configurator.endpoint.get-config' );
|
||||
assert( $endpoint instanceof GetConfig );
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
$current_page_id = $c->get( 'wcgateway.current-ppcp-settings-page-id' );
|
||||
|
||||
if ( $current_page_id !== Settings::PAY_LATER_TAB_ID ) {
|
||||
|
@ -112,6 +122,10 @@ class PayLaterConfiguratorModule implements ModuleInterface {
|
|||
'endpoint' => \WC_AJAX::get_endpoint( SaveConfig::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( SaveConfig::nonce() ),
|
||||
),
|
||||
'get_config' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( GetConfig::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( GetConfig::nonce() ),
|
||||
),
|
||||
),
|
||||
'config' => $config_factory->from_settings( $settings ),
|
||||
'merchantClientId' => $settings->get( 'client_id' ),
|
||||
|
|
|
@ -61,8 +61,8 @@ $background-ident-color: #fbfbfb;
|
|||
border: 1px solid #c3c4c7;
|
||||
border-left-width: 4px;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
|
||||
margin: 5px 15px 2px;
|
||||
padding: 1px 12px;
|
||||
margin: 5px 0px 2px;
|
||||
padding: 0px 12px 4px 12px;
|
||||
}
|
||||
|
||||
.ppcp-notice-warning {
|
||||
|
|
|
@ -347,6 +347,7 @@ return array(
|
|||
$container->get( 'api.partner_merchant_id-production' ),
|
||||
$container->get( 'api.partner_merchant_id-sandbox' ),
|
||||
$container->get( 'api.endpoint.billing-agreements' ),
|
||||
$container->get( 'wc-subscriptions.helper' ),
|
||||
$logger
|
||||
);
|
||||
},
|
||||
|
@ -1461,7 +1462,7 @@ return array(
|
|||
|
||||
$button_text = $enabled
|
||||
? esc_html__( 'Settings', 'woocommerce-paypal-payments' )
|
||||
: esc_html__( 'Enable Advanced PayPal Wallet', 'woocommerce-paypal-payments' );
|
||||
: esc_html__( 'Enable saving PayPal & Venmo', 'woocommerce-paypal-payments' );
|
||||
|
||||
$enable_url = $environment->current_environment_is( Environment::PRODUCTION )
|
||||
? $container->get( 'wcgateway.enable-reference-transactions-url-live' )
|
||||
|
|
|
@ -263,7 +263,7 @@ class SettingsPageAssets {
|
|||
'reference_transaction_enabled' => $this->billing_agreements_endpoint->reference_transaction_enabled(),
|
||||
'vaulting_must_enable_advanced_wallet_message' => sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
esc_html__( 'Your PayPal account must be enabled for the %1$sAdvanced PayPal Wallet%2$s to use PayPal Vaulting.', 'woocommerce-paypal-payments' ),
|
||||
esc_html__( 'Your PayPal account must be eligible to %1$ssave PayPal and Venmo payment methods%2$s to enable PayPal Vaulting.', 'woocommerce-paypal-payments' ),
|
||||
'<a href="/wp-admin/admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=ppcp-connection#field-credentials_feature_onboarding_heading">',
|
||||
'</a>'
|
||||
),
|
||||
|
|
|
@ -114,7 +114,7 @@ class CartCheckoutDetector {
|
|||
*/
|
||||
public static function has_classic_checkout(): bool {
|
||||
$checkout_page_id = wc_get_page_id( 'checkout' );
|
||||
return $checkout_page_id && has_block( 'woocommerce/classic-shortcode', $checkout_page_id );
|
||||
return $checkout_page_id && ( has_block( 'woocommerce/classic-shortcode', $checkout_page_id ) || self::has_classic_shortcode( $checkout_page_id, 'woocommerce_checkout' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,6 +124,25 @@ class CartCheckoutDetector {
|
|||
*/
|
||||
public static function has_classic_cart(): bool {
|
||||
$cart_page_id = wc_get_page_id( 'cart' );
|
||||
return $cart_page_id && has_block( 'woocommerce/classic-shortcode', $cart_page_id );
|
||||
return $cart_page_id && ( has_block( 'woocommerce/classic-shortcode', $cart_page_id ) || self::has_classic_shortcode( $cart_page_id, 'woocommerce_cart' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a page has a specific shortcode.
|
||||
*
|
||||
* @param int $page_id The ID of the page.
|
||||
* @param string $shortcode The shortcode to check for.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function has_classic_shortcode( int $page_id, string $shortcode ): bool {
|
||||
if ( ! $page_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$page = get_post( $page_id );
|
||||
$page_content = is_object( $page ) ? $page->post_content : '';
|
||||
|
||||
return str_contains( $page_content, $shortcode );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -411,7 +411,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
),
|
||||
'ppcp_reference_transactions_status' => array(
|
||||
'title' => __( 'Advanced PayPal Wallet', 'woocommerce-paypal-payments' ),
|
||||
'title' => __( 'Save PayPal & Venmo payment methods', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'ppcp-text',
|
||||
'text' => $container->get( 'wcgateway.settings.connection.reference-transactions-status-text' ),
|
||||
'screens' => array(
|
||||
|
|
|
@ -23,6 +23,7 @@ use WooCommerce\PayPalCommerce\Onboarding\Helper\OnboardingUrl;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\WooCommerce\Logging\Logger\NullLogger;
|
||||
|
@ -160,6 +161,13 @@ class SettingsListener {
|
|||
*/
|
||||
private $billing_agreements_endpoint;
|
||||
|
||||
/**
|
||||
* The subscription helper
|
||||
*
|
||||
* @var SubscriptionHelper
|
||||
*/
|
||||
protected $subscription_helper;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -185,6 +193,7 @@ class SettingsListener {
|
|||
* @param string $partner_merchant_id_production Partner merchant ID production.
|
||||
* @param string $partner_merchant_id_sandbox Partner merchant ID sandbox.
|
||||
* @param BillingAgreementsEndpoint $billing_agreements_endpoint Billing Agreements endpoint.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param ?LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
|
@ -203,6 +212,7 @@ class SettingsListener {
|
|||
string $partner_merchant_id_production,
|
||||
string $partner_merchant_id_sandbox,
|
||||
BillingAgreementsEndpoint $billing_agreements_endpoint,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
LoggerInterface $logger = null
|
||||
) {
|
||||
|
||||
|
@ -221,6 +231,7 @@ class SettingsListener {
|
|||
$this->partner_merchant_id_production = $partner_merchant_id_production;
|
||||
$this->partner_merchant_id_sandbox = $partner_merchant_id_sandbox;
|
||||
$this->billing_agreements_endpoint = $billing_agreements_endpoint;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger ?: new NullLogger();
|
||||
}
|
||||
|
||||
|
@ -392,6 +403,11 @@ class SettingsListener {
|
|||
$this->settings->persist();
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->plugin_is_active() ) {
|
||||
$this->settings->set( 'blocks_final_review_enabled', true );
|
||||
$this->settings->persist();
|
||||
}
|
||||
|
||||
if ( $subscription_mode === 'disable_paypal_subscriptions' && $vault_enabled === '1' ) {
|
||||
$this->settings->set( 'vault_enabled', false );
|
||||
$this->settings->persist();
|
||||
|
|
|
@ -185,6 +185,10 @@ If you encounter issues with the PayPal buttons not appearing after an update, p
|
|||
* Fix - Allow PUI Gateway for refund processor #2192
|
||||
* Fix - Notice on newly created block cart checkout #2211
|
||||
* Fix - Apple Pay button in the editor #2177
|
||||
* Fix - Allow shipping callback and skipping confirmation page from any express button #2236
|
||||
* Fix - Pay Later messaging configurator sometimes displays old settings after saving #2249
|
||||
* Fix - Update the apple-developer-merchantid-domain-association validation strings for Apple Pay #2251
|
||||
* Enhancement - Use admin theme color #1602
|
||||
|
||||
= 2.7.0 - 2024-04-30 =
|
||||
* Fix - Zero sum subscriptions cause CANNOT_BE_ZERO_OR_NEGATIVE when using Vault v3 #2152
|
||||
|
|
|
@ -3,16 +3,15 @@
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Requests_Utility_CaseInsensitiveDictionary;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingAgreementsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\Helper\RedirectorStub;
|
||||
use WooCommerce\PayPalCommerce\Helper\StubRedirectionException;
|
||||
use WooCommerce\PayPalCommerce\ModularTestCase;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use Mockery;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
|
||||
use function Brain\Monkey\Functions\when;
|
||||
|
||||
|
@ -42,6 +41,7 @@ class SettingsListenerTest extends ModularTestCase
|
|||
$pui_status_cache = Mockery::mock(Cache::class);
|
||||
$dcc_status_cache = Mockery::mock(Cache::class);
|
||||
$billing_agreement_endpoint = Mockery::mock(BillingAgreementsEndpoint::class);
|
||||
$subscription_helper = Mockery::mock(SubscriptionHelper::class);
|
||||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
|
||||
$testee = new SettingsListener(
|
||||
|
@ -60,6 +60,7 @@ class SettingsListenerTest extends ModularTestCase
|
|||
'',
|
||||
'',
|
||||
$billing_agreement_endpoint,
|
||||
$subscription_helper,
|
||||
$logger
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue