Merge branch 'trunk' into PCP-1083-update-standard-payments-tab-settings

This commit is contained in:
Narek Zakarian 2022-12-20 19:37:51 +04:00
commit eb080c9275
No known key found for this signature in database
GPG key ID: 07AFD7E7A9C164A7
47 changed files with 3866 additions and 190 deletions

View file

@ -198,7 +198,9 @@ return array(
$logger,
$application_context_repository,
$paypal_request_id,
$subscription_helper
$subscription_helper,
$container->get( 'wcgateway.is-fraudnet-enabled' ),
$container->get( 'wcgateway.fraudnet' )
);
},
'api.endpoint.billing-agreements' => static function ( ContainerInterface $container ): BillingAgreementsEndpoint {

View file

@ -29,6 +29,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
use WP_Error;
/**
@ -94,6 +95,20 @@ class OrderEndpoint {
*/
private $application_context_repository;
/**
* True if FraudNet support is enabled in settings, otherwise false.
*
* @var bool
*/
protected $is_fraudnet_enabled;
/**
* The FraudNet entity.
*
* @var FraudNet
*/
protected $fraudnet;
/**
* The BN Code.
*
@ -120,6 +135,8 @@ class OrderEndpoint {
* @param ApplicationContextRepository $application_context_repository The application context repository.
* @param PayPalRequestIdRepository $paypal_request_id_repository The paypal request id repository.
* @param SubscriptionHelper $subscription_helper The subscription helper.
* @param bool $is_fraudnet_enabled true if FraudNet support is enabled in settings, otherwise false.
* @param FraudNet $fraudnet The FraudNet entity.
* @param string $bn_code The BN Code.
*/
public function __construct(
@ -132,6 +149,8 @@ class OrderEndpoint {
ApplicationContextRepository $application_context_repository,
PayPalRequestIdRepository $paypal_request_id_repository,
SubscriptionHelper $subscription_helper,
bool $is_fraudnet_enabled,
FraudNet $fraudnet,
string $bn_code = ''
) {
@ -144,7 +163,9 @@ class OrderEndpoint {
$this->application_context_repository = $application_context_repository;
$this->bn_code = $bn_code;
$this->paypal_request_id_repository = $paypal_request_id_repository;
$this->is_fraudnet_enabled = $is_fraudnet_enabled;
$this->subscription_helper = $subscription_helper;
$this->fraudnet = $fraudnet;
}
/**
@ -224,6 +245,11 @@ class OrderEndpoint {
if ( $this->bn_code ) {
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bn_code;
}
if ( $this->is_fraudnet_enabled ) {
$args['headers']['PayPal-Client-Metadata-Id'] = $this->fraudnet->session_id();
}
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(

View file

@ -26,7 +26,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet;
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSource;
use WP_Error;

View file

@ -59,9 +59,9 @@ class CheckoutActionHandler {
);
} else {
errorHandler.clear();
if (data.data.errors.length > 0) {
if (data.data.errors?.length > 0) {
errorHandler.messages(data.data.errors);
} else if (data.data.details.length > 0) {
} else if (data.data.details?.length > 0) {
errorHandler.message(data.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);
} else {
errorHandler.message(data.data.message, true);

View file

@ -233,8 +233,14 @@ class CreditCardRenderer {
this.spinner.unblock();
this.errorHandler.clear();
if (err.details?.length) {
if (err.data?.details?.length) {
this.errorHandler.message(err.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);
} else if (err.details?.length) {
this.errorHandler.message(err.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);
} else if (err.data?.errors?.length > 0) {
this.errorHandler.messages(err.data.errors);
} else if (err.data?.message) {
this.errorHandler.message(err.data.message, true);
} else if (err.message) {
this.errorHandler.message(err.message, true);
} else {

View file

@ -248,7 +248,11 @@ class CreateOrderEndpoint implements EndpointInterface {
$form_fields = $data['form'] ?? null;
if ( $this->early_validation_enabled && is_array( $form_fields ) ) {
if ( $this->early_validation_enabled
&& is_array( $form_fields )
&& 'checkout' === $data['context']
&& in_array( $payment_method, array( PayPalGateway::ID, CardButtonGateway::ID ), true )
) {
$this->validate_form( $form_fields );
}

View file

@ -32,6 +32,8 @@ class CheckoutFormValidator extends WC_Checkout {
foreach ( $data as $key => $value ) {
$_POST[ $key ] = $value;
}
// And we must call get_posted_data because it handles the shipping address.
$data = $this->get_posted_data();
// It throws some notices when checking fields etc., also from other plugins via hooks.
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged

View file

@ -56,15 +56,6 @@ return array(
return function_exists( 'wc_gzd_get_shipments_by_order' ); // 3.0+
},
'compat.gzd.tracking_statuses_map' => function ( ContainerInterface $container ): array {
return array(
'draft' => 'ON_HOLD',
'processing' => 'SHIPPED',
'shipped' => 'SHIPPED',
'delivered' => 'DELIVERED',
);
},
'compat.module.url' => static function ( ContainerInterface $container ): string {
/**
* The path cannot be false.

View file

@ -131,20 +131,13 @@ class CompatModule implements ModuleInterface {
$logger = $c->get( 'woocommerce.logger.woocommerce' );
assert( $logger instanceof LoggerInterface );
$status_map = $c->get( 'compat.gzd.tracking_statuses_map' );
add_action(
'woocommerce_gzd_shipment_after_save',
static function( Shipment $shipment ) use ( $endpoint, $logger, $status_map ) {
'woocommerce_gzd_shipment_status_shipped',
static function( int $shipment_id, Shipment $shipment ) use ( $endpoint, $logger ) {
if ( ! apply_filters( 'woocommerce_paypal_payments_sync_gzd_tracking', true ) ) {
return;
}
$gzd_shipment_status = $shipment->get_status();
if ( ! array_key_exists( $gzd_shipment_status, $status_map ) ) {
return;
}
$wc_order = $shipment->get_order();
if ( ! is_a( $wc_order, WC_Order::class ) ) {
return;
@ -157,7 +150,7 @@ class CompatModule implements ModuleInterface {
$tracking_data = array(
'transaction_id' => $transaction_id,
'status' => (string) $status_map[ $gzd_shipment_status ],
'status' => 'SHIPPED',
);
$provider = $shipment->get_shipping_provider();
@ -178,7 +171,9 @@ class CompatModule implements ModuleInterface {
} catch ( Exception $exception ) {
$logger->error( "Couldn't sync tracking information: " . $exception->getMessage() );
}
}
},
500,
2
);
}

View file

@ -0,0 +1,11 @@
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3.25.0"
}
]
]
}

2
modules/ppcp-uninstall/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules
/assets

View file

@ -0,0 +1,17 @@
{
"name": "woocommerce/ppcp-uninstall",
"type": "dhii-mod",
"description": "Uninstall module for PPCP",
"license": "GPL-2.0",
"require": {
"php": "^7.2 | ^8.0",
"dhii/module-interface": "^0.3.0-alpha1"
},
"autoload": {
"psr-4": {
"WooCommerce\\PayPalCommerce\\Uninstall\\": "src"
}
},
"minimum-stability": "dev",
"prefer-stable": true
}

View file

@ -0,0 +1,56 @@
<?php
/**
* The uninstall module extensions.
*
* @package WooCommerce\PayPalCommerce\Uninstall
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Uninstall;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
return array(
'wcgateway.settings.fields' => static function ( ContainerInterface $container, array $fields ): array {
$uninstall_fields = array(
'uninstall_heading' => array(
'heading' => __( 'Uninstall/Clear Database', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-heading',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Manage plugin data and scheduled actions stored in database.', 'woocommerce-paypal-payments' ),
),
'uninstall_clear_db_on_uninstall' => array(
'title' => __( 'Remove PayPal Payments data from Database on uninstall', 'woocommerce-paypal-payments' ),
'type' => 'checkbox',
'label' => __( 'Remove options and scheduled actions from database when uninstalling the plugin.', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'uninstall_clear_db_now' => array(
'title' => __( 'Remove PayPal Payments data from Database.', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-text',
'text' => '<button type="button" class="button ppcp-clear_db_now">' . esc_html__( 'Clear now', 'woocommerce-paypal-payments' ) . '</button>',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Click to remove options and scheduled actions from database now.', 'woocommerce-paypal-payments' ),
),
);
return array_merge( $fields, $uninstall_fields );
},
);

View file

@ -0,0 +1,16 @@
<?php
/**
* The uninstall module.
*
* @package WooCommerce\PayPalCommerce\Uninstall
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Uninstall;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
return function (): ModuleInterface {
return new UninstallModule();
};

View file

@ -0,0 +1,32 @@
{
"name": "ppcp-uninstall",
"version": "1.0.0",
"license": "GPL-3.0-or-later",
"main": "resources/js/ppcp-clear-db.js",
"browserslist": [
"> 0.5%",
"Safari >= 8",
"Chrome >= 41",
"Firefox >= 43",
"Edge >= 14"
],
"dependencies": {
"core-js": "^3.25.0"
},
"devDependencies": {
"@babel/core": "^7.19",
"@babel/preset-env": "^7.19",
"babel-loader": "^8.2",
"cross-env": "^7.0.3",
"file-loader": "^6.2.0",
"sass": "^1.42.1",
"sass-loader": "^12.1.0",
"webpack": "^5.74",
"webpack-cli": "^4.10"
},
"scripts": {
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
"watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch",
"dev": "cross-env BABEL_ENV=default webpack --watch"
}
}

View file

@ -0,0 +1,43 @@
document.addEventListener(
'DOMContentLoaded',
() => {
const config = PayPalCommerceGatewayClearDb;
if (!typeof (config)) {
return;
}
const clearDbConfig = config.clearDb;
document.querySelector(clearDbConfig.button)?.addEventListener('click', function () {
const isConfirmed = confirm(clearDbConfig.confirmationMessage);
if (!isConfirmed) {
return;
}
const clearButton = document.querySelector(clearDbConfig.button);
clearButton.setAttribute('disabled', 'disabled');
fetch(clearDbConfig.endpoint, {
method: 'POST',
credentials: 'same-origin',
body: JSON.stringify({
nonce: clearDbConfig.nonce,
})
}).then((res)=>{
return res.json();
}).then((data)=>{
if (!data.success) {
jQuery(clearDbConfig.failureMessage).insertAfter(clearButton);
setTimeout(()=> jQuery(clearDbConfig.messageSelector).remove(),3000);
clearButton.removeAttribute('disabled');
throw Error(data.data.message);
}
jQuery(clearDbConfig.successMessage).insertAfter(clearButton);
setTimeout(()=> jQuery(clearDbConfig.messageSelector).remove(),3000);
clearButton.removeAttribute('disabled');
window.location.replace(clearDbConfig.redirectUrl);
});
})
},
);

View file

@ -0,0 +1,96 @@
<?php
/**
* The uninstall module services.
*
* @package WooCommerce\PayPalCommerce\Uninstall
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Uninstall;
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
use WooCommerce\PayPalCommerce\Uninstall\Assets\ClearDatabaseAssets;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhookSimulation;
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
return array(
'uninstall.ppcp-all-option-names' => function( ContainerInterface $container ) : array {
return array(
$container->get( 'webhook.last-webhook-storage.key' ),
PayPalRequestIdRepository::KEY,
'woocommerce_ppcp-is_pay_later_settings_migrated',
'woocommerce_' . PayPalGateway::ID . '_settings',
'woocommerce_' . CreditCardGateway::ID . '_settings',
'woocommerce_' . PayUponInvoiceGateway::ID . '_settings',
'woocommerce_' . CardButtonGateway::ID . '_settings',
Settings::KEY,
'woocommerce-ppcp-version',
WebhookSimulation::OPTION_ID,
WebhookRegistrar::KEY,
);
},
'uninstall.ppcp-all-scheduled-action-names' => function( ContainerInterface $container ) : array {
return array(
'woocommerce_paypal_payments_check_pui_payment_captured',
'woocommerce_paypal_payments_check_saved_payment',
);
},
'uninstall.clear-db-endpoint' => function( ContainerInterface $container ) : string {
return 'ppcp-clear-db';
},
'uninstall.clear-database-script-data' => function( ContainerInterface $container ) : array {
return array(
'clearDb' => array(
'endpoint' => \WC_AJAX::get_endpoint( $container->get( 'uninstall.clear-db-endpoint' ) ),
'nonce' => wp_create_nonce( $container->get( 'uninstall.clear-db-endpoint' ) ),
'button' => '.ppcp-clear_db_now',
'messageSelector' => '.clear-db-info-message',
'confirmationMessage' => __( 'Are you sure? the operation will remove all plugin data.', 'woocommerce-paypal-payments' ),
'successMessage' => sprintf(
'<div class="updated clear-db-info-message"><p><strong>%1$s</strong></p></div>',
esc_html__( 'The plugin data is successfully cleared.', 'woocommerce-paypal-payments' )
),
'failureMessage' => sprintf(
'<div class="error clear-db-info-message"><p><strong>%1$s</strong></p></div>',
esc_html__( 'Operation failed. Check WooCommerce logs for more details.', 'woocommerce-paypal-payments' )
),
'redirectUrl' => admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway' ),
),
);
},
'uninstall.module-url' => static function ( ContainerInterface $container ): string {
/**
* The path cannot be false.
*
* @psalm-suppress PossiblyFalseArgument
*/
return plugins_url(
'/modules/ppcp-uninstall/',
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
);
},
'uninstall.clear-db-assets' => function( ContainerInterface $container ) : ClearDatabaseAssets {
return new ClearDatabaseAssets(
$container->get( 'uninstall.module-url' ),
$container->get( 'ppcp.asset-version' ),
'ppcp-clear-db',
$container->get( 'uninstall.clear-database-script-data' )
);
},
'uninstall.clear-db' => function( ContainerInterface $container ) : ClearDatabaseInterface {
return new ClearDatabase();
},
);

View file

@ -0,0 +1,96 @@
<?php
/**
* Register and configure assets for uninstall module.
*
* @package WooCommerce\PayPalCommerce\Uninstall\Assets
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Uninstall\Assets;
/**
* Class ClearDatabaseAssets
*/
class ClearDatabaseAssets {
/**
* The URL to the module.
*
* @var string
*/
private $module_url;
/**
* The assets version.
*
* @var string
*/
private $version;
/**
* The script name.
*
* @var string
*/
protected $script_name;
/**
* A map of script data.
*
* @var array
*/
protected $script_data;
/**
* ClearDatabaseAssets constructor.
*
* @param string $module_url The URL to the module.
* @param string $version The assets version.
* @param string $script_name The script name.
* @param array $script_data A map of script data.
*/
public function __construct(
string $module_url,
string $version,
string $script_name,
array $script_data
) {
$this->module_url = $module_url;
$this->version = $version;
$this->script_data = $script_data;
$this->script_name = $script_name;
}
/**
* Registers the scripts and styles.
*
* @return void
*/
public function register(): void {
$module_url = untrailingslashit( $this->module_url );
wp_register_script(
$this->script_name,
"{$module_url}/assets/js/{$this->script_name}.js",
array( 'jquery' ),
$this->version,
true
);
wp_localize_script(
$this->script_name,
'PayPalCommerceGatewayClearDb',
$this->script_data
);
}
/**
* Enqueues the necessary scripts.
*
* @return void
*/
public function enqueue(): void {
wp_enqueue_script( $this->script_name );
}
}

View file

@ -0,0 +1,34 @@
<?php
/**
* Clears the plugin related data from DB.
*
* @package WooCommerce\PayPalCommerce\Uninstall
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Uninstall;
/**
* Class ClearDatabase
*/
class ClearDatabase implements ClearDatabaseInterface {
/**
* {@inheritDoc}
*/
public function delete_options( array $option_names ):void {
foreach ( $option_names as $option_name ) {
delete_option( $option_name );
}
}
/**
* {@inheritDoc}
*/
public function clear_scheduled_actions( array $action_names ):void {
foreach ( $action_names as $action_name ) {
as_unschedule_action( $action_name );
}
}
}

View file

@ -0,0 +1,32 @@
<?php
/**
* Can delete the options and clear scheduled actions from database.
*
* @package WooCommerce\PayPalCommerce\Uninstall
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Uninstall;
use RuntimeException;
interface ClearDatabaseInterface {
/**
* Deletes the given options from database.
*
* @param string[] $option_names The list of option names.
* @throws RuntimeException If problem deleting.
*/
public function delete_options( array $option_names ): void;
/**
* Clears the given scheduled actions.
*
* @param string[] $action_names The list of scheduled action names.
* @throws RuntimeException If problem clearing.
*/
public function clear_scheduled_actions( array $action_names ): void;
}

View file

@ -0,0 +1,98 @@
<?php
/**
* The uninstall module.
*
* @package WooCommerce\PayPalCommerce\Uninstall
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Uninstall;
use Exception;
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
use WooCommerce\PayPalCommerce\Uninstall\Assets\ClearDatabaseAssets;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
* Class UninstallModule
*/
class UninstallModule implements ModuleInterface {
/**
* {@inheritDoc}
*/
public function setup(): ServiceProviderInterface {
return new ServiceProvider(
require __DIR__ . '/../services.php',
require __DIR__ . '/../extensions.php'
);
}
/**
* {@inheritDoc}
*/
public function run( ContainerInterface $container ): void {
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
if ( Settings::CONNECTION_TAB_ID === $page_id ) {
$this->registerClearDatabaseAssets( $container->get( 'uninstall.clear-db-assets' ) );
}
$request_data = $container->get( 'button.request-data' );
$clear_db = $container->get( 'uninstall.clear-db' );
$clear_db_endpoint = $container->get( 'uninstall.clear-db-endpoint' );
$option_names = $container->get( 'uninstall.ppcp-all-option-names' );
$scheduled_action_names = $container->get( 'uninstall.ppcp-all-scheduled-action-names' );
$this->handleClearDbAjaxRequest( $request_data, $clear_db, $clear_db_endpoint, $option_names, $scheduled_action_names );
}
/**
* Registers the assets for clear database functionality.
*
* @param ClearDatabaseAssets $asset_loader The clear database functionality asset loader.
*/
protected function registerClearDatabaseAssets( ClearDatabaseAssets $asset_loader ): void {
add_action( 'init', array( $asset_loader, 'register' ) );
add_action( 'admin_enqueue_scripts', array( $asset_loader, 'enqueue' ) );
}
/**
* Handles the AJAX request to clear the database.
*
* @param RequestData $request_data The request data helper.
* @param ClearDatabaseInterface $clear_db Can delete the options and clear scheduled actions from database.
* @param string $nonce The nonce.
* @param string[] $option_names The list of option names.
* @param string[] $scheduled_action_names The list of scheduled action names.
*/
protected function handleClearDbAjaxRequest(
RequestData $request_data,
ClearDatabaseInterface $clear_db,
string $nonce,
array $option_names,
array $scheduled_action_names
): void {
add_action(
"wc_ajax_{$nonce}",
static function () use ( $request_data, $clear_db, $nonce, $option_names, $scheduled_action_names ) {
try {
// Validate nonce.
$request_data->read_request( $nonce );
$clear_db->delete_options( $option_names );
$clear_db->clear_scheduled_actions( $scheduled_action_names );
wp_send_json_success();
return true;
} catch ( Exception $error ) {
wp_send_json_error( $error->getMessage(), 403 );
return false;
}
}
);
}
}

View file

@ -0,0 +1,35 @@
const path = require('path');
const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
devtool: isProduction ? 'source-map' : 'eval-source-map',
mode: isProduction ? 'production' : 'development',
target: 'web',
entry: {
'ppcp-clear-db': path.resolve('./resources/js/ppcp-clear-db.js'),
},
output: {
path: path.resolve(__dirname, 'assets/'),
filename: 'js/[name].js',
},
module: {
rules: [{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
{
loader: 'file-loader',
options: {
name: 'css/[name].css',
}
},
{loader:'sass-loader'}
]
}]
}
};

File diff suppressed because it is too large Load diff

View file

@ -84,6 +84,8 @@ return array(
$application_context_repository,
$pay_pal_request_id_repository,
$subscription_helper,
$container->get( 'wcgateway.is-fraudnet-enabled' ),
$container->get( 'wcgateway.fraudnet' ),
$bn_code
);
},

View file

@ -11,6 +11,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint;
@ -28,6 +29,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Admin\FeesRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Admin\OrderTablePaymentStatusColumn;
use WooCommerce\PayPalCommerce\WcGateway\Admin\PaymentStatusOrderDetail;
use WooCommerce\PayPalCommerce\WcGateway\Admin\RenderAuthorizeAction;
use WooCommerce\PayPalCommerce\WcGateway\Assets\FraudNetAssets;
use WooCommerce\PayPalCommerce\WcGateway\Checkout\CheckoutPayPalAddressPreset;
use WooCommerce\PayPalCommerce\WcGateway\Checkout\DisableGateways;
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
@ -38,9 +40,9 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXO;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOEndpoint;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSessionId;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSourceWebsiteId;
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSessionId;
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSourceWebsiteId;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSourceFactory;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoice;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
@ -169,7 +171,7 @@ return array(
CreditCardGateway::ID,
PayUponInvoiceGateway::ID,
CardButtonGateway::ID,
OXXOGateway::ID .
OXXOGateway::ID,
Settings::PAY_LATER_TAB_ID,
),
true
@ -941,7 +943,7 @@ return array(
$container->get( 'api.host' ),
$container->get( 'api.bearer' ),
$container->get( 'api.factory.order' ),
$container->get( 'wcgateway.pay-upon-invoice-fraudnet' ),
$container->get( 'wcgateway.fraudnet' ),
$container->get( 'woocommerce.logger.woocommerce' )
);
},
@ -962,15 +964,15 @@ return array(
$container->get( 'wcgateway.processor.refunds' )
);
},
'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId {
'wcgateway.fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId {
return new FraudNetSessionId();
},
'wcgateway.pay-upon-invoice-fraudnet-source-website-id' => static function ( ContainerInterface $container ): FraudNetSourceWebsiteId {
'wcgateway.fraudnet-source-website-id' => static function ( ContainerInterface $container ): FraudNetSourceWebsiteId {
return new FraudNetSourceWebsiteId( $container->get( 'api.merchant_id' ) );
},
'wcgateway.pay-upon-invoice-fraudnet' => static function ( ContainerInterface $container ): FraudNet {
$session_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-session-id' );
$source_website_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-source-website-id' );
'wcgateway.fraudnet' => static function ( ContainerInterface $container ): FraudNet {
$session_id = $container->get( 'wcgateway.fraudnet-session-id' );
$source_website_id = $container->get( 'wcgateway.fraudnet-source-website-id' );
return new FraudNet(
(string) $session_id(),
(string) $source_website_id()
@ -991,21 +993,15 @@ return array(
},
'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
return new PayUponInvoice(
$container->get( 'wcgateway.url' ),
$container->get( 'wcgateway.pay-upon-invoice-fraudnet' ),
$container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ),
$container->get( 'woocommerce.logger.woocommerce' ),
$container->get( 'wcgateway.settings' ),
$container->get( 'onboarding.environment' ),
$container->get( 'ppcp.asset-version' ),
$container->get( 'onboarding.state' ),
$container->get( 'wcgateway.is-ppcp-settings-page' ),
$container->get( 'wcgateway.current-ppcp-settings-page-id' ),
$container->get( 'wcgateway.pay-upon-invoice-product-status' ),
$container->get( 'wcgateway.pay-upon-invoice-helper' ),
$container->get( 'wcgateway.checkout-helper' ),
$container->get( 'api.factory.capture' ),
$container->get( 'session.handler' )
$container->get( 'api.factory.capture' )
);
},
'wcgateway.oxxo' => static function( ContainerInterface $container ): OXXO {
@ -1303,4 +1299,78 @@ return array(
return $pay_later_button_locations;
},
'wcgateway.ppcp-gateways' => static function ( ContainerInterface $container ): array {
return array(
PayPalGateway::ID,
CreditCardGateway::ID,
PayUponInvoiceGateway::ID,
CardButtonGateway::ID,
OXXOGateway::ID,
);
},
'wcgateway.enabled-ppcp-gateways' => static function ( ContainerInterface $container ): array {
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
$ppcp_gateways = $container->get( 'wcgateway.ppcp-gateways' );
$enabled_ppcp_gateways = array();
foreach ( $ppcp_gateways as $gateway ) {
if ( ! isset( $available_gateways[ $gateway ] ) ) {
continue;
}
$enabled_ppcp_gateways[] = $gateway;
}
return $enabled_ppcp_gateways;
},
'wcgateway.is-paypal-continuation' => static function ( ContainerInterface $container ): bool {
$session_handler = $container->get( 'session.handler' );
assert( $session_handler instanceof SessionHandler );
$order = $session_handler->order();
if ( ! $order ) {
return false;
}
$source = $order->payment_source();
if ( $source && $source->card() ) {
return false; // Ignore for DCC.
}
if ( 'card' === $session_handler->funding_source() ) {
return false; // Ignore for card buttons.
}
return true;
},
'wcgateway.current-context' => static function ( ContainerInterface $container ): string {
$context = 'mini-cart';
if ( is_product() || wc_post_content_has_shortcode( 'product_page' ) ) {
$context = 'product';
}
if ( is_cart() ) {
$context = 'cart';
}
if ( is_checkout() && ! $container->get( 'wcgateway.is-paypal-continuation' ) ) {
$context = 'checkout';
}
if ( is_checkout_pay_page() ) {
$context = 'pay-now';
}
return $context;
},
'wcgateway.is-fraudnet-enabled' => static function ( ContainerInterface $container ): bool {
$settings = $container->get( 'wcgateway.settings' );
assert( $settings instanceof Settings );
return $settings->has( 'fraudnet_enabled' ) && $settings->get( 'fraudnet_enabled' );
},
'wcgateway.fraudnet-assets' => function( ContainerInterface $container ) : FraudNetAssets {
return new FraudNetAssets(
$container->get( 'wcgateway.url' ),
$container->get( 'ppcp.asset-version' ),
$container->get( 'wcgateway.fraudnet' ),
$container->get( 'onboarding.environment' ),
$container->get( 'wcgateway.settings' ),
$container->get( 'wcgateway.enabled-ppcp-gateways' ),
$container->get( 'wcgateway.current-context' ),
$container->get( 'wcgateway.is-fraudnet-enabled' )
);
},
);

View file

@ -0,0 +1,186 @@
<?php
/**
* Register and configure FraudNet assets
*
* @package WooCommerce\PayPalCommerce\WcGateway\Assets
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Assets;
use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
* Class FraudNetAssets
*/
class FraudNetAssets {
/**
* The URL of this module.
*
* @var string
*/
protected $module_url;
/**
* The assets version.
*
* @var string
*/
protected $version;
/**
* The FraudNet entity.
*
* @var FraudNet
*/
protected $fraud_net;
/**
* The environment.
*
* @var Environment
*/
protected $environment;
/**
* The Settings.
*
* @var Settings
*/
protected $settings;
/**
* The list of enabled PayPal gateways.
*
* @var string[]
*/
protected $enabled_ppcp_gateways;
/**
* The current context.
*
* @var string
*/
protected $context;
/**
* True if FraudNet support is enabled in settings, otherwise false.
*
* @var bool
*/
protected $is_fraudnet_enabled;
/**
* Assets constructor.
*
* @param string $module_url The url of this module.
* @param string $version The assets version.
* @param FraudNet $fraud_net The FraudNet entity.
* @param Environment $environment The environment.
* @param Settings $settings The Settings.
* @param string[] $enabled_ppcp_gateways The list of enabled PayPal gateways.
* @param string $context The current context.
* @param bool $is_fraudnet_enabled true if FraudNet support is enabled in settings, otherwise false.
*/
public function __construct(
string $module_url,
string $version,
FraudNet $fraud_net,
Environment $environment,
Settings $settings,
array $enabled_ppcp_gateways,
string $context,
bool $is_fraudnet_enabled
) {
$this->module_url = $module_url;
$this->version = $version;
$this->fraud_net = $fraud_net;
$this->environment = $environment;
$this->settings = $settings;
$this->enabled_ppcp_gateways = $enabled_ppcp_gateways;
$this->context = $context;
$this->is_fraudnet_enabled = $is_fraudnet_enabled;
}
/**
* Registers FraudNet assets.
*/
public function register_assets(): void {
add_action(
'wp_enqueue_scripts',
function() {
if ( $this->should_load_fraudnet_script() ) {
wp_enqueue_script(
'ppcp-fraudnet',
trailingslashit( $this->module_url ) . 'assets/js/fraudnet.js',
array(),
$this->version,
true
);
wp_localize_script(
'ppcp-fraudnet',
'FraudNetConfig',
array(
'f' => $this->fraud_net->session_id(),
's' => $this->fraud_net->source_website_id(),
'sandbox' => $this->environment->current_environment_is( Environment::SANDBOX ),
)
);
}
}
);
}
/**
* Checks if FraudNet script should be loaded.
*
* @return bool true if FraudNet script should be loaded, otherwise false.
*/
protected function should_load_fraudnet_script(): bool {
if ( empty( $this->enabled_ppcp_gateways ) ) {
return false;
}
$is_pui_gateway_enabled = in_array( PayUponInvoiceGateway::ID, $this->enabled_ppcp_gateways, true );
$is_only_standard_gateway_enabled = $this->enabled_ppcp_gateways === array( PayPalGateway::ID );
if ( $this->context !== 'checkout' || $is_only_standard_gateway_enabled ) {
return $this->is_fraudnet_enabled && $this->are_buttons_enabled_for_context();
}
return $is_pui_gateway_enabled ? true : $this->is_fraudnet_enabled;
}
/**
* Checks if buttons are enabled for current context.
*
* @return bool true if enabled, otherwise false.
*/
protected function are_buttons_enabled_for_context() : bool {
if ( ! in_array( PayPalGateway::ID, $this->enabled_ppcp_gateways, true ) ) {
return false;
}
$location_prefix = $this->context === 'checkout' ? '' : "{$this->context}_";
$setting_name = "button_{$location_prefix}enabled";
$buttons_enabled_for_context = $this->settings->has( $setting_name ) && $this->settings->get( $setting_name );
if ( $this->context === 'product' ) {
return $buttons_enabled_for_context || $this->settings->has( 'mini-cart' ) && $this->settings->get( 'mini-cart' );
}
if ( $this->context === 'pay-now' ) {
return true;
}
return $buttons_enabled_for_context;
}
}

View file

@ -7,7 +7,7 @@
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
namespace WooCommerce\PayPalCommerce\WcGateway\FraudNet;
/**
* Class FraudNet

View file

@ -7,7 +7,7 @@
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
namespace WooCommerce\PayPalCommerce\WcGateway\FraudNet;
use Exception;

View file

@ -7,7 +7,7 @@
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
namespace WooCommerce\PayPalCommerce\WcGateway\FraudNet;
/**
* Class FraudNetSourceWebsiteId.

View file

@ -81,12 +81,12 @@ class OXXO {
add_filter(
'woocommerce_thankyou_order_received_text',
/**
* Order can be null.
* Param types removed to avoid third-party issues.
*
* @psalm-suppress MissingClosureParamType
*/
function( string $message, $order ) {
if ( ! $order instanceof WC_Order ) {
function( $message, $order ) {
if ( ! is_string( $message ) || ! $order instanceof WC_Order ) {
return $message;
}

View file

@ -17,6 +17,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\CaptureFactory;
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
@ -34,20 +35,6 @@ class PayUponInvoice {
use TransactionIdHandlingTrait;
/**
* The module URL.
*
* @var string
*/
protected $module_url;
/**
* The FraudNet entity.
*
* @var FraudNet
*/
protected $fraud_net;
/**
* The pui order endpoint.
*
@ -69,20 +56,6 @@ class PayUponInvoice {
*/
protected $settings;
/**
* The environment.
*
* @var Environment
*/
protected $environment;
/**
* The asset version.
*
* @var string
*/
protected $asset_version;
/**
* The PUI helper.
*
@ -97,13 +70,6 @@ class PayUponInvoice {
*/
protected $state;
/**
* Whether the current page is the PPCP settings page.
*
* @var bool
*/
protected $is_ppcp_settings_page;
/**
* Current PayPal settings page id.
*
@ -132,64 +98,39 @@ class PayUponInvoice {
*/
protected $capture_factory;
/**
* The session handler
*
* @var SessionHandler
*/
protected $session_handler;
/**
* PayUponInvoice constructor.
*
* @param string $module_url The module URL.
* @param FraudNet $fraud_net The FraudNet entity.
* @param PayUponInvoiceOrderEndpoint $pui_order_endpoint The PUI order endpoint.
* @param LoggerInterface $logger The logger.
* @param Settings $settings The settings.
* @param Environment $environment The environment.
* @param string $asset_version The asset version.
* @param State $state The onboarding state.
* @param bool $is_ppcp_settings_page Whether page is PayPal settings poge.
* @param string $current_ppcp_settings_page_id Current PayPal settings page id.
* @param PayUponInvoiceProductStatus $pui_product_status The PUI product status.
* @param PayUponInvoiceHelper $pui_helper The PUI helper.
* @param CheckoutHelper $checkout_helper The checkout helper.
* @param CaptureFactory $capture_factory The capture factory.
* @param SessionHandler $session_handler The session handler.
*/
public function __construct(
string $module_url,
FraudNet $fraud_net,
PayUponInvoiceOrderEndpoint $pui_order_endpoint,
LoggerInterface $logger,
Settings $settings,
Environment $environment,
string $asset_version,
State $state,
bool $is_ppcp_settings_page,
string $current_ppcp_settings_page_id,
PayUponInvoiceProductStatus $pui_product_status,
PayUponInvoiceHelper $pui_helper,
CheckoutHelper $checkout_helper,
CaptureFactory $capture_factory,
SessionHandler $session_handler
CaptureFactory $capture_factory
) {
$this->module_url = $module_url;
$this->fraud_net = $fraud_net;
$this->pui_order_endpoint = $pui_order_endpoint;
$this->logger = $logger;
$this->settings = $settings;
$this->environment = $environment;
$this->asset_version = $asset_version;
$this->state = $state;
$this->is_ppcp_settings_page = $is_ppcp_settings_page;
$this->current_ppcp_settings_page_id = $current_ppcp_settings_page_id;
$this->pui_product_status = $pui_product_status;
$this->pui_helper = $pui_helper;
$this->checkout_helper = $checkout_helper;
$this->capture_factory = $capture_factory;
$this->session_handler = $session_handler;
}
/**
@ -236,11 +177,6 @@ class PayUponInvoice {
}
);
add_action(
'wp_enqueue_scripts',
array( $this, 'register_assets' )
);
add_action(
'ppcp_payment_capture_completed_webhook_handler',
function ( WC_Order $wc_order, string $order_id ) {
@ -360,7 +296,16 @@ class PayUponInvoice {
add_filter(
'woocommerce_gateway_description',
function( string $description, string $id ): string {
/**
* Param types removed to avoid third-party issues.
*
* @psalm-suppress MissingClosureParamType
*/
function( $description, $id ): string {
if ( ! is_string( $description ) || ! is_string( $id ) ) {
return $description;
}
if ( PayUponInvoiceGateway::ID === $id ) {
ob_start();
@ -423,7 +368,16 @@ class PayUponInvoice {
add_action(
'woocommerce_after_checkout_validation',
function( array $fields, WP_Error $errors ) {
/**
* Param types removed to avoid third-party issues.
*
* @psalm-suppress MissingClosureParamType
*/
function( $fields, WP_Error $errors ) {
if ( ! is_array( $fields ) ) {
return;
}
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$payment_method = wc_clean( wp_unslash( $_POST['payment_method'] ?? '' ) );
if ( PayUponInvoiceGateway::ID !== $payment_method ) {
@ -458,8 +412,13 @@ class PayUponInvoice {
add_filter(
'woocommerce_available_payment_gateways',
function ( array $methods ): array {
if ( State::STATE_ONBOARDED !== $this->state->current_state() ) {
/**
* Param types removed to avoid third-party issues.
*
* @psalm-suppress MissingClosureParamType
*/
function ( $methods ): array {
if ( ! is_array( $methods ) || State::STATE_ONBOARDED !== $this->state->current_state() ) {
return $methods;
}
@ -587,31 +546,4 @@ class PayUponInvoice {
}
);
}
/**
* Registers PUI assets.
*/
public function register_assets(): void {
$gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' );
$gateway_enabled = $gateway_settings['enabled'] ?? '';
if ( $gateway_enabled === 'yes' && ! $this->session_handler->order() && ( is_checkout() || is_checkout_pay_page() ) ) {
wp_enqueue_script(
'ppcp-pay-upon-invoice',
trailingslashit( $this->module_url ) . 'assets/js/pay-upon-invoice.js',
array(),
$this->asset_version,
true
);
wp_localize_script(
'ppcp-pay-upon-invoice',
'FraudNetConfig',
array(
'f' => $this->fraud_net->session_id(),
's' => $this->fraud_net->source_website_id(),
'sandbox' => $this->environment->current_environment_is( Environment::SANDBOX ),
)
);
}
}
}

View file

@ -394,6 +394,24 @@ return function ( ContainerInterface $container, array $fields ): array {
'gateway' => Settings::CONNECTION_TAB_ID,
'input_class' => $container->get( 'wcgateway.settings.should-disable-tracking-checkbox' ) ? array( 'ppcp-disabled-checkbox' ) : array(),
),
'fraudnet_enabled' => array(
'title' => __( 'FraudNet', 'woocommerce-paypal-payments' ),
'type' => 'checkbox',
'desc_tip' => true,
'label' => sprintf(
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
__( 'Manage online risk with %1$sFraudNet%2$s.', 'woocommerce-paypal-payments' ),
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#FraudNet" target="_blank">',
'</a>'
),
'description' => __( 'FraudNet is a JavaScript library developed by PayPal and embedded into a merchants web page to collect browser-based data to help reduce fraud.', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'credentials_integration_configuration_heading' => array(
'heading' => __( 'General integration configuration', 'woocommerce-paypal-payments' ),

View file

@ -22,6 +22,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Admin\FeesRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Admin\OrderTablePaymentStatusColumn;
use WooCommerce\PayPalCommerce\WcGateway\Admin\PaymentStatusOrderDetail;
use WooCommerce\PayPalCommerce\WcGateway\Admin\RenderAuthorizeAction;
use WooCommerce\PayPalCommerce\WcGateway\Assets\FraudNetAssets;
use WooCommerce\PayPalCommerce\WcGateway\Assets\SettingsPageAssets;
use WooCommerce\PayPalCommerce\WcGateway\Checkout\CheckoutPayPalAddressPreset;
use WooCommerce\PayPalCommerce\WcGateway\Checkout\DisableGateways;
@ -258,6 +259,10 @@ class WCGatewayModule implements ModuleInterface {
}
( $c->get( 'wcgateway.oxxo' ) )->init();
$fraudnet_assets = $c->get( 'wcgateway.fraudnet-assets' );
assert( $fraudnet_assets instanceof FraudNetAssets );
$fraudnet_assets->register_assets();
}
);

View file

@ -7,7 +7,7 @@ module.exports = {
target: 'web',
entry: {
'gateway-settings': path.resolve('./resources/js/gateway-settings.js'),
'pay-upon-invoice': path.resolve('./resources/js/pay-upon-invoice.js'),
'fraudnet': path.resolve('./resources/js/fraudnet.js'),
'oxxo': path.resolve('./resources/js/oxxo.js'),
'gateway-settings-style': path.resolve('./resources/css/gateway-settings.scss'),
},

View file

@ -23,7 +23,7 @@ class WebhookSimulation {
public const STATE_WAITING = 'waiting';
public const STATE_RECEIVED = 'received';
private const OPTION_ID = 'ppcp-webhook-simulation';
public const OPTION_ID = 'ppcp-webhook-simulation';
/**
* The webhooks endpoint.