mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Merge trunk
This commit is contained in:
commit
4ee33d5fd0
25 changed files with 533 additions and 272 deletions
|
@ -1,5 +1,17 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 2.8.0 - xxxx-xx-xx =
|
||||
* Fix - Calculate totals after adding shipping to include taxes #2296
|
||||
* Fix - Package tracking integration throws error in 2.7.1 #2289
|
||||
* Fix - Make PayPal Subscription products unique in cart #2265
|
||||
* Fix - PayPal declares subscription support when merchant not enabled for Reference Transactions #2282
|
||||
* Fix - Google Pay and Apple Pay Settings button from Connection tab have wrong links #2273
|
||||
* Fix - Smart Buttons in Block Checkout not respecting the location setting (2830) #2278
|
||||
* Fix - Disable Pay Upon Invoice if billing/shipping country not set #2281
|
||||
* Enhancement - Enable shipping callback for WC subscriptions #2259
|
||||
* Enhancement - Disable the shipping callback for "venmo" when vaulting is active #2269
|
||||
* Enhancement - Improve "Could not retrieve order" error message #2271
|
||||
|
||||
= 2.7.1 - 2024-05-28 =
|
||||
* Fix - Ensure package tracking data is sent to original PayPal transaction #2180
|
||||
* Fix - Set the 'Woo_PPCP' as a default value for data-partner-attribution-id #2188
|
||||
|
|
|
@ -50,9 +50,7 @@ class ShippingOptionFactory {
|
|||
$cart->calculate_shipping();
|
||||
|
||||
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods', array() );
|
||||
if ( ! is_array( $chosen_shipping_methods ) ) {
|
||||
$chosen_shipping_methods = array();
|
||||
}
|
||||
$chosen_shipping_method = $chosen_shipping_methods[0] ?? false;
|
||||
|
||||
$packages = WC()->shipping()->get_packages();
|
||||
$options = array();
|
||||
|
@ -62,11 +60,10 @@ class ShippingOptionFactory {
|
|||
if ( ! $rate instanceof \WC_Shipping_Rate ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$options[] = new ShippingOption(
|
||||
$rate->get_id(),
|
||||
$rate->get_label(),
|
||||
in_array( $rate->get_id(), $chosen_shipping_methods, true ),
|
||||
$rate->get_id() === $chosen_shipping_method,
|
||||
new Money(
|
||||
(float) $rate->get_cost(),
|
||||
get_woocommerce_currency()
|
||||
|
|
|
@ -23,6 +23,9 @@ import {
|
|||
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
|
||||
import BlockCheckoutMessagesBootstrap from "./Bootstrap/BlockCheckoutMessagesBootstrap";
|
||||
import {keysToCamelCase} from "../../../ppcp-button/resources/js/modules/Helper/Utils";
|
||||
import {
|
||||
handleShippingOptionsChange
|
||||
} from "../../../ppcp-button/resources/js/modules/Helper/ShippingHandler";
|
||||
const config = wc.wcSettings.getSetting('ppcp-gateway_data');
|
||||
|
||||
window.ppcpFundingSource = config.fundingSource;
|
||||
|
@ -146,7 +149,7 @@ const PayPalComponent = ({
|
|||
shipping_address: addresses.shippingAddress,
|
||||
}),
|
||||
];
|
||||
if (!config.finalReviewEnabled) {
|
||||
if (shouldHandleShippingInPayPal()) {
|
||||
// set address in UI
|
||||
promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress));
|
||||
if (shippingData.needsShipping) {
|
||||
|
@ -181,7 +184,7 @@ const PayPalComponent = ({
|
|||
throw new Error(config.scriptData.labels.error.generic)
|
||||
}
|
||||
|
||||
if (config.finalReviewEnabled) {
|
||||
if (!shouldHandleShippingInPayPal()) {
|
||||
location.href = getCheckoutRedirectUrl();
|
||||
} else {
|
||||
setGotoContinuationOnError(true);
|
||||
|
@ -220,7 +223,7 @@ const PayPalComponent = ({
|
|||
shipping_address: addresses.shippingAddress,
|
||||
}),
|
||||
];
|
||||
if (!config.finalReviewEnabled) {
|
||||
if (shouldHandleShippingInPayPal()) {
|
||||
// set address in UI
|
||||
promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress));
|
||||
if (shippingData.needsShipping) {
|
||||
|
@ -255,7 +258,7 @@ const PayPalComponent = ({
|
|||
throw new Error(config.scriptData.labels.error.generic)
|
||||
}
|
||||
|
||||
if (config.finalReviewEnabled) {
|
||||
if (!shouldHandleShippingInPayPal()) {
|
||||
location.href = getCheckoutRedirectUrl();
|
||||
} else {
|
||||
setGotoContinuationOnError(true);
|
||||
|
@ -297,8 +300,12 @@ const PayPalComponent = ({
|
|||
onClick();
|
||||
};
|
||||
|
||||
const isVenmoAndVaultingEnabled = () => {
|
||||
return window.ppcpFundingSource === 'venmo' && config.scriptData.vaultingEnabled;
|
||||
const shouldHandleShippingInPayPal = () => {
|
||||
if (config.finalReviewEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return window.ppcpFundingSource !== 'venmo' || !config.scriptData.vaultingEnabled;
|
||||
}
|
||||
|
||||
let handleShippingOptionsChange = null;
|
||||
|
@ -306,7 +313,7 @@ const PayPalComponent = ({
|
|||
let handleSubscriptionShippingOptionsChange = null;
|
||||
let handleSubscriptionShippingAddressChange = null;
|
||||
|
||||
if (shippingData.needsShipping && !config.finalReviewEnabled) {
|
||||
if (shippingData.needsShipping && shouldHandleShippingInPayPal()) {
|
||||
handleShippingOptionsChange = async (data, actions) => {
|
||||
try {
|
||||
const shippingOptionId = data.selectedShippingOption?.id;
|
||||
|
@ -391,6 +398,21 @@ const PayPalComponent = ({
|
|||
|
||||
await shippingData.setShippingAddress(address);
|
||||
|
||||
const res = await fetch(config.ajax.update_shipping.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
|
@ -447,7 +469,7 @@ const PayPalComponent = ({
|
|||
if (config.scriptData.continuation) {
|
||||
return true;
|
||||
}
|
||||
if (!config.finalReviewEnabled) {
|
||||
if (shouldHandleShippingInPayPal()) {
|
||||
location.href = getCheckoutRedirectUrl();
|
||||
}
|
||||
return true;
|
||||
|
@ -493,8 +515,16 @@ const PayPalComponent = ({
|
|||
onError={onClose}
|
||||
createSubscription={createSubscription}
|
||||
onApprove={handleApproveSubscription}
|
||||
onShippingOptionsChange={handleSubscriptionShippingOptionsChange}
|
||||
onShippingAddressChange={handleSubscriptionShippingAddressChange}
|
||||
onShippingOptionsChange={(data, actions) => {
|
||||
shouldHandleShippingInPayPal()
|
||||
? handleSubscriptionShippingOptionsChange(data, actions)
|
||||
: null;
|
||||
}}
|
||||
onShippingAddressChange={(data, actions) => {
|
||||
shouldHandleShippingInPayPal()
|
||||
? handleSubscriptionShippingAddressChange(data, actions)
|
||||
: null;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -508,8 +538,16 @@ const PayPalComponent = ({
|
|||
onError={onClose}
|
||||
createOrder={createOrder}
|
||||
onApprove={handleApprove}
|
||||
onShippingOptionsChange={handleShippingOptionsChange}
|
||||
onShippingAddressChange={handleShippingAddressChange}
|
||||
onShippingOptionsChange={(data, actions) => {
|
||||
shouldHandleShippingInPayPal()
|
||||
? handleShippingOptionsChange(data, actions)
|
||||
: null;
|
||||
}}
|
||||
onShippingAddressChange={(data, actions) => {
|
||||
shouldHandleShippingInPayPal()
|
||||
? handleShippingAddressChange(data, actions)
|
||||
: null;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -568,7 +606,7 @@ if(cartHasSubscriptionProducts(config.scriptData)) {
|
|||
features.push('subscriptions');
|
||||
}
|
||||
|
||||
if (block_enabled) {
|
||||
if (block_enabled && config.enabled) {
|
||||
if ((config.addPlaceOrderMethod || config.usePlaceOrder) && !config.scriptData.continuation) {
|
||||
let descriptionElement = <div dangerouslySetInnerHTML={{__html: config.description}}></div>;
|
||||
if (config.placeOrderButtonDescription) {
|
||||
|
|
|
@ -23,7 +23,8 @@ class CartActionHandler {
|
|||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.approve_subscription.nonce,
|
||||
order_id: data.orderID,
|
||||
subscription_id: data.subscriptionID
|
||||
subscription_id: data.subscriptionID,
|
||||
should_create_wc_order: !context.config.vaultingEnabled || data.paymentSource !== 'venmo'
|
||||
})
|
||||
}).then((res)=>{
|
||||
return res.json();
|
||||
|
@ -33,7 +34,9 @@ class CartActionHandler {
|
|||
throw Error(data.data.message);
|
||||
}
|
||||
|
||||
location.href = this.config.redirect;
|
||||
let orderReceivedUrl = data.data?.order_received_url
|
||||
|
||||
location.href = orderReceivedUrl ? orderReceivedUrl : context.config.redirect;
|
||||
});
|
||||
},
|
||||
onError: (err) => {
|
||||
|
@ -60,8 +63,7 @@ class CartActionHandler {
|
|||
funding_source: window.ppcpFundingSource,
|
||||
bn_code:bnCode,
|
||||
payer,
|
||||
context:this.config.context,
|
||||
payment_source: data.paymentSource
|
||||
context:this.config.context
|
||||
}),
|
||||
}).then(function(res) {
|
||||
return res.json();
|
||||
|
|
|
@ -39,19 +39,21 @@ export const handleShippingOptionsChange = async (data, actions, config) => {
|
|||
})
|
||||
}
|
||||
|
||||
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,
|
||||
})
|
||||
});
|
||||
if (!config.data_client_id.has_subscriptions) {
|
||||
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();
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
throw new Error(json.data.message);
|
||||
if (!json.success) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@ -104,20 +106,20 @@ export const handleShippingAddressChange = async (data, actions, config) => {
|
|||
})
|
||||
})
|
||||
|
||||
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 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();
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
if (!json.success) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
|
|
|
@ -68,14 +68,6 @@ 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.
|
||||
|
@ -93,7 +85,16 @@ class Renderer {
|
|||
const options = {
|
||||
style,
|
||||
...contextConfig,
|
||||
onClick: this.onSmartButtonClick,
|
||||
onClick: (data, actions) => {
|
||||
if (this.onSmartButtonClick) {
|
||||
this.onSmartButtonClick(data, actions);
|
||||
}
|
||||
|
||||
venmoButtonClicked = false;
|
||||
if (data.fundingSource === 'venmo') {
|
||||
venmoButtonClicked = true;
|
||||
}
|
||||
},
|
||||
onInit: (data, actions) => {
|
||||
if (this.onSmartButtonsInit) {
|
||||
this.onSmartButtonsInit(data, actions);
|
||||
|
@ -103,9 +104,17 @@ class Renderer {
|
|||
};
|
||||
|
||||
// Check the condition and add the handler if needed
|
||||
if (this.shouldHandleShippingInPaypal(venmoButtonClicked)) {
|
||||
options.onShippingOptionsChange = (data, actions) => handleShippingOptionsChange(data, actions, this.defaultSettings);
|
||||
options.onShippingAddressChange = (data, actions) => handleShippingAddressChange(data, actions, this.defaultSettings);
|
||||
if (this.defaultSettings.should_handle_shipping_in_paypal) {
|
||||
options.onShippingOptionsChange = (data, actions) => {
|
||||
!this.isVenmoButtonClickedWhenVaultingIsEnabled(venmoButtonClicked)
|
||||
? handleShippingOptionsChange(data, actions, this.defaultSettings)
|
||||
: null;
|
||||
}
|
||||
options.onShippingAddressChange = (data, actions) => {
|
||||
!this.isVenmoButtonClickedWhenVaultingIsEnabled(venmoButtonClicked)
|
||||
? handleShippingAddressChange(data, actions, this.defaultSettings)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
|
@ -139,6 +148,10 @@ class Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
isVenmoButtonClickedWhenVaultingIsEnabled = (venmoButtonClicked) => {
|
||||
return venmoButtonClicked && this.defaultSettings.vaultingEnabled;
|
||||
}
|
||||
|
||||
isAlreadyRendered(wrapper, fundingSource) {
|
||||
return this.renderedSources.has(wrapper + (fundingSource ?? ''));
|
||||
}
|
||||
|
|
|
@ -239,7 +239,6 @@ return array(
|
|||
$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,
|
||||
|
@ -252,7 +251,6 @@ return array(
|
|||
$final_review_enabled,
|
||||
$gateway,
|
||||
$wc_order_creator,
|
||||
$subscription_helper,
|
||||
$logger
|
||||
);
|
||||
},
|
||||
|
@ -260,7 +258,10 @@ return array(
|
|||
return new ApproveSubscriptionEndpoint(
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'session.handler' )
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'blocks.settings.final_review_enabled' ),
|
||||
$container->get( 'button.helper.wc-order-creator' ),
|
||||
$container->get( 'wcgateway.paypal-gateway' )
|
||||
);
|
||||
},
|
||||
'button.checkout-form-saver' => static function ( ContainerInterface $container ): CheckoutFormSaver {
|
||||
|
@ -362,6 +363,10 @@ return array(
|
|||
},
|
||||
|
||||
'button.helper.wc-order-creator' => static function ( ContainerInterface $container ): WooCommerceOrderCreator {
|
||||
return new WooCommerceOrderCreator( $container->get( 'wcgateway.funding-source.renderer' ), $container->get( 'session.handler' ) );
|
||||
return new WooCommerceOrderCreator(
|
||||
$container->get( 'wcgateway.funding-source.renderer' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'wc-subscriptions.helper' )
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -105,13 +105,6 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
*/
|
||||
protected $wc_order_creator;
|
||||
|
||||
/**
|
||||
* The Subscription Helper.
|
||||
*
|
||||
* @var SubscriptionHelper
|
||||
*/
|
||||
protected $subscription_helper;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -132,7 +125,6 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
* @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(
|
||||
|
@ -146,7 +138,6 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
bool $final_review_enabled,
|
||||
PayPalGateway $gateway,
|
||||
WooCommerceOrderCreator $wc_order_creator,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
|
@ -160,7 +151,6 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
$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;
|
||||
}
|
||||
|
||||
|
@ -247,7 +237,7 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
|
||||
$this->session_handler->replace_order( $order );
|
||||
|
||||
if ( ! $this->subscription_helper->plugin_is_active() && apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ) ) {
|
||||
if ( apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ) ) {
|
||||
$this->toggle_final_review_enabled_setting();
|
||||
}
|
||||
|
||||
|
|
|
@ -11,13 +11,18 @@ namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
|||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\WooCommerceOrderCreator;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
||||
/**
|
||||
* Class ApproveSubscriptionEndpoint
|
||||
*/
|
||||
class ApproveSubscriptionEndpoint implements EndpointInterface {
|
||||
|
||||
use ContextTrait;
|
||||
|
||||
const ENDPOINT = 'ppc-approve-subscription';
|
||||
|
||||
/**
|
||||
|
@ -41,21 +46,51 @@ class ApproveSubscriptionEndpoint implements EndpointInterface {
|
|||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* Whether the final review is enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $final_review_enabled;
|
||||
|
||||
/**
|
||||
* The WooCommerce order creator.
|
||||
*
|
||||
* @var WooCommerceOrderCreator
|
||||
*/
|
||||
protected $wc_order_creator;
|
||||
|
||||
/**
|
||||
* The WC gateway.
|
||||
*
|
||||
* @var PayPalGateway
|
||||
*/
|
||||
protected $gateway;
|
||||
|
||||
/**
|
||||
* ApproveSubscriptionEndpoint constructor.
|
||||
*
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
* @param bool $final_review_enabled Whether the final review is enabled.
|
||||
* @param WooCommerceOrderCreator $wc_order_creator The WooCommerce order creator.
|
||||
* @param PayPalGateway $gateway The WC gateway.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
OrderEndpoint $order_endpoint,
|
||||
SessionHandler $session_handler
|
||||
SessionHandler $session_handler,
|
||||
bool $final_review_enabled,
|
||||
WooCommerceOrderCreator $wc_order_creator,
|
||||
PayPalGateway $gateway
|
||||
) {
|
||||
$this->request_data = $request_data;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->request_data = $request_data;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->final_review_enabled = $final_review_enabled;
|
||||
$this->wc_order_creator = $wc_order_creator;
|
||||
$this->gateway = $gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,6 +123,15 @@ class ApproveSubscriptionEndpoint implements EndpointInterface {
|
|||
WC()->session->set( 'ppcp_subscription_id', $data['subscription_id'] );
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
|
|
@ -246,7 +246,6 @@ 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'] );
|
||||
|
@ -262,7 +261,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->should_handle_shipping_in_paypal( $payment_source ) );
|
||||
$this->purchase_unit = $this->purchase_unit_factory->from_wc_cart( null, $this->should_handle_shipping_in_paypal( $funding_source ) );
|
||||
|
||||
// Do not allow completion by webhooks when started via non-checkout buttons,
|
||||
// it is needed only for some APMs in checkout.
|
||||
|
@ -615,16 +614,16 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
/**
|
||||
* Checks if the shipping should be handled in PayPal popup.
|
||||
*
|
||||
* @param string $payment_source The payment source.
|
||||
* @param string $funding_source The funding 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 {
|
||||
protected function should_handle_shipping_in_paypal( string $funding_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';
|
||||
return ! $is_vaulting_enabled || $funding_source !== 'venmo';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,12 +14,16 @@ use WC_Cart;
|
|||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Order_Item_Shipping;
|
||||
use WC_Subscription;
|
||||
use WC_Subscriptions_Product;
|
||||
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;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class WooCommerceOrderCreator
|
||||
|
@ -40,18 +44,28 @@ class WooCommerceOrderCreator {
|
|||
*/
|
||||
protected $session_handler;
|
||||
|
||||
/**
|
||||
* The subscription helper
|
||||
*
|
||||
* @var SubscriptionHelper
|
||||
*/
|
||||
protected $subscription_helper;
|
||||
|
||||
/**
|
||||
* WooCommerceOrderCreator constructor.
|
||||
*
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
*/
|
||||
public function __construct(
|
||||
FundingSourceRenderer $funding_source_renderer,
|
||||
SessionHandler $session_handler
|
||||
SessionHandler $session_handler,
|
||||
SubscriptionHelper $subscription_helper
|
||||
) {
|
||||
$this->funding_source_renderer = $funding_source_renderer;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,10 +83,13 @@ class WooCommerceOrderCreator {
|
|||
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() );
|
||||
$payer = $order->payer();
|
||||
$shipping = $order->purchase_units()[0]->shipping();
|
||||
|
||||
$this->configure_payment_source( $wc_order );
|
||||
$this->configure_customer( $wc_order );
|
||||
$this->configure_line_items( $wc_order, $wc_cart, $payer, $shipping );
|
||||
$this->configure_shipping( $wc_order, $payer, $shipping );
|
||||
$this->configure_coupons( $wc_order, $wc_cart->get_applied_coupons() );
|
||||
|
||||
$wc_order->calculate_totals();
|
||||
|
@ -84,11 +101,13 @@ class WooCommerceOrderCreator {
|
|||
/**
|
||||
* Configures the line items.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @param WC_Cart $wc_cart The Cart.
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @param WC_Cart $wc_cart The Cart.
|
||||
* @param Payer|null $payer The payer.
|
||||
* @param Shipping|null $shipping The shipping.
|
||||
* @return void
|
||||
*/
|
||||
protected function configure_line_items( WC_Order $wc_order, WC_Cart $wc_cart ): void {
|
||||
protected function configure_line_items( WC_Order $wc_order, WC_Cart $wc_cart, ?Payer $payer, ?Shipping $shipping ): void {
|
||||
$cart_contents = $wc_cart->get_cart();
|
||||
|
||||
foreach ( $cart_contents as $cart_item ) {
|
||||
|
@ -111,9 +130,37 @@ class WooCommerceOrderCreator {
|
|||
return;
|
||||
}
|
||||
|
||||
$total = $product->get_price() * $quantity;
|
||||
|
||||
$item->set_name( $product->get_name() );
|
||||
$item->set_subtotal( $product->get_price() * $quantity );
|
||||
$item->set_total( $product->get_price() * $quantity );
|
||||
$item->set_subtotal( $total );
|
||||
$item->set_total( $total );
|
||||
|
||||
$product_id = $product->get_id();
|
||||
|
||||
if ( $this->is_subscription( $product_id ) ) {
|
||||
$subscription = $this->create_subscription( $wc_order, $product_id );
|
||||
$sign_up_fee = WC_Subscriptions_Product::get_sign_up_fee( $product );
|
||||
$subscription_total = $total + $sign_up_fee;
|
||||
|
||||
$item->set_subtotal( $subscription_total );
|
||||
$item->set_total( $subscription_total );
|
||||
|
||||
$subscription->add_product( $product );
|
||||
$this->configure_shipping( $subscription, $payer, $shipping );
|
||||
$this->configure_payment_source( $subscription );
|
||||
$this->configure_coupons( $subscription, $wc_cart->get_applied_coupons() );
|
||||
|
||||
$dates = array(
|
||||
'trial_end' => WC_Subscriptions_Product::get_trial_expiration_date( $product_id ),
|
||||
'next_payment' => WC_Subscriptions_Product::get_first_renewal_payment_date( $product_id ),
|
||||
'end' => WC_Subscriptions_Product::get_expiration_date( $product_id ),
|
||||
);
|
||||
|
||||
$subscription->update_dates( $dates );
|
||||
$subscription->calculate_totals();
|
||||
$subscription->payment_complete_for_order( $wc_order );
|
||||
}
|
||||
|
||||
$wc_order->add_item( $item );
|
||||
}
|
||||
|
@ -179,8 +226,18 @@ class WooCommerceOrderCreator {
|
|||
$shipping->set_method_id( $shipping_options->id() );
|
||||
$shipping->set_total( $shipping_options->amount()->value_str() );
|
||||
|
||||
$items = $wc_order->get_items();
|
||||
$items_in_package = array();
|
||||
foreach ( $items as $item ) {
|
||||
$items_in_package[] = $item->get_name() . ' × ' . (string) $item->get_quantity();
|
||||
}
|
||||
|
||||
$shipping->add_meta_data( __( 'Items', 'woocommerce-paypal-payments' ), implode( ', ', $items_in_package ) );
|
||||
|
||||
$wc_order->add_item( $shipping );
|
||||
}
|
||||
|
||||
$wc_order->calculate_totals();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -225,4 +282,43 @@ class WooCommerceOrderCreator {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the product with given ID is WC subscription.
|
||||
*
|
||||
* @param int $product_id The product ID.
|
||||
* @return bool true if the product is subscription, otherwise false.
|
||||
*/
|
||||
protected function is_subscription( int $product_id ): bool {
|
||||
if ( ! $this->subscription_helper->plugin_is_active() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return WC_Subscriptions_Product::is_subscription( $product_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates WC subscription from given order and product ID.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @param int $product_id The product ID.
|
||||
* @return WC_Subscription The subscription order
|
||||
* @throws RuntimeException If problem creating.
|
||||
*/
|
||||
protected function create_subscription( WC_Order $wc_order, int $product_id ): WC_Subscription {
|
||||
$subscription = wcs_create_subscription(
|
||||
array(
|
||||
'order_id' => $wc_order->get_id(),
|
||||
'status' => 'pending',
|
||||
'billing_period' => WC_Subscriptions_Product::get_period( $product_id ),
|
||||
'billing_interval' => WC_Subscriptions_Product::get_interval( $product_id ),
|
||||
'customer_id' => $wc_order->get_customer_id(),
|
||||
)
|
||||
);
|
||||
|
||||
if ( $subscription instanceof WP_Error ) {
|
||||
throw new RuntimeException( $subscription->get_error_message() );
|
||||
}
|
||||
|
||||
return $subscription;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,34 +73,34 @@ class GermanizedShipmentIntegration implements Integration {
|
|||
add_action(
|
||||
'woocommerce_gzd_shipment_status_shipped',
|
||||
function( int $shipment_id, Shipment $shipment ) {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_gzd_tracking', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wc_order = $shipment->get_order();
|
||||
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$wc_order_id = $wc_order->get_id();
|
||||
$tracking_number = $shipment->get_tracking_id();
|
||||
$carrier = $shipment->get_shipping_provider();
|
||||
|
||||
$items = array_map(
|
||||
function ( ShipmentItem $item ): int {
|
||||
return $item->get_order_item_id();
|
||||
},
|
||||
$shipment->get_items()
|
||||
);
|
||||
|
||||
if ( ! $tracking_number || ! $carrier || ! $capture_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_gzd_tracking', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wc_order = $shipment->get_order();
|
||||
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$wc_order_id = $wc_order->get_id();
|
||||
$tracking_number = $shipment->get_tracking_id();
|
||||
$carrier = $shipment->get_shipping_provider();
|
||||
|
||||
$items = array_map(
|
||||
function ( ShipmentItem $item ): int {
|
||||
return $item->get_order_item_id();
|
||||
},
|
||||
$shipment->get_items()
|
||||
);
|
||||
|
||||
if ( ! $tracking_number || ! $carrier || ! $capture_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ppcp_shipment = $this->shipment_factory->create_shipment(
|
||||
$wc_order_id,
|
||||
$capture_id,
|
||||
|
@ -118,7 +118,7 @@ class GermanizedShipmentIntegration implements Integration {
|
|||
: $this->endpoint->add_tracking_information( $ppcp_shipment, $wc_order_id );
|
||||
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( "Couldn't sync tracking information: " . $exception->getMessage() );
|
||||
return;
|
||||
}
|
||||
},
|
||||
500,
|
||||
|
|
|
@ -76,25 +76,25 @@ class ShipStationIntegration implements Integration {
|
|||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function( $wc_order, array $data ) {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_ship_station_tracking', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$order_id = $wc_order->get_id();
|
||||
$tracking_number = $data['tracking_number'] ?? '';
|
||||
$carrier = $data['carrier'] ?? '';
|
||||
|
||||
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_ship_station_tracking', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$order_id = $wc_order->get_id();
|
||||
$tracking_number = $data['tracking_number'] ?? '';
|
||||
$carrier = $data['carrier'] ?? '';
|
||||
|
||||
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ppcp_shipment = $this->shipment_factory->create_shipment(
|
||||
$order_id,
|
||||
$capture_id,
|
||||
|
@ -112,7 +112,7 @@ class ShipStationIntegration implements Integration {
|
|||
: $this->endpoint->add_tracking_information( $ppcp_shipment, $order_id );
|
||||
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( "Couldn't sync tracking information: " . $exception->getMessage() );
|
||||
return;
|
||||
}
|
||||
},
|
||||
500,
|
||||
|
|
|
@ -73,30 +73,35 @@ class ShipmentTrackingIntegration implements Integration {
|
|||
add_action(
|
||||
'wp_ajax_wc_shipment_tracking_save_form',
|
||||
function() {
|
||||
check_ajax_referer( 'create-tracking-item', 'security', true );
|
||||
try {
|
||||
check_ajax_referer( 'create-tracking-item', 'security', true );
|
||||
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_wc_shipment_tracking', true ) ) {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_wc_shipment_tracking', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order_id = (int) wc_clean( wp_unslash( $_POST['order_id'] ?? '' ) );
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$tracking_number = wc_clean( wp_unslash( $_POST['tracking_number'] ?? '' ) );
|
||||
$carrier = wc_clean( wp_unslash( $_POST['tracking_provider'] ?? '' ) );
|
||||
$carrier_other = wc_clean( wp_unslash( $_POST['custom_tracking_provider'] ?? '' ) );
|
||||
$carrier = $carrier ?: $carrier_other ?: '';
|
||||
|
||||
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sync_tracking( $order_id, $capture_id, $tracking_number, $carrier );
|
||||
|
||||
} catch ( Exception $exception ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order_id = (int) wc_clean( wp_unslash( $_POST['order_id'] ?? '' ) );
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$tracking_number = wc_clean( wp_unslash( $_POST['tracking_number'] ?? '' ) );
|
||||
$carrier = wc_clean( wp_unslash( $_POST['tracking_provider'] ?? '' ) );
|
||||
$carrier_other = wc_clean( wp_unslash( $_POST['custom_tracking_provider'] ?? '' ) );
|
||||
$carrier = $carrier ?: $carrier_other ?: '';
|
||||
|
||||
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sync_tracking( $order_id, $capture_id, $tracking_number, $carrier );
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -106,34 +111,39 @@ class ShipmentTrackingIntegration implements Integration {
|
|||
add_filter(
|
||||
'woocommerce_rest_prepare_order_shipment_tracking',
|
||||
function( WP_REST_Response $response, array $tracking_item, WP_REST_Request $request ): WP_REST_Response {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_wc_shipment_tracking', true ) ) {
|
||||
try {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_wc_shipment_tracking', true ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$callback = $request->get_attributes()['callback']['1'] ?? '';
|
||||
if ( $callback !== 'create_item' ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$order_id = $tracking_item['order_id'] ?? 0;
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$tracking_number = $tracking_item['tracking_number'] ?? '';
|
||||
$carrier = $tracking_item['tracking_provider'] ?? '';
|
||||
$carrier_other = $tracking_item['custom_tracking_provider'] ?? '';
|
||||
$carrier = $carrier ?: $carrier_other ?: '';
|
||||
|
||||
if ( ! $tracking_number || ! $carrier || ! $capture_id ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$this->sync_tracking( $order_id, $capture_id, $tracking_number, $carrier );
|
||||
|
||||
} catch ( Exception $exception ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$callback = $request->get_attributes()['callback']['1'] ?? '';
|
||||
if ( $callback !== 'create_item' ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$order_id = $tracking_item['order_id'] ?? 0;
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$tracking_number = $tracking_item['tracking_number'] ?? '';
|
||||
$carrier = $tracking_item['tracking_provider'] ?? '';
|
||||
$carrier_other = $tracking_item['custom_tracking_provider'] ?? '';
|
||||
$carrier = $carrier ?: $carrier_other ?: '';
|
||||
|
||||
if ( ! $tracking_number || ! $carrier || ! $capture_id ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$this->sync_tracking( $order_id, $capture_id, $tracking_number, $carrier );
|
||||
|
||||
return $response;
|
||||
},
|
||||
10,
|
||||
|
|
|
@ -75,44 +75,48 @@ class WcShippingTaxIntegration implements Integration {
|
|||
add_filter(
|
||||
'rest_post_dispatch',
|
||||
function( WP_HTTP_Response $response, WP_REST_Server $server, WP_REST_Request $request ): WP_HTTP_Response {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_wc_shipping_tax', true ) ) {
|
||||
try {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_wc_shipping_tax', true ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$params = $request->get_params();
|
||||
$order_id = (int) ( $params['order_id'] ?? 0 );
|
||||
$label_id = (int) ( $params['label_ids'] ?? 0 );
|
||||
|
||||
if ( ! $order_id || "/wc/v1/connect/label/{$order_id}/{$label_id}" !== $request->get_route() ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data = $response->get_data() ?? array();
|
||||
$labels = $data['labels'] ?? array();
|
||||
|
||||
foreach ( $labels as $label ) {
|
||||
$tracking_number = $label['tracking'] ?? '';
|
||||
if ( ! $tracking_number ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$carrier = $label['carrier_id'] ?? $label['service_name'] ?? '';
|
||||
$items = array_map( 'intval', $label['product_ids'] ?? array() );
|
||||
|
||||
if ( ! $carrier || ! $capture_id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->sync_tracking( $order_id, $capture_id, $tracking_number, $carrier, $items );
|
||||
}
|
||||
} catch ( Exception $exception ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$params = $request->get_params();
|
||||
$order_id = (int) ( $params['order_id'] ?? 0 );
|
||||
$label_id = (int) ( $params['label_ids'] ?? 0 );
|
||||
|
||||
if ( ! $order_id || "/wc/v1/connect/label/{$order_id}/{$label_id}" !== $request->get_route() ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data = $response->get_data() ?? array();
|
||||
$labels = $data['labels'] ?? array();
|
||||
|
||||
foreach ( $labels as $label ) {
|
||||
$tracking_number = $label['tracking'] ?? '';
|
||||
if ( ! $tracking_number ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$carrier = $label['carrier_id'] ?? $label['service_name'] ?? '';
|
||||
$items = array_map( 'intval', $label['product_ids'] ?? array() );
|
||||
|
||||
if ( ! $carrier || ! $capture_id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->sync_tracking( $order_id, $capture_id, $tracking_number, $carrier, $items );
|
||||
}
|
||||
|
||||
return $response;
|
||||
},
|
||||
10,
|
||||
|
|
|
@ -71,27 +71,27 @@ class YithShipmentIntegration implements Integration {
|
|||
add_action(
|
||||
'woocommerce_process_shop_order_meta',
|
||||
function( int $order_id ) {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_ywot_tracking', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$tracking_number = wc_clean( wp_unslash( $_POST['ywot_tracking_code'] ?? '' ) );
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$carrier = wc_clean( wp_unslash( $_POST['ywot_carrier_name'] ?? '' ) );
|
||||
|
||||
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_ywot_tracking', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$tracking_number = wc_clean( wp_unslash( $_POST['ywot_tracking_code'] ?? '' ) );
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$carrier = wc_clean( wp_unslash( $_POST['ywot_carrier_name'] ?? '' ) );
|
||||
|
||||
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ppcp_shipment = $this->shipment_factory->create_shipment(
|
||||
$order_id,
|
||||
$capture_id,
|
||||
|
@ -109,7 +109,7 @@ class YithShipmentIntegration implements Integration {
|
|||
: $this->endpoint->add_tracking_information( $ppcp_shipment, $order_id );
|
||||
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( "Couldn't sync tracking information: " . $exception->getMessage() );
|
||||
return;
|
||||
}
|
||||
},
|
||||
500,
|
||||
|
|
|
@ -38,6 +38,9 @@ document.addEventListener(
|
|||
|
||||
const subscriptionTrial = document.querySelector('._subscription_trial_length_field');
|
||||
subscriptionTrial.style.display = 'none';
|
||||
|
||||
const soldIndividually = document.querySelector( '#_sold_individually' );
|
||||
soldIndividually.setAttribute( 'disabled', 'disabled' );
|
||||
}
|
||||
|
||||
const setupProducts = () => {
|
||||
|
|
|
@ -87,6 +87,44 @@ class PayPalSubscriptionsModule implements ModuleInterface {
|
|||
12
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_add_to_cart_validation',
|
||||
/**
|
||||
* Param types removed to avoid third-party issues.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
static function ( $passed_validation, $product_id ) {
|
||||
if ( WC()->cart->is_empty() ) {
|
||||
return $passed_validation;
|
||||
}
|
||||
|
||||
$product = wc_get_product( $product_id );
|
||||
|
||||
if ( $product && $product->get_meta( '_ppcp_enable_subscription_product', true ) === 'yes' ) {
|
||||
if ( ! $product->get_sold_individually() ) {
|
||||
$product->set_sold_individually( true );
|
||||
$product->save();
|
||||
}
|
||||
|
||||
wc_add_notice( __( 'You cannot add a subscription product to a cart with other items.', 'woocommerce-paypal-payments' ), 'error' );
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
|
||||
$cart_product = wc_get_product( $cart_item['product_id'] );
|
||||
if ( $cart_product && $cart_product->get_meta( '_ppcp_enable_subscription_product', true ) === 'yes' ) {
|
||||
wc_add_notice( __( 'You can only have one subscription product in your cart.', 'woocommerce-paypal-payments' ), 'error' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $passed_validation;
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_save_product_variation',
|
||||
/**
|
||||
|
@ -654,12 +692,18 @@ class PayPalSubscriptionsModule implements ModuleInterface {
|
|||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
$enable_subscription_product = wc_clean( wp_unslash( $_POST['_ppcp_enable_subscription_product'] ?? '' ) );
|
||||
$product->update_meta_data( '_ppcp_enable_subscription_product', $enable_subscription_product );
|
||||
|
||||
if ( ! $product->get_sold_individually() ) {
|
||||
$product->set_sold_individually( true );
|
||||
}
|
||||
|
||||
$product->save();
|
||||
|
||||
if ( ( $product->get_type() === 'subscription' || $product->get_type() === 'subscription_variation' ) && $enable_subscription_product === 'yes' ) {
|
||||
if ( $product->meta_exists( 'ppcp_subscription_product' ) && $product->meta_exists( 'ppcp_subscription_plan' ) ) {
|
||||
$subscriptions_api_handler->update_product( $product );
|
||||
$subscriptions_api_handler->update_plan( $product );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -347,7 +347,6 @@ 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
|
||||
);
|
||||
},
|
||||
|
|
|
@ -56,14 +56,14 @@ class PayUponInvoiceHelper {
|
|||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$billing_country = wc_clean( wp_unslash( $_POST['country'] ?? '' ) );
|
||||
if ( $billing_country && 'DE' !== $billing_country ) {
|
||||
$billing_country = WC()->customer->get_billing_country();
|
||||
if ( empty( $billing_country ) || 'DE' !== $billing_country ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$shipping_country = wc_clean( wp_unslash( $_POST['s_country'] ?? '' ) );
|
||||
if ( $shipping_country && 'DE' !== $shipping_country ) {
|
||||
$shipping_country = WC()->customer->get_shipping_country();
|
||||
if ( empty( $shipping_country ) || 'DE' !== $shipping_country ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Repository\Repository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingAgreementsEndpoint;
|
||||
|
@ -23,9 +21,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;
|
||||
|
||||
/**
|
||||
|
@ -161,13 +157,6 @@ class SettingsListener {
|
|||
*/
|
||||
private $billing_agreements_endpoint;
|
||||
|
||||
/**
|
||||
* The subscription helper
|
||||
*
|
||||
* @var SubscriptionHelper
|
||||
*/
|
||||
protected $subscription_helper;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -193,7 +182,6 @@ 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(
|
||||
|
@ -212,7 +200,6 @@ class SettingsListener {
|
|||
string $partner_merchant_id_production,
|
||||
string $partner_merchant_id_sandbox,
|
||||
BillingAgreementsEndpoint $billing_agreements_endpoint,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
LoggerInterface $logger = null
|
||||
) {
|
||||
|
||||
|
@ -231,7 +218,6 @@ 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();
|
||||
}
|
||||
|
||||
|
@ -394,7 +380,18 @@ class SettingsListener {
|
|||
|
||||
if ( $reference_transaction_enabled !== true ) {
|
||||
$this->settings->set( 'vault_enabled', false );
|
||||
$this->settings->set( 'subscriptions_mode', 'subscriptions_api' );
|
||||
|
||||
/**
|
||||
* If Vaulting-API was previously enabled, then fall-back to the
|
||||
* PayPal subscription mode, to ensure subscriptions are still
|
||||
* possible on this shop.
|
||||
*
|
||||
* This can happen when switching to a different PayPal merchant account
|
||||
*/
|
||||
if ( 'vaulting_api' === $subscription_mode ) {
|
||||
$this->settings->set( 'subscriptions_mode', 'subscriptions_api' );
|
||||
}
|
||||
|
||||
$this->settings->persist();
|
||||
}
|
||||
|
||||
|
@ -403,11 +400,6 @@ 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();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "woocommerce-paypal-payments",
|
||||
"version": "2.7.1",
|
||||
"version": "2.8.0",
|
||||
"description": "WooCommerce PayPal Payments",
|
||||
"repository": "https://github.com/woocommerce/woocommerce-paypal-payments",
|
||||
"license": "GPL-2.0",
|
||||
|
|
14
readme.txt
14
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.5
|
||||
Requires PHP: 7.2
|
||||
Stable tag: 2.7.1
|
||||
Stable tag: 2.8.0
|
||||
License: GPLv2
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
|
@ -191,6 +191,18 @@ If you encounter issues with the PayPal buttons not appearing after an update, p
|
|||
* Fix - Enable the Shipping Callback handlers #2266
|
||||
* Enhancement - Use admin theme color #1602
|
||||
|
||||
= 2.8.0 - xxxx-xx-xx =
|
||||
* Fix - Calculate totals after adding shipping to include taxes #2296
|
||||
* Fix - Package tracking integration throws error in 2.7.1 #2289
|
||||
* Fix - Make PayPal Subscription products unique in cart #2265
|
||||
* Fix - PayPal declares subscription support when merchant not enabled for Reference Transactions #2282
|
||||
* Fix - Google Pay and Apple Pay Settings button from Connection tab have wrong links #2273
|
||||
* Fix - Smart Buttons in Block Checkout not respecting the location setting (2830) #2278
|
||||
* Fix - Disable Pay Upon Invoice if billing/shipping country not set #2281
|
||||
* Enhancement - Enable shipping callback for WC subscriptions #2259
|
||||
* Enhancement - Disable the shipping callback for "venmo" when vaulting is active #2269
|
||||
* Enhancement - Improve "Could not retrieve order" error message #2271
|
||||
|
||||
= 2.7.0 - 2024-04-30 =
|
||||
* Fix - Zero sum subscriptions cause CANNOT_BE_ZERO_OR_NEGATIVE when using Vault v3 #2152
|
||||
* Fix - Incorrect Pricing Issue with Variable Subscriptions in PayPal Subscriptions Mode #2156
|
||||
|
|
|
@ -60,7 +60,6 @@ class SettingsListenerTest extends ModularTestCase
|
|||
'',
|
||||
'',
|
||||
$billing_agreement_endpoint,
|
||||
$subscription_helper,
|
||||
$logger
|
||||
);
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
* Plugin Name: WooCommerce PayPal Payments
|
||||
* Plugin URI: https://woocommerce.com/products/woocommerce-paypal-payments/
|
||||
* Description: PayPal's latest complete payments processing solution. Accept PayPal, Pay Later, credit/debit cards, alternative digital wallets local payment types and bank accounts. Turn on only PayPal options or process a full suite of payment methods. Enable global transaction with extensive currency and country coverage.
|
||||
* Version: 2.7.1
|
||||
* Version: 2.8.0
|
||||
* Author: WooCommerce
|
||||
* Author URI: https://woocommerce.com/
|
||||
* License: GPL-2.0
|
||||
* Requires PHP: 7.2
|
||||
* Requires Plugins: woocommerce
|
||||
* WC requires at least: 3.9
|
||||
* WC tested up to: 8.8
|
||||
* WC tested up to: 8.9
|
||||
* Text Domain: woocommerce-paypal-payments
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce
|
||||
|
@ -26,7 +26,7 @@ define( 'PAYPAL_API_URL', 'https://api-m.paypal.com' );
|
|||
define( 'PAYPAL_URL', 'https://www.paypal.com' );
|
||||
define( 'PAYPAL_SANDBOX_API_URL', 'https://api-m.sandbox.paypal.com' );
|
||||
define( 'PAYPAL_SANDBOX_URL', 'https://www.sandbox.paypal.com' );
|
||||
define( 'PAYPAL_INTEGRATION_DATE', '2024-05-13' );
|
||||
define( 'PAYPAL_INTEGRATION_DATE', '2024-06-03' );
|
||||
|
||||
! defined( 'CONNECT_WOO_CLIENT_ID' ) && define( 'CONNECT_WOO_CLIENT_ID', 'AcCAsWta_JTL__OfpjspNyH7c1GGHH332fLwonA5CwX4Y10mhybRZmHLA0GdRbwKwjQIhpDQy0pluX_P' );
|
||||
! defined( 'CONNECT_WOO_SANDBOX_CLIENT_ID' ) && define( 'CONNECT_WOO_SANDBOX_CLIENT_ID', 'AYmOHbt1VHg-OZ_oihPdzKEVbU3qg0qXonBcAztuzniQRaKE0w1Hr762cSFwd4n8wxOl-TCWohEa0XM_' );
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue