mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Merge branch 'trunk' into pcp-328-mismatch
This commit is contained in:
commit
84a5d9cd0f
22 changed files with 215 additions and 58 deletions
|
@ -1,5 +1,17 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 1.8.2 - TBD =
|
||||
* Fix - Order not approved: payment via vaulted PayPal account fails #677
|
||||
* Fix - Cant' refund : "ERROR Refund failed: No country given for address." #639
|
||||
* Fix - Something went wrong error in Virtual products when using vaulted payment #673
|
||||
* Fix - PayPal smart buttons are not displayed for product variations when parent product is set to out of stock #669
|
||||
* Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
|
||||
* Fix - "Capture Virtual-Only Orders" intent sets virtual+downloadable product orders to "Processing" instead of "Completed" #665
|
||||
* Fix - Free trial period causing incorrerct disable-funding parameters with DCC disabled #661
|
||||
* Fix - Smart button not visible on single product page when product price is below 1 and decimal is "," #654
|
||||
* Fix - Checkout using an email address containing a + symbol results in a "[INVALID_REQUEST]" error #523
|
||||
* Enhancement - Improve checkout validation & order creation #513
|
||||
|
||||
= 1.8.1 - 2022-05-31 =
|
||||
* Fix - Manual orders return an error for guest users when paying with PayPal Card Processing #530
|
||||
* Fix - "No PayPal order found in the current WooCommerce session" error for guests on Pay for Order page #605
|
||||
|
|
|
@ -47,6 +47,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository;
|
||||
|
@ -671,4 +672,7 @@ return array(
|
|||
'SE',
|
||||
);
|
||||
},
|
||||
'api.order-helper' => static function( ContainerInterface $container ): OrderHelper {
|
||||
return new OrderHelper();
|
||||
},
|
||||
);
|
||||
|
|
|
@ -69,13 +69,8 @@ class AddressFactory {
|
|||
* @throws RuntimeException When JSON object is malformed.
|
||||
*/
|
||||
public function from_paypal_response( \stdClass $data ): Address {
|
||||
if ( ! isset( $data->country_code ) ) {
|
||||
throw new RuntimeException(
|
||||
__( 'No country given for address.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
return new Address(
|
||||
$data->country_code,
|
||||
( isset( $data->country_code ) ) ? $data->country_code : '',
|
||||
( isset( $data->address_line_1 ) ) ? $data->address_line_1 : '',
|
||||
( isset( $data->address_line_2 ) ) ? $data->address_line_2 : '',
|
||||
( isset( $data->admin_area_1 ) ) ? $data->admin_area_1 : '',
|
||||
|
|
|
@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PayerName;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PayerTaxInfo;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Phone;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PhoneWithType;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class PayerFactory
|
||||
|
@ -158,6 +159,7 @@ class PayerFactory {
|
|||
*
|
||||
* @param array $form_fields The checkout form fields.
|
||||
* @return Payer
|
||||
* @throws RuntimeException When invalid data.
|
||||
*/
|
||||
public function from_checkout_form( array $form_fields ): Payer {
|
||||
|
||||
|
@ -189,6 +191,14 @@ class PayerFactory {
|
|||
}
|
||||
}
|
||||
|
||||
if ( ! is_email( $billing_email ) ) {
|
||||
/*
|
||||
phpcs:disable WordPress.WP.I18n.TextDomainMismatch
|
||||
translators: %s: email address
|
||||
*/
|
||||
throw new RuntimeException( sprintf( __( '%s is not a valid email address.', 'woocommerce' ), esc_html( $billing_email ) ) );
|
||||
}
|
||||
|
||||
return new Payer(
|
||||
new PayerName( $first_name, $last_name ),
|
||||
$billing_email,
|
||||
|
|
34
modules/ppcp-api-client/src/Helper/OrderHelper.php
Normal file
34
modules/ppcp-api-client/src/Helper/OrderHelper.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/**
|
||||
* PayPal order helper.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
|
||||
/**
|
||||
* Class OrderHelper
|
||||
*/
|
||||
class OrderHelper {
|
||||
|
||||
/**
|
||||
* Checks if order contains physical goods.
|
||||
*
|
||||
* @param Order $order PayPal order.
|
||||
* @return bool
|
||||
*/
|
||||
public function contains_physical_goods( Order $order ): bool {
|
||||
foreach ( $order->purchase_units() as $unit ) {
|
||||
if ( $unit->contains_physical_goods() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -31,6 +31,19 @@ const bootstrap = () => {
|
|||
const onSmartButtonClick = (data, actions) => {
|
||||
window.ppcpFundingSource = data.fundingSource;
|
||||
|
||||
// TODO: quick fix to get the error about empty form before attempting PayPal order
|
||||
// it should solve #513 for most of the users, but proper solution should be implemented later.
|
||||
const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');
|
||||
requiredFields.each((i, input) => {
|
||||
jQuery(input).trigger('validate');
|
||||
});
|
||||
if (jQuery('form.woocommerce-checkout .woocommerce-invalid').length) {
|
||||
errorHandler.clear();
|
||||
errorHandler.message(PayPalCommerceGateway.labels.error.js_validation);
|
||||
|
||||
return actions.reject();
|
||||
}
|
||||
|
||||
const form = document.querySelector('form.woocommerce-checkout');
|
||||
if (form) {
|
||||
jQuery('#ppcp-funding-source-form-input').remove();
|
||||
|
|
|
@ -20,7 +20,9 @@ class CheckoutActionHandler {
|
|||
const errorHandler = this.errorHandler;
|
||||
|
||||
const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review';
|
||||
const formValues = jQuery(formSelector).serialize();
|
||||
const formData = new FormData(document.querySelector(formSelector));
|
||||
// will not handle fields with multiple values (checkboxes, <select multiple>), but we do not care about this here
|
||||
const formJsonObj = Object.fromEntries(formData);
|
||||
|
||||
const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
|
||||
|
||||
|
@ -34,7 +36,7 @@ class CheckoutActionHandler {
|
|||
order_id:this.config.order_id,
|
||||
payment_method: getCurrentPaymentMethod(),
|
||||
funding_source: window.ppcpFundingSource,
|
||||
form:formValues,
|
||||
form: formJsonObj,
|
||||
createaccount: createaccount
|
||||
})
|
||||
}).then(function (res) {
|
||||
|
@ -59,7 +61,7 @@ class CheckoutActionHandler {
|
|||
}
|
||||
}
|
||||
|
||||
return;
|
||||
throw new Error(data.data.message);
|
||||
}
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('type', 'hidden');
|
||||
|
|
|
@ -14,6 +14,7 @@ class SingleProductBootstap {
|
|||
if (!this.shouldRender()) {
|
||||
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
|
||||
this.renderer.hideButtons(this.gateway.button.wrapper);
|
||||
this.messages.hideMessages();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -26,6 +27,7 @@ class SingleProductBootstap {
|
|||
|
||||
if (!this.shouldRender()) {
|
||||
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
|
||||
this.messages.hideMessages();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -51,6 +53,8 @@ class SingleProductBootstap {
|
|||
else if (document.querySelector('.product .woocommerce-Price-amount')) {
|
||||
priceText = document.querySelector('.product .woocommerce-Price-amount').innerText;
|
||||
}
|
||||
|
||||
priceText = priceText.replace(/,/g, '.');
|
||||
const amount = parseFloat(priceText.replace(/([^\d,\.\s]*)/g, ''));
|
||||
return amount === 0;
|
||||
|
||||
|
|
|
@ -53,5 +53,14 @@ class MessageRenderer {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
hideMessages() {
|
||||
const domElement = document.querySelector(this.config.wrapper);
|
||||
if (! domElement ) {
|
||||
return false;
|
||||
}
|
||||
domElement.style.display = 'none';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
export default MessageRenderer;
|
||||
|
|
|
@ -151,6 +151,7 @@ return array(
|
|||
$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' );
|
||||
return new ApproveOrderEndpoint(
|
||||
$request_data,
|
||||
|
@ -159,6 +160,7 @@ return array(
|
|||
$three_d_secure,
|
||||
$settings,
|
||||
$dcc_applies,
|
||||
$order_helper,
|
||||
$logger
|
||||
);
|
||||
},
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Button\Assets;
|
|||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Product;
|
||||
use WC_Product_Variation;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
|
@ -847,6 +848,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
'Something went wrong. Please try again or choose another payment source.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'js_validation' => __(
|
||||
'Required form fields are not filled or invalid.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
),
|
||||
),
|
||||
'order_id' => 'pay-now' === $this->context() ? absint( $wp->query_vars['order-pay'] ) : 0,
|
||||
|
@ -926,9 +931,9 @@ class SmartButton implements SmartButtonInterface {
|
|||
}
|
||||
|
||||
if ( $this->is_free_trial_cart() ) {
|
||||
$all_sources = $this->all_funding_sources;
|
||||
$all_sources = array_keys( $this->all_funding_sources );
|
||||
if ( $is_dcc_enabled ) {
|
||||
$all_sources = array_keys( array_diff_key( $all_sources, array( 'card' => '' ) ) );
|
||||
$all_sources = array_diff( $all_sources, array( 'card' ) );
|
||||
}
|
||||
$disable_funding = $all_sources;
|
||||
}
|
||||
|
@ -1256,9 +1261,25 @@ class SmartButton implements SmartButtonInterface {
|
|||
/**
|
||||
* The filter returning true if PayPal buttons/messages can be rendered for this product, or false otherwise.
|
||||
*/
|
||||
|
||||
$in_stock = $product->is_in_stock();
|
||||
|
||||
if ( $product->is_type( 'variable' ) ) {
|
||||
/**
|
||||
* The method is defined in WC_Product_Variable class.
|
||||
*
|
||||
* @psalm-suppress UndefinedMethod
|
||||
*/
|
||||
$variations = $product->get_available_variations( 'objects' );
|
||||
$in_stock = $this->has_in_stock_variation( $variations );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to filter if PayPal buttons/messages can be rendered for the given product.
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_product_supports_payment_request_button',
|
||||
! $product->is_type( array( 'external', 'grouped' ) ) && $product->is_in_stock(),
|
||||
! $product->is_type( array( 'external', 'grouped' ) ) && $in_stock,
|
||||
$product
|
||||
);
|
||||
}
|
||||
|
@ -1295,4 +1316,20 @@ class SmartButton implements SmartButtonInterface {
|
|||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if variations contain any in stock variation.
|
||||
*
|
||||
* @param WC_Product_Variation[] $variations The list of variations.
|
||||
* @return bool True if any in stock variation, false otherwise.
|
||||
*/
|
||||
protected function has_in_stock_variation( array $variations ): bool {
|
||||
foreach ( $variations as $variation ) {
|
||||
if ( $variation->is_in_stock() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
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\ThreeDSecure;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
|
@ -26,7 +27,6 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
|||
*/
|
||||
class ApproveOrderEndpoint implements EndpointInterface {
|
||||
|
||||
|
||||
const ENDPOINT = 'ppc-approve-order';
|
||||
|
||||
/**
|
||||
|
@ -71,6 +71,13 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
*/
|
||||
private $dcc_applies;
|
||||
|
||||
/**
|
||||
* The order helper.
|
||||
*
|
||||
* @var OrderHelper
|
||||
*/
|
||||
protected $order_helper;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -87,6 +94,7 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
* @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.
|
||||
*/
|
||||
public function __construct(
|
||||
|
@ -96,6 +104,7 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
ThreeDSecure $three_d_secure,
|
||||
Settings $settings,
|
||||
DccApplies $dcc_applies,
|
||||
OrderHelper $order_helper,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
|
@ -105,6 +114,7 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
$this->threed_secure = $three_d_secure;
|
||||
$this->settings = $settings;
|
||||
$this->dcc_applies = $dcc_applies;
|
||||
$this->order_helper = $order_helper;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
@ -173,10 +183,10 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
|||
wp_send_json_success( $order );
|
||||
}
|
||||
|
||||
if ( ! $order->status()->is( OrderStatus::APPROVED ) ) {
|
||||
if ( $this->order_helper->contains_physical_goods( $order ) && ! $order->status()->is( OrderStatus::APPROVED ) && ! $order->status()->is( OrderStatus::CREATED ) ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the id of the order.
|
||||
__( 'Order %s is not approved yet.', 'woocommerce-paypal-payments' ),
|
||||
__( 'Order %s is not ready for processing yet.', 'woocommerce-paypal-payments' ),
|
||||
$data['order_id']
|
||||
);
|
||||
|
||||
|
|
|
@ -403,9 +403,9 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
}
|
||||
|
||||
if ( ! $payer && isset( $data['form'] ) ) {
|
||||
parse_str( $data['form'], $form_fields );
|
||||
$form_fields = $data['form'];
|
||||
|
||||
if ( isset( $form_fields['billing_email'] ) && '' !== $form_fields['billing_email'] ) {
|
||||
if ( is_array( $form_fields ) && isset( $form_fields['billing_email'] ) && '' !== $form_fields['billing_email'] ) {
|
||||
return $this->payer_factory->from_checkout_form( $form_fields );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,15 +81,9 @@ class RequestData {
|
|||
$data = array();
|
||||
foreach ( (array) $assoc_array as $raw_key => $raw_value ) {
|
||||
if ( ! is_array( $raw_value ) ) {
|
||||
/**
|
||||
* The 'form' key is preserved for url encoded data and needs different
|
||||
* sanitization.
|
||||
*/
|
||||
if ( 'form' !== $raw_key ) {
|
||||
$data[ sanitize_text_field( (string) $raw_key ) ] = sanitize_text_field( (string) $raw_value );
|
||||
} else {
|
||||
$data[ sanitize_text_field( (string) $raw_key ) ] = sanitize_text_field( urldecode( (string) $raw_value ) );
|
||||
}
|
||||
// Not sure if it is a good idea to sanitize everything at this level,
|
||||
// but should be fine for now since we do not send any HTML or multi-line texts via ajax.
|
||||
$data[ sanitize_text_field( (string) $raw_key ) ] = sanitize_text_field( (string) $raw_value );
|
||||
continue;
|
||||
}
|
||||
$data[ sanitize_text_field( (string) $raw_key ) ] = $this->sanitize( $raw_value );
|
||||
|
|
|
@ -218,6 +218,7 @@ return array(
|
|||
$environment = $container->get( 'onboarding.environment' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
$order_helper = $container->get( 'api.order-helper' );
|
||||
return new OrderProcessor(
|
||||
$session_handler,
|
||||
$order_endpoint,
|
||||
|
@ -227,7 +228,8 @@ return array(
|
|||
$settings,
|
||||
$logger,
|
||||
$environment,
|
||||
$subscription_helper
|
||||
$subscription_helper,
|
||||
$order_helper
|
||||
);
|
||||
},
|
||||
'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor {
|
||||
|
|
|
@ -131,6 +131,7 @@ class AuthorizedPaymentsProcessor {
|
|||
try {
|
||||
$order = $this->paypal_order_from_wc_order( $wc_order );
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( 'Could not get PayPal order from WC order: ' . $exception->getMessage() );
|
||||
if ( $exception->getCode() === 404 ) {
|
||||
return self::NOT_FOUND;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
|
@ -106,6 +107,13 @@ class OrderProcessor {
|
|||
*/
|
||||
private $subscription_helper;
|
||||
|
||||
/**
|
||||
* The order helper.
|
||||
*
|
||||
* @var OrderHelper
|
||||
*/
|
||||
private $order_helper;
|
||||
|
||||
/**
|
||||
* OrderProcessor constructor.
|
||||
*
|
||||
|
@ -118,6 +126,7 @@ class OrderProcessor {
|
|||
* @param LoggerInterface $logger A logger service.
|
||||
* @param Environment $environment The environment.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param OrderHelper $order_helper The order helper.
|
||||
*/
|
||||
public function __construct(
|
||||
SessionHandler $session_handler,
|
||||
|
@ -128,7 +137,8 @@ class OrderProcessor {
|
|||
Settings $settings,
|
||||
LoggerInterface $logger,
|
||||
Environment $environment,
|
||||
SubscriptionHelper $subscription_helper
|
||||
SubscriptionHelper $subscription_helper,
|
||||
OrderHelper $order_helper
|
||||
) {
|
||||
|
||||
$this->session_handler = $session_handler;
|
||||
|
@ -140,6 +150,7 @@ class OrderProcessor {
|
|||
$this->environment = $environment;
|
||||
$this->logger = $logger;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->order_helper = $order_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,9 +171,9 @@ class OrderProcessor {
|
|||
$this->add_paypal_meta( $wc_order, $order, $this->environment );
|
||||
|
||||
$error_message = null;
|
||||
if ( ! $this->order_is_approved( $order ) ) {
|
||||
if ( $this->order_helper->contains_physical_goods( $order ) && ! $this->order_is_ready_for_process( $order ) ) {
|
||||
$error_message = __(
|
||||
'The payment has not been approved yet.',
|
||||
'The payment is not ready for processing yet.',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
}
|
||||
|
@ -204,7 +215,7 @@ class OrderProcessor {
|
|||
__( 'Payment successfully captured.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'true' );
|
||||
$wc_order->update_status( 'processing' );
|
||||
$wc_order->update_status( 'completed' );
|
||||
}
|
||||
$this->last_error = '';
|
||||
return true;
|
||||
|
@ -269,15 +280,15 @@ class OrderProcessor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Whether a given order is approved.
|
||||
* Whether a given order is ready for processing.
|
||||
*
|
||||
* @param Order $order The order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function order_is_approved( Order $order ): bool {
|
||||
private function order_is_ready_for_process( Order $order ): bool {
|
||||
|
||||
if ( $order->status()->is( OrderStatus::APPROVED ) ) {
|
||||
if ( $order->status()->is( OrderStatus::APPROVED ) || $order->status()->is( OrderStatus::CREATED ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -285,7 +296,7 @@ class OrderProcessor {
|
|||
return false;
|
||||
}
|
||||
|
||||
$is_approved = in_array(
|
||||
return in_array(
|
||||
$this->threed_secure->proceed_with_order( $order ),
|
||||
array(
|
||||
ThreeDSecure::NO_DECISION,
|
||||
|
@ -293,6 +304,5 @@ class OrderProcessor {
|
|||
),
|
||||
true
|
||||
);
|
||||
return $is_approved;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "woocommerce-paypal-payments",
|
||||
"version": "1.8.1",
|
||||
"version": "1.8.2",
|
||||
"description": "WooCommerce PayPal Payments",
|
||||
"repository": "https://github.com/woocommerce/woocommerce-paypal-payments",
|
||||
"license": "GPL-2.0",
|
||||
|
|
16
readme.txt
16
readme.txt
|
@ -1,10 +1,10 @@
|
|||
=== WooCommerce PayPal Payments ===
|
||||
Contributors: woocommerce, automattic
|
||||
Contributors: woocommerce, automattic, inpsyde
|
||||
Tags: woocommerce, paypal, payments, ecommerce, e-commerce, store, sales, sell, shop, shopping, cart, checkout
|
||||
Requires at least: 5.3
|
||||
Tested up to: 6.0
|
||||
Requires PHP: 7.1
|
||||
Stable tag: 1.8.1
|
||||
Stable tag: 1.8.2
|
||||
License: GPLv2
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
|
@ -81,6 +81,18 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
|
||||
== Changelog ==
|
||||
|
||||
= 1.8.2 =
|
||||
* Fix - Order not approved: payment via vaulted PayPal account fails #677
|
||||
* Fix - Cant' refund : "ERROR Refund failed: No country given for address." #639
|
||||
* Fix - Something went wrong error in Virtual products when using vaulted payment #673
|
||||
* Fix - PayPal smart buttons are not displayed for product variations when parent product is set to out of stock #669
|
||||
* Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
|
||||
* Fix - "Capture Virtual-Only Orders" intent sets virtual+downloadable product orders to "Processing" instead of "Completed" #665
|
||||
* Fix - Free trial period causing incorrerct disable-funding parameters with DCC disabled #661
|
||||
* Fix - Smart button not visible on single product page when product price is below 1 and decimal is "," #654
|
||||
* Fix - Checkout using an email address containing a + symbol results in a "[INVALID_REQUEST]" error #523
|
||||
* Enhancement - Improve checkout validation & order creation #513
|
||||
|
||||
= 1.8.1 =
|
||||
* Fix - Manual orders return an error for guest users when paying with PayPal Card Processing #530
|
||||
* Fix - "No PayPal order found in the current WooCommerce session" error for guests on Pay for Order page #605
|
||||
|
|
|
@ -127,21 +127,6 @@ class AddressFactoryTest extends TestCase
|
|||
$this->assertEquals($expectedPostalCode, $result->postal_code());
|
||||
}
|
||||
|
||||
public function testFromPayPalRequestThrowsError()
|
||||
{
|
||||
$testee = new AddressFactory();
|
||||
|
||||
$data = (object) [
|
||||
'address_line_1' => 'shipping_address_1',
|
||||
'address_line_2' => 'shipping_address_2',
|
||||
'admin_area_1' => 'shipping_admin_area_1',
|
||||
'admin_area_2' => 'shipping_admin_area_2',
|
||||
'postal_code' => 'shipping_postcode',
|
||||
];
|
||||
$this->expectException(RuntimeException::class);
|
||||
$testee->from_paypal_response($data);
|
||||
}
|
||||
|
||||
public function dataFromPayPalRequest() : array
|
||||
{
|
||||
return [
|
||||
|
|
|
@ -16,6 +16,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
|
@ -129,6 +130,8 @@ class OrderProcessorTest extends TestCase
|
|||
$subscription_helper = Mockery::mock(SubscriptionHelper::class);
|
||||
$subscription_helper->shouldReceive('has_subscription');
|
||||
|
||||
$order_helper = Mockery::mock(OrderHelper::class);
|
||||
|
||||
$testee = new OrderProcessor(
|
||||
$sessionHandler,
|
||||
$orderEndpoint,
|
||||
|
@ -138,7 +141,8 @@ class OrderProcessorTest extends TestCase
|
|||
$settings,
|
||||
$logger,
|
||||
$this->environment,
|
||||
$subscription_helper
|
||||
$subscription_helper,
|
||||
$order_helper
|
||||
);
|
||||
|
||||
$wcOrder
|
||||
|
@ -165,6 +169,8 @@ class OrderProcessorTest extends TestCase
|
|||
$wcOrder->expects('set_transaction_id')
|
||||
->with($transactionId);
|
||||
|
||||
$order_helper->shouldReceive('contains_physical_goods')->andReturn(true);
|
||||
|
||||
$this->assertTrue($testee->process($wcOrder));
|
||||
}
|
||||
|
||||
|
@ -247,6 +253,8 @@ class OrderProcessorTest extends TestCase
|
|||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
$subscription_helper = Mockery::mock(SubscriptionHelper::class);
|
||||
|
||||
$order_helper = Mockery::mock(OrderHelper::class);
|
||||
|
||||
$testee = new OrderProcessor(
|
||||
$sessionHandler,
|
||||
$orderEndpoint,
|
||||
|
@ -256,7 +264,8 @@ class OrderProcessorTest extends TestCase
|
|||
$settings,
|
||||
$logger,
|
||||
$this->environment,
|
||||
$subscription_helper
|
||||
$subscription_helper,
|
||||
$order_helper
|
||||
);
|
||||
|
||||
$wcOrder
|
||||
|
@ -277,6 +286,9 @@ class OrderProcessorTest extends TestCase
|
|||
->with($transactionId);
|
||||
$wcOrder
|
||||
->expects('payment_complete');
|
||||
|
||||
$order_helper->shouldReceive('contains_physical_goods')->andReturn(true);
|
||||
|
||||
$this->assertTrue($testee->process($wcOrder));
|
||||
}
|
||||
|
||||
|
@ -306,6 +318,10 @@ class OrderProcessorTest extends TestCase
|
|||
->expects('is')
|
||||
->with(OrderStatus::APPROVED)
|
||||
->andReturn(false);
|
||||
$orderStatus
|
||||
->expects('is')
|
||||
->with(OrderStatus::CREATED)
|
||||
->andReturn(false);
|
||||
$orderId = 'abc';
|
||||
$orderIntent = 'CAPTURE';
|
||||
$currentOrder = Mockery::mock(Order::class);
|
||||
|
@ -343,6 +359,8 @@ class OrderProcessorTest extends TestCase
|
|||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
$subscription_helper = Mockery::mock(SubscriptionHelper::class);
|
||||
|
||||
$order_helper = Mockery::mock(OrderHelper::class);
|
||||
|
||||
$testee = new OrderProcessor(
|
||||
$sessionHandler,
|
||||
$orderEndpoint,
|
||||
|
@ -352,7 +370,8 @@ class OrderProcessorTest extends TestCase
|
|||
$settings,
|
||||
$logger,
|
||||
$this->environment,
|
||||
$subscription_helper
|
||||
$subscription_helper,
|
||||
$order_helper
|
||||
);
|
||||
|
||||
$wcOrder
|
||||
|
@ -368,6 +387,8 @@ class OrderProcessorTest extends TestCase
|
|||
$orderIntent
|
||||
);
|
||||
|
||||
$order_helper->shouldReceive('contains_physical_goods')->andReturn(true);
|
||||
|
||||
$this->assertFalse($testee->process($wcOrder));
|
||||
$this->assertNotEmpty($testee->last_error());
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Plugin Name: WooCommerce PayPal Payments
|
||||
* Plugin URI: https://woocommerce.com/products/woocommerce-paypal-payments/
|
||||
* Description: PayPal's latest complete payments processing solution. Accept PayPal, Pay Later, credit/debit cards, alternative digital wallets local payment types and bank accounts. Turn on only PayPal options or process a full suite of payment methods. Enable global transaction with extensive currency and country coverage.
|
||||
* Version: 1.8.1
|
||||
* Version: 1.8.2
|
||||
* Author: WooCommerce
|
||||
* Author URI: https://woocommerce.com/
|
||||
* License: GPL-2.0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue