diff --git a/changelog.txt b/changelog.txt index 0f939d84d..5ddd00d5a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,19 @@ *** Changelog *** += 1.6.0 - TBD = +* Add - Webhook status. #246 #273 +* Add - Show CC gateway in admin payments list. #236 +* Add - Add 3d secure contingency settings. #230 +* Add - Improve logging. #252 #275 +* Add - Do not send payee email. #231 +* Add - Allow customers to see and delete their saved payments in My Account. #274 +* Fix - PayPal Payments generates multiple orders. #244 +* Fix - Saved credit card does not auto fill. #242 +* Fix - Incorrect webhooks registration. #254 +* Fix - Disable funding credit cards affecting hosted fields, unset for GB. #249 +* Fix - REFUND_CAPTURE_CURRENCY_MISMATCH on multicurrency sites. #225 +* Fix - Can't checkout to certain countries with optional postcode. #224 + = 1.5.1 - 2021-08-19 = * Fix - Set 3DS contingencies to "SCA_WHEN_REQUIRED". #178 * Fix - Plugin conflict blocking line item details. #221 diff --git a/modules/ppcp-api-client/services.php b/modules/ppcp-api-client/services.php index ad71c5936..982d4265f 100644 --- a/modules/ppcp-api-client/services.php +++ b/modules/ppcp-api-client/services.php @@ -72,19 +72,19 @@ return 'WC-'; }, 'api.bearer' => static function ( $container ): Bearer { - $cache = new Cache( 'ppcp-paypal-bearer' ); $key = $container->get( 'api.key' ); $secret = $container->get( 'api.secret' ); - $host = $container->get( 'api.host' ); $logger = $container->get( 'woocommerce.logger.woocommerce' ); + $settings = $container->get( 'wcgateway.settings' ); return new PayPalBearer( $cache, $host, $key, $secret, - $logger + $logger, + $settings ); }, 'api.endpoint.partners' => static function ( $container ) : PartnersEndpoint { diff --git a/modules/ppcp-api-client/src/Entity/class-cardauthenticationresult.php b/modules/ppcp-api-client/src/Entity/class-cardauthenticationresult.php index c537ba936..7eedf7d56 100644 --- a/modules/ppcp-api-client/src/Entity/class-cardauthenticationresult.php +++ b/modules/ppcp-api-client/src/Entity/class-cardauthenticationresult.php @@ -112,7 +112,7 @@ public function to_array(): array { $data['liability_shift'] = $this->liability_shift(); $data['three_d_secure'] = array( 'enrollment_status' => $this->enrollment_status(), - 'authentication_result' => $this->authentication_result(), + 'authentication_status' => $this->authentication_result(), ); return $data; } diff --git a/modules/ppcp-api-client/src/Factory/class-paymentsourcefactory.php b/modules/ppcp-api-client/src/Factory/class-paymentsourcefactory.php index aa19e5e4f..b4efffb0e 100644 --- a/modules/ppcp-api-client/src/Factory/class-paymentsourcefactory.php +++ b/modules/ppcp-api-client/src/Factory/class-paymentsourcefactory.php @@ -37,8 +37,8 @@ public function from_paypal_response( \stdClass $data ): PaymentSource { (string) $data->card->authentication_result->liability_shift : '', isset( $data->card->authentication_result->three_d_secure->enrollment_status ) ? (string) $data->card->authentication_result->three_d_secure->enrollment_status : '', - isset( $data->card->authentication_result->three_d_secure->authentication_result ) ? - (string) $data->card->authentication_result->three_d_secure->authentication_result : '' + isset( $data->card->authentication_result->three_d_secure->authentication_status ) ? + (string) $data->card->authentication_result->three_d_secure->authentication_status : '' ); } $card = new PaymentSourceCard( diff --git a/modules/ppcp-api-client/src/Factory/class-purchaseunitfactory.php b/modules/ppcp-api-client/src/Factory/class-purchaseunitfactory.php index a809de37f..ce97bb5bc 100644 --- a/modules/ppcp-api-client/src/Factory/class-purchaseunitfactory.php +++ b/modules/ppcp-api-client/src/Factory/class-purchaseunitfactory.php @@ -158,6 +158,8 @@ public function from_wc_cart( \WC_Cart $cart ): PurchaseUnit { $shipping = $this->shipping_factory->from_wc_customer( \WC()->customer ); if ( 2 !== strlen( $shipping->address()->country_code() ) + || ( ! $shipping->address()->postal_code() ) + || $this->country_without_postal_code( $shipping->address()->country_code() ) ) { $shipping = null; } @@ -264,4 +266,18 @@ private function shipping_needed( Item ...$items ): bool { } return false; } + + /** + * Check if country does not have postal code. + * + * @param string $country_code The country code. + * @return bool Whether country has postal code or not. + */ + private function country_without_postal_code( string $country_code ): bool { + $countries = array( 'AE', 'AF', 'AG', 'AI', 'AL', 'AN', 'AO', 'AW', 'BB', 'BF', 'BH', 'BI', 'BJ', 'BM', 'BO', 'BS', 'BT', 'BW', 'BZ', 'CD', 'CF', 'CG', 'CI', 'CK', 'CL', 'CM', 'CO', 'CR', 'CV', 'DJ', 'DM', 'DO', 'EC', 'EG', 'ER', 'ET', 'FJ', 'FK', 'GA', 'GD', 'GH', 'GI', 'GM', 'GN', 'GQ', 'GT', 'GW', 'GY', 'HK', 'HN', 'HT', 'IE', 'IQ', 'IR', 'JM', 'JO', 'KE', 'KH', 'KI', 'KM', 'KN', 'KP', 'KW', 'KY', 'LA', 'LB', 'LC', 'LK', 'LR', 'LS', 'LY', 'ML', 'MM', 'MO', 'MR', 'MS', 'MT', 'MU', 'MW', 'MZ', 'NA', 'NE', 'NG', 'NI', 'NP', 'NR', 'NU', 'OM', 'PA', 'PE', 'PF', 'PY', 'QA', 'RW', 'SA', 'SB', 'SC', 'SD', 'SL', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SY', 'TC', 'TD', 'TG', 'TL', 'TO', 'TT', 'TV', 'TZ', 'UG', 'UY', 'VC', 'VE', 'VG', 'VN', 'VU', 'WS', 'XA', 'XB', 'XC', 'XE', 'XL', 'XM', 'XN', 'XS', 'YE', 'ZM', 'ZW' ); + if ( in_array( $country_code, $countries, true ) ) { + return true; + } + return false; + } } diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js index 6b8b79142..33da3ab45 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js @@ -143,33 +143,37 @@ class CreditCardRenderer { } disableFields() { - this.currentHostedFieldsInstance.setAttribute({ - field: 'number', - attribute: 'disabled' - }) - this.currentHostedFieldsInstance.setAttribute({ - field: 'cvv', - attribute: 'disabled' - }) - this.currentHostedFieldsInstance.setAttribute({ - field: 'expirationDate', - attribute: 'disabled' - }) + if( this.currentHostedFieldsInstance) { + this.currentHostedFieldsInstance.setAttribute({ + field: 'number', + attribute: 'disabled' + }) + this.currentHostedFieldsInstance.setAttribute({ + field: 'cvv', + attribute: 'disabled' + }) + this.currentHostedFieldsInstance.setAttribute({ + field: 'expirationDate', + attribute: 'disabled' + }) + } } enableFields() { - this.currentHostedFieldsInstance.removeAttribute({ - field: 'number', - attribute: 'disabled' - }) - this.currentHostedFieldsInstance.removeAttribute({ - field: 'cvv', - attribute: 'disabled' - }) - this.currentHostedFieldsInstance.removeAttribute({ - field: 'expirationDate', - attribute: 'disabled' - }) + if( this.currentHostedFieldsInstance) { + this.currentHostedFieldsInstance.removeAttribute({ + field: 'number', + attribute: 'disabled' + }) + this.currentHostedFieldsInstance.removeAttribute({ + field: 'cvv', + attribute: 'disabled' + }) + this.currentHostedFieldsInstance.removeAttribute({ + field: 'expirationDate', + attribute: 'disabled' + }) + } } _submit(contextConfig) { @@ -193,7 +197,6 @@ class CreditCardRenderer { return contextConfig.onApprove(payload); }).catch(err => { console.error(err); - this.errorHandler.genericError(); this.spinner.unblock(); }); } else { diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index f5ef6da06..737a5032c 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -102,7 +102,8 @@ $request_data = $container->get( 'button.request-data' ); $repository = $container->get( 'api.repository.cart' ); $data_store = \WC_Data_Store::load( 'product' ); - return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store ); + $logger = $container->get( 'woocommerce.logger.woocommerce' ); + return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store, $logger ); }, 'button.endpoint.create-order' => static function ( $container ): CreateOrderEndpoint { $request_data = $container->get( 'button.request-data' ); @@ -113,6 +114,7 @@ $session_handler = $container->get( 'session.handler' ); $settings = $container->get( 'wcgateway.settings' ); $early_order_handler = $container->get( 'button.helper.early-order-handler' ); + $logger = $container->get( 'woocommerce.logger.woocommerce' ); return new CreateOrderEndpoint( $request_data, $cart_repository, @@ -121,7 +123,8 @@ $payer_factory, $session_handler, $settings, - $early_order_handler + $early_order_handler, + $logger ); }, 'button.helper.early-order-handler' => static function ( $container ) : EarlyOrderHandler { @@ -153,13 +156,16 @@ 'button.endpoint.data-client-id' => static function( $container ) : DataClientIdEndpoint { $request_data = $container->get( 'button.request-data' ); $identity_token = $container->get( 'api.endpoint.identity-token' ); + $logger = $container->get( 'woocommerce.logger.woocommerce' ); return new DataClientIdEndpoint( $request_data, - $identity_token + $identity_token, + $logger ); }, 'button.helper.three-d-secure' => static function ( $container ): ThreeDSecure { - return new ThreeDSecure(); + $logger = $container->get( 'woocommerce.logger.woocommerce' ); + return new ThreeDSecure( $logger ); }, 'button.helper.messages-apply' => static function ( $container ): MessagesApply { return new MessagesApply(); diff --git a/modules/ppcp-button/src/Helper/class-threedsecure.php b/modules/ppcp-button/src/Helper/class-threedsecure.php index 988ce3ce8..e2d8b9e49 100644 --- a/modules/ppcp-button/src/Helper/class-threedsecure.php +++ b/modules/ppcp-button/src/Helper/class-threedsecure.php @@ -9,6 +9,7 @@ namespace WooCommerce\PayPalCommerce\Button\Helper; +use Psr\Log\LoggerInterface; use WooCommerce\PayPalCommerce\ApiClient\Entity\CardAuthenticationResult as AuthResult; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; @@ -17,12 +18,27 @@ */ class ThreeDSecure { - const NO_DECISION = 0; const PROCCEED = 1; const REJECT = 2; const RETRY = 3; + /** + * The logger. + * + * @var LoggerInterface + */ + protected $logger; + + /** + * ThreeDSecure constructor. + * + * @param LoggerInterface $logger The logger. + */ + public function __construct( LoggerInterface $logger ) { + $this->logger = $logger; + } + /** * Determine, how we proceed with a given order. * @@ -42,7 +58,10 @@ public function proceed_with_order( Order $order ): int { if ( ! $order->payment_source()->card()->authentication_result() ) { return self::NO_DECISION; } + $result = $order->payment_source()->card()->authentication_result(); + $this->logger->info( '3DS authentication result: ' . wc_print_r( $result->to_array(), true ) ); + if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_POSSIBLE ) { return self::PROCCEED; } diff --git a/modules/ppcp-vaulting/services.php b/modules/ppcp-vaulting/services.php index 1eea5810a..b1b3ea7af 100644 --- a/modules/ppcp-vaulting/services.php +++ b/modules/ppcp-vaulting/services.php @@ -24,8 +24,8 @@ $container->get( 'vaulting.module-url' ) ); }, - 'vaulting.payment-tokens-renderer' => static function (): PaymentTokensRendered { - return new PaymentTokensRendered(); + 'vaulting.payment-tokens-renderer' => static function (): PaymentTokensRenderer { + return new PaymentTokensRenderer(); }, 'vaulting.repository.payment-token' => static function ( $container ): PaymentTokenRepository { $factory = $container->get( 'api.factory.payment-token' ); diff --git a/modules/ppcp-webhooks/src/Status/class-webhooksimulation.php b/modules/ppcp-webhooks/src/Status/class-webhooksimulation.php index 78fc72ff3..6bd4f8e15 100644 --- a/modules/ppcp-webhooks/src/Status/class-webhooksimulation.php +++ b/modules/ppcp-webhooks/src/Status/class-webhooksimulation.php @@ -55,7 +55,7 @@ class WebhookSimulation { */ public function __construct( WebhookEndpoint $webhook_endpoint, - Webhook $webhook, + ?Webhook $webhook, string $event_type ) { $this->webhook_endpoint = $webhook_endpoint; diff --git a/package.json b/package.json index f87393ccd..609cb644f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "woocommerce-paypal-payments", - "version": "1.5.1", + "version": "1.6.0", "description": "WooCommerce PayPal Payments", "repository": "https://github.com/woocommerce/woocommerce-paypal-payments", "license": "GPL-2.0", diff --git a/readme.txt b/readme.txt index 6d9fff3fd..7969aef99 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: woocommerce, paypal, payments, ecommerce, e-commerce, store, sales, sell, Requires at least: 5.3 Tested up to: 5.8 Requires PHP: 7.1 -Stable tag: 1.5.1 +Stable tag: 1.6.0 License: GPLv2 License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -81,6 +81,20 @@ Follow the steps below to connect the plugin to your PayPal account: == Changelog == += 1.6.0 = +* Add - Webhook status. #246 #273 +* Add - Show CC gateway in admin payments list. #236 +* Add - Add 3d secure contingency settings. #230 +* Add - Improve logging. #252 #275 +* Add - Do not send payee email. #231 +* Add - Allow customers to see and delete their saved payments in My Account. #274 +* Fix - PayPal Payments generates multiple orders. #244 +* Fix - Saved credit card does not auto fill. #242 +* Fix - Incorrect webhooks registration. #254 +* Fix - Disable funding credit cards affecting hosted fields, unset for GB. #249 +* Fix - REFUND_CAPTURE_CURRENCY_MISMATCH on multicurrency sites. #225 +* Fix - Can't checkout to certain countries with optional postcode. #224 + = 1.5.1 = * Fix - Set 3DS contingencies to "SCA_WHEN_REQUIRED". #178 * Fix - Plugin conflict blocking line item details. #221 diff --git a/tests/PHPUnit/Button/Helper/ThreeDSecureTest.php b/tests/PHPUnit/Button/Helper/ThreeDSecureTest.php index 13f78c699..31392f356 100644 --- a/tests/PHPUnit/Button/Helper/ThreeDSecureTest.php +++ b/tests/PHPUnit/Button/Helper/ThreeDSecureTest.php @@ -4,12 +4,14 @@ namespace WooCommerce\PayPalCommerce\Button\Helper; +use Psr\Log\LoggerInterface; use WooCommerce\PayPalCommerce\ApiClient\Entity\CardAuthenticationResult; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource; use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSourceCard; use WooCommerce\PayPalCommerce\TestCase; use Mockery\Mock; +use function Brain\Monkey\Functions\when; class ThreeDSecureTest extends TestCase { @@ -25,13 +27,18 @@ public function testDefault(int $expected, string $liabilityShift, string $authe $result->shouldReceive('liability_shift')->andReturn($liabilityShift); $result->shouldReceive('authentication_result')->andReturn($authenticationResult); $result->shouldReceive('enrollment_status')->andReturn($enrollment); + $result->shouldReceive('to_array')->andReturn(['foo' => 'bar',]); $card = \Mockery::mock(PaymentSourceCard::class); $card->shouldReceive('authentication_result')->andReturn($result); $source = \Mockery::mock(PaymentSource::class); $source->shouldReceive('card')->andReturn($card); $order = \Mockery::mock(Order::class); $order->shouldReceive('payment_source')->andReturn($source); - $testee = new ThreeDSecure(); + $logger = \Mockery::mock(LoggerInterface::class); + $logger->shouldReceive('info'); + when('wc_print_r')->justReturn(); + + $testee = new ThreeDSecure($logger); $result = $testee->proceed_with_order($order); $this->assertEquals($expected, $result); } @@ -120,4 +127,4 @@ public function dataForTestDefault() : array ]; return $matrix; } -} \ No newline at end of file +} diff --git a/woocommerce-paypal-payments.php b/woocommerce-paypal-payments.php index 3bf7b3b97..26c1ad203 100644 --- a/woocommerce-paypal-payments.php +++ b/woocommerce-paypal-payments.php @@ -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.5.1 + * Version: 1.6.0 * Author: WooCommerce * Author URI: https://woocommerce.com/ * License: GPL-2.0 @@ -21,7 +21,7 @@ define( 'PAYPAL_API_URL', 'https://api.paypal.com' ); define( 'PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com' ); -define( 'PAYPAL_INTEGRATION_DATE', '2020-10-15' ); +define( 'PAYPAL_INTEGRATION_DATE', '2021-09-17' ); define( 'PPCP_FLAG_SUBSCRIPTION', true );