mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-31 06:52:50 +08:00
Add express checkout block (wip)
This commit is contained in:
parent
0bf18d67c5
commit
ea3e5bbeb6
22 changed files with 3199 additions and 25 deletions
370
.psalm/wcblocks.php
Normal file
370
.psalm/wcblocks.php
Normal file
|
@ -0,0 +1,370 @@
|
|||
<?php
|
||||
namespace Automattic\WooCommerce\Blocks\Integrations {
|
||||
/**
|
||||
* Integration.Interface
|
||||
*
|
||||
* Integrations must use this interface when registering themselves with blocks,
|
||||
*/
|
||||
interface IntegrationInterface
|
||||
{
|
||||
/**
|
||||
* The name of the integration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name();
|
||||
|
||||
/**
|
||||
* When called invokes any initialization/setup for the integration.
|
||||
*/
|
||||
public function initialize();
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue in the frontend context.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_script_handles();
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue in the editor context.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_editor_script_handles();
|
||||
|
||||
/**
|
||||
* An array of key, value pairs of data made available to the block on the client side.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_script_data();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Automattic\WooCommerce\Blocks\Payments {
|
||||
use Automattic\WooCommerce\Blocks\Integrations\IntegrationInterface;
|
||||
|
||||
interface PaymentMethodTypeInterface extends IntegrationInterface
|
||||
{
|
||||
/**
|
||||
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active();
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue for this payment method in
|
||||
* the frontend context
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_payment_method_script_handles();
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue for this payment method in
|
||||
* the admin context
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_payment_method_script_handles_for_admin();
|
||||
|
||||
/**
|
||||
* An array of key, value pairs of data made available to payment methods
|
||||
* client side.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_payment_method_data();
|
||||
|
||||
/**
|
||||
* Get array of supported features.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_supported_features();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Automattic\WooCommerce\Blocks\Payments\Integrations
|
||||
{
|
||||
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodTypeInterface;
|
||||
|
||||
/**
|
||||
* AbstractPaymentMethodType class.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
abstract class AbstractPaymentMethodType implements PaymentMethodTypeInterface
|
||||
{
|
||||
/**
|
||||
* Payment method name defined by payment methods extending this class.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = '';
|
||||
|
||||
/**
|
||||
* Settings from the WP options table
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $settings = [];
|
||||
|
||||
/**
|
||||
* Get a setting from the settings array if set.
|
||||
*
|
||||
* @param string $name Setting name.
|
||||
* @param mixed $default Value that is returned if the setting does not exist.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_setting($name, $default = '')
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the payment method.
|
||||
*/
|
||||
public function get_name()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue for this payment method in
|
||||
* the frontend context
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_payment_method_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue for this payment method in
|
||||
* the admin context
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_payment_method_script_handles_for_admin()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of supported features.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_supported_features()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of key, value pairs of data made available to payment methods
|
||||
* client side.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_payment_method_data()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue in the frontend context.
|
||||
*
|
||||
* Alias of get_payment_method_script_handles. Defined by IntegrationInterface.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue in the admin context.
|
||||
*
|
||||
* Alias of get_payment_method_script_handles_for_admin. Defined by IntegrationInterface.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_editor_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of key, value pairs of data made available to the block on the client side.
|
||||
*
|
||||
* Alias of get_payment_method_data. Defined by IntegrationInterface.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_script_data()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Automattic\WooCommerce\Blocks\Integrations {
|
||||
/**
|
||||
* Class used for tracking registered integrations with various Block types.
|
||||
*/
|
||||
class IntegrationRegistry
|
||||
{
|
||||
/**
|
||||
* Integration identifier is used to construct hook names and is given when the integration registry is initialized.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $registry_identifier = '';
|
||||
|
||||
/**
|
||||
* Registered integrations, as `$name => $instance` pairs.
|
||||
*
|
||||
* @var IntegrationInterface[]
|
||||
*/
|
||||
protected $registered_integrations = [];
|
||||
|
||||
/**
|
||||
* Initializes all registered integrations.
|
||||
*
|
||||
* Integration identifier is used to construct hook names and is given when the integration registry is initialized.
|
||||
*
|
||||
* @param string $registry_identifier Identifier for this registry.
|
||||
*/
|
||||
public function initialize($registry_identifier = '')
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an integration.
|
||||
*
|
||||
* @param IntegrationInterface $integration An instance of IntegrationInterface.
|
||||
*
|
||||
* @return boolean True means registered successfully.
|
||||
*/
|
||||
public function register(IntegrationInterface $integration)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an integration is already registered.
|
||||
*
|
||||
* @param string $name Integration name.
|
||||
* @return bool True if the integration is registered, false otherwise.
|
||||
*/
|
||||
public function is_registered($name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-register an integration.
|
||||
*
|
||||
* @param string|IntegrationInterface $name Integration name, or alternatively a IntegrationInterface instance.
|
||||
* @return boolean|IntegrationInterface Returns the unregistered integration instance if unregistered successfully.
|
||||
*/
|
||||
public function unregister($name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a registered Integration by name.
|
||||
*
|
||||
* @param string $name Integration name.
|
||||
* @return IntegrationInterface|null The registered integration, or null if it is not registered.
|
||||
*/
|
||||
public function get_registered($name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all registered integrations.
|
||||
*
|
||||
* @return IntegrationInterface[]
|
||||
*/
|
||||
public function get_all_registered()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered integration's script handles for the editor.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_all_registered_editor_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered integration's script handles.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_all_registered_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered integration's script data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_all_registered_script_data()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Automattic\WooCommerce\Blocks\Payments {
|
||||
use Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry;
|
||||
|
||||
/**
|
||||
* Class used for interacting with payment method types.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
final class PaymentMethodRegistry extends IntegrationRegistry
|
||||
{
|
||||
/**
|
||||
* Integration identifier is used to construct hook names and is given when the integration registry is initialized.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $registry_identifier = 'payment_method_type';
|
||||
|
||||
/**
|
||||
* Retrieves all registered payment methods that are also active.
|
||||
*
|
||||
* @return PaymentMethodTypeInterface[]
|
||||
*/
|
||||
public function get_all_active_registered()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered payment method script handles, but only for active payment methods.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_all_active_payment_method_script_dependencies()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered payment method script data, but only for active payment methods.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_all_registered_script_data()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
40
composer.lock
generated
40
composer.lock
generated
|
@ -1430,30 +1430,30 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.4.1",
|
||||
"version": "1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
|
||||
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9",
|
||||
"doctrine/coding-standard": "^9 || ^11",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpbench/phpbench": "^0.16 || ^1",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpstan/phpstan-phpunit": "^1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"vimeo/psalm": "^4.22"
|
||||
"vimeo/psalm": "^4.30 || ^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -1480,7 +1480,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/instantiator/issues",
|
||||
"source": "https://github.com/doctrine/instantiator/tree/1.4.1"
|
||||
"source": "https://github.com/doctrine/instantiator/tree/1.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1496,7 +1496,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-03T08:28:38+00:00"
|
||||
"time": "2022-12-30T00:15:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "felixfbecker/advanced-json-rpc",
|
||||
|
@ -3792,16 +3792,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.4.16",
|
||||
"version": "v5.4.17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "8e9b9c8dfb33af6057c94e1b44846bee700dc5ef"
|
||||
"reference": "58422fdcb0e715ed05b385f70d3e8b5ed4bbd45f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/8e9b9c8dfb33af6057c94e1b44846bee700dc5ef",
|
||||
"reference": "8e9b9c8dfb33af6057c94e1b44846bee700dc5ef",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/58422fdcb0e715ed05b385f70d3e8b5ed4bbd45f",
|
||||
"reference": "58422fdcb0e715ed05b385f70d3e8b5ed4bbd45f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3871,7 +3871,7 @@
|
|||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v5.4.16"
|
||||
"source": "https://github.com/symfony/console/tree/v5.4.17"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3887,7 +3887,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-25T14:09:27+00:00"
|
||||
"time": "2022-12-28T14:15:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
|
@ -4450,16 +4450,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v5.4.15",
|
||||
"version": "v5.4.17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed"
|
||||
"reference": "55733a8664b8853b003e70251c58bc8cb2d82a6b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/571334ce9f687e3e6af72db4d3b2a9431e4fd9ed",
|
||||
"reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/55733a8664b8853b003e70251c58bc8cb2d82a6b",
|
||||
"reference": "55733a8664b8853b003e70251c58bc8cb2d82a6b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4516,7 +4516,7 @@
|
|||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v5.4.15"
|
||||
"source": "https://github.com/symfony/string/tree/v5.4.17"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4532,7 +4532,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-10-05T15:16:54+00:00"
|
||||
"time": "2022-12-12T15:54:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
|
|
|
@ -26,6 +26,7 @@ return function ( string $root_dir ): iterable {
|
|||
( require "$modules_dir/ppcp-vaulting/module.php" )(),
|
||||
( require "$modules_dir/ppcp-order-tracking/module.php" )(),
|
||||
( require "$modules_dir/ppcp-uninstall/module.php" )(),
|
||||
( require "$modules_dir/ppcp-blocks/module.php" )(),
|
||||
);
|
||||
|
||||
return $modules;
|
||||
|
|
14
modules/ppcp-blocks/.babelrc
Normal file
14
modules/ppcp-blocks/.babelrc
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"useBuiltIns": "usage",
|
||||
"corejs": "3.25.0"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@babel/preset-react"
|
||||
]
|
||||
]
|
||||
}
|
3
modules/ppcp-blocks/.gitignore
vendored
Normal file
3
modules/ppcp-blocks/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
node_modules
|
||||
assets/js
|
||||
assets/css
|
17
modules/ppcp-blocks/composer.json
Normal file
17
modules/ppcp-blocks/composer.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "woocommerce/ppcp-blocks",
|
||||
"type": "dhii-mod",
|
||||
"description": "Blocks 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\\Blocks\\": "src"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
12
modules/ppcp-blocks/extensions.php
Normal file
12
modules/ppcp-blocks/extensions.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* The blocks module extensions.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Blocks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Blocks;
|
||||
|
||||
return array();
|
16
modules/ppcp-blocks/module.php
Normal file
16
modules/ppcp-blocks/module.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* The blocks module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Blocks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Blocks;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
|
||||
return static function (): ModuleInterface {
|
||||
return new BlocksModule();
|
||||
};
|
34
modules/ppcp-blocks/package.json
Normal file
34
modules/ppcp-blocks/package.json
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "ppcp-blocks",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"browserslist": [
|
||||
"> 0.5%",
|
||||
"Safari >= 8",
|
||||
"Chrome >= 41",
|
||||
"Firefox >= 43",
|
||||
"Edge >= 14"
|
||||
],
|
||||
"dependencies": {
|
||||
"@paypal/react-paypal-js": "^7.8.2",
|
||||
"core-js": "^3.25.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19",
|
||||
"@babel/preset-env": "^7.19",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@woocommerce/dependency-extraction-webpack-plugin": "^2.2.0",
|
||||
"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"
|
||||
}
|
||||
}
|
84
modules/ppcp-blocks/resources/js/Helper/Address.js
Normal file
84
modules/ppcp-blocks/resources/js/Helper/Address.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @param {String} fullName
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const splitFullName = (fullName) => {
|
||||
fullName = fullName.trim()
|
||||
if (!fullName.includes(' ')) {
|
||||
return [fullName, ''];
|
||||
}
|
||||
const parts = fullName.split(' ');
|
||||
const firstName = parts[0];
|
||||
parts.shift();
|
||||
const lastName = parts.join(' ');
|
||||
return [firstName, lastName];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} address
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const paypalAddressToWc = (address) => {
|
||||
const map = {
|
||||
country_code: 'country',
|
||||
address_line_1: 'address_1',
|
||||
address_line_2: 'address_2',
|
||||
admin_area_1: 'state',
|
||||
admin_area_2: 'city',
|
||||
postal_code: 'postcode',
|
||||
};
|
||||
const result = {};
|
||||
Object.entries(map).forEach(([paypalKey, wcKey]) => {
|
||||
if (address[paypalKey]) {
|
||||
result[wcKey] = address[paypalKey];
|
||||
}
|
||||
})
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} shipping
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const paypalShippingToWc = (shipping) => {
|
||||
const [firstName, lastName] = splitFullName(shipping.name.full_name);
|
||||
return {
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
...paypalAddressToWc(shipping.address),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} payer
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const paypalPayerToWc = (payer) => {
|
||||
const firstName = payer.name.given_name;
|
||||
const lastName = payer.name.surname;
|
||||
const address = payer.address ? paypalAddressToWc(payer.address) : {};
|
||||
return {
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
email: payer.email_address,
|
||||
...address,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} order
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const paypalOrderToWcShippingAddress = (order) => {
|
||||
const res = paypalShippingToWc(order.purchase_units[0].shipping);
|
||||
|
||||
// use the name from billing if the same, to avoid possible mistakes when splitting full_name
|
||||
const billingAddress = paypalPayerToWc(order.payer);
|
||||
if (`${res.first_name} ${res.last_name}` === `${billingAddress.first_name} ${billingAddress.last_name}`) {
|
||||
res.first_name = billingAddress.first_name;
|
||||
res.last_name = billingAddress.last_name;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
151
modules/ppcp-blocks/resources/js/checkout-block.js
Normal file
151
modules/ppcp-blocks/resources/js/checkout-block.js
Normal file
|
@ -0,0 +1,151 @@
|
|||
import {useEffect, useState} from '@wordpress/element';
|
||||
import {registerExpressPaymentMethod} from '@woocommerce/blocks-registry';
|
||||
import {PayPalScriptProvider, PayPalButtons} from "@paypal/react-paypal-js";
|
||||
import {paypalOrderToWcShippingAddress, paypalPayerToWc} from "./Helper/Address";
|
||||
|
||||
const config = wc.wcSettings.getSetting('ppcp-gateway_data');
|
||||
|
||||
const PayPalComponent = ({
|
||||
onClick,
|
||||
onClose,
|
||||
onSubmit,
|
||||
eventRegistration,
|
||||
emitResponse,
|
||||
setExpressPaymentError,
|
||||
}) => {
|
||||
const {onPaymentProcessing} = eventRegistration;
|
||||
const {responseTypes} = emitResponse;
|
||||
|
||||
const [paypalOrder, setPaypalOrder] = useState(null);
|
||||
|
||||
const createOrder = async () => {
|
||||
try {
|
||||
const res = await fetch(config.scriptData.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.scriptData.ajax.create_order.nonce,
|
||||
bn_code: '',
|
||||
context: 'express',
|
||||
order_id: config.scriptData.order_id,
|
||||
payment_method: 'ppcp-gateway',
|
||||
funding_source: 'paypal',
|
||||
createaccount: false
|
||||
}),
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
if (json.data?.details?.length > 0) {
|
||||
throw new Error(json.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'));
|
||||
} else if (json.data?.message) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
|
||||
throw new Error(config.scriptData.labels.error.generic);
|
||||
}
|
||||
return json.data.id;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
setExpressPaymentError(err.message);
|
||||
|
||||
onClose();
|
||||
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const handleApprove = async (data, actions) => {
|
||||
try {
|
||||
const res = await fetch(config.scriptData.ajax.approve_order.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.scriptData.ajax.approve_order.nonce,
|
||||
order_id: data.orderID,
|
||||
//funding_source: ,
|
||||
})
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
if (typeof actions !== 'undefined' && typeof actions.restart !== 'undefined') {
|
||||
return actions.restart();
|
||||
}
|
||||
if (json.data?.message) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
|
||||
throw new Error(config.scriptData.labels.error.generic)
|
||||
}
|
||||
|
||||
setPaypalOrder(json.data);
|
||||
|
||||
onSubmit();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
setExpressPaymentError(err.message);
|
||||
|
||||
onClose();
|
||||
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
setExpressPaymentError('');
|
||||
|
||||
onClick();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeProcessing = onPaymentProcessing(() => {
|
||||
const shippingAddress = paypalOrderToWcShippingAddress(paypalOrder);
|
||||
const billingAddress = paypalPayerToWc(paypalOrder.payer);
|
||||
|
||||
return {
|
||||
type: responseTypes.SUCCESS,
|
||||
meta: {
|
||||
paymentMethodData: {
|
||||
'paypal_order_id': paypalOrder.id,
|
||||
},
|
||||
shippingData: {address: shippingAddress},
|
||||
billingAddress,
|
||||
billingData: billingAddress,
|
||||
},
|
||||
};
|
||||
});
|
||||
return () => {
|
||||
unsubscribeProcessing();
|
||||
};
|
||||
}, [onPaymentProcessing, paypalOrder]);
|
||||
|
||||
return (
|
||||
<PayPalScriptProvider options={config.scriptData.url_params}>
|
||||
<PayPalButtons
|
||||
style={config.scriptData.button.style}
|
||||
onClick={handleClick}
|
||||
onCancel={onClose}
|
||||
onError={onClose}
|
||||
createOrder={createOrder}
|
||||
onApprove={handleApprove}
|
||||
/>
|
||||
</PayPalScriptProvider>
|
||||
);
|
||||
}
|
||||
|
||||
registerExpressPaymentMethod({
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: config.title}}/>,
|
||||
content: <PayPalComponent/>,
|
||||
edit: <b>TODO: editing</b>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => true,
|
||||
supports: {
|
||||
features: ['products'],
|
||||
},
|
||||
});
|
34
modules/ppcp-blocks/services.php
Normal file
34
modules/ppcp-blocks/services.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/**
|
||||
* The blocks module services.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Blocks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Blocks;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
return array(
|
||||
'blocks.url' => static function ( ContainerInterface $container ): string {
|
||||
/**
|
||||
* The path cannot be false.
|
||||
*
|
||||
* @psalm-suppress PossiblyFalseArgument
|
||||
*/
|
||||
return plugins_url(
|
||||
'/modules/ppcp-blocks/',
|
||||
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
},
|
||||
'blocks.method' => static function ( ContainerInterface $container ): PayPalPaymentMethod {
|
||||
return new PayPalPaymentMethod(
|
||||
$container->get( 'blocks.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
$container->get( 'button.smart-button' ),
|
||||
$container->get( 'wcgateway.paypal-gateway' )
|
||||
);
|
||||
},
|
||||
);
|
53
modules/ppcp-blocks/src/BlocksModule.php
Normal file
53
modules/ppcp-blocks/src/BlocksModule.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/**
|
||||
* The blocks module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Blocks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Blocks;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class BlocksModule
|
||||
*/
|
||||
class BlocksModule implements ModuleInterface {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setup(): ServiceProviderInterface {
|
||||
return new ServiceProvider(
|
||||
require __DIR__ . '/../services.php',
|
||||
require __DIR__ . '/../extensions.php'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function run( ContainerInterface $c ): void {
|
||||
if ( class_exists( 'Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType' ) ) {
|
||||
add_action(
|
||||
'woocommerce_blocks_payment_method_type_registration',
|
||||
function( PaymentMethodRegistry $payment_method_registry ) use ( $c ): void {
|
||||
$payment_method_registry->register( $c->get( 'blocks.method' ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key for the module.
|
||||
*
|
||||
* @return string|void
|
||||
*/
|
||||
public function getKey() {
|
||||
}
|
||||
}
|
100
modules/ppcp-blocks/src/PayPalPaymentMethod.php
Normal file
100
modules/ppcp-blocks/src/PayPalPaymentMethod.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
/**
|
||||
* The blocks module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Blocks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Blocks;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
||||
/**
|
||||
* Class PayPalPaymentMethod
|
||||
*/
|
||||
class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
||||
/**
|
||||
* The URL of this module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The assets version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* The smart button script loading handler.
|
||||
*
|
||||
* @var SmartButtonInterface
|
||||
*/
|
||||
private $smart_button;
|
||||
|
||||
/**
|
||||
* The WC gateway.
|
||||
*
|
||||
* @var PayPalGateway
|
||||
*/
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* Assets constructor.
|
||||
*
|
||||
* @param string $module_url The url of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param SmartButtonInterface $smart_button The smart button script loading handler.
|
||||
* @param PayPalGateway $gateway The WC gateway.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
string $version,
|
||||
SmartButtonInterface $smart_button,
|
||||
PayPalGateway $gateway
|
||||
) {
|
||||
$this->name = PayPalGateway::ID;
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->smart_button = $smart_button;
|
||||
$this->gateway = $gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initialize() { }
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_script_handles() {
|
||||
wp_register_script(
|
||||
'ppcp-checkout-block',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/checkout-block.js',
|
||||
array(),
|
||||
$this->version,
|
||||
true
|
||||
);
|
||||
|
||||
return array( 'ppcp-checkout-block' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_data() {
|
||||
return array(
|
||||
'id' => $this->gateway->id,
|
||||
'title' => $this->gateway->title,
|
||||
'description' => $this->gateway->description,
|
||||
'scriptData' => $this->smart_button->script_data(),
|
||||
);
|
||||
}
|
||||
}
|
38
modules/ppcp-blocks/webpack.config.js
Normal file
38
modules/ppcp-blocks/webpack.config.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
const path = require('path');
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
const DependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );
|
||||
|
||||
module.exports = {
|
||||
devtool: isProduction ? 'source-map' : 'eval-source-map',
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
target: 'web',
|
||||
plugins: [ new DependencyExtractionWebpackPlugin() ],
|
||||
entry: {
|
||||
'checkout-block': path.resolve('./resources/js/checkout-block.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'}
|
||||
]
|
||||
}]
|
||||
}
|
||||
};
|
2233
modules/ppcp-blocks/yarn.lock
Normal file
2233
modules/ppcp-blocks/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1081,8 +1081,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
if ( is_cart() ) {
|
||||
$context = 'cart';
|
||||
}
|
||||
// TODO: refactor.
|
||||
if ( is_checkout() && ! $this->is_paypal_continuation() || did_action( 'woocommerce_blocks_checkout_enqueue_data' ) ) {
|
||||
if ( is_checkout() && ! $this->is_paypal_continuation() || has_block( 'woocommerce/checkout' ) ) {
|
||||
$context = 'checkout';
|
||||
}
|
||||
if ( is_checkout_pay_page() ) {
|
||||
|
|
|
@ -382,6 +382,9 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
$funding_source
|
||||
);
|
||||
|
||||
$action = in_array( $this->parsed_request_data['context'], array( 'checkout', 'express' ), true ) ?
|
||||
ApplicationContext::USER_ACTION_PAY_NOW : ApplicationContext::USER_ACTION_CONTINUE;
|
||||
|
||||
if ( 'card' === $funding_source ) {
|
||||
if ( CardBillingMode::MINIMAL_INPUT === $this->card_billing_data_mode ) {
|
||||
if ( ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS === $shipping_preference ) {
|
||||
|
@ -407,7 +410,9 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
$shipping_preference,
|
||||
$payer,
|
||||
null,
|
||||
$this->payment_method()
|
||||
$this->payment_method(),
|
||||
'',
|
||||
$action
|
||||
);
|
||||
} catch ( PayPalApiException $exception ) {
|
||||
// Looks like currently there is no proper way to validate the shipping address for PayPal,
|
||||
|
|
|
@ -162,8 +162,13 @@ class OrderProcessor {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function process( WC_Order $wc_order ): bool {
|
||||
public function process( \WC_Order $wc_order ): bool {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
$order_id = $wc_order->get_meta( PayPalGateway::ORDER_ID_META_KEY ) ?: wc_clean( wp_unslash( $_POST['paypal_order_id'] ?? '' ) );
|
||||
$order = $this->session_handler->order();
|
||||
if ( ! $order && is_string( $order_id ) ) {
|
||||
$order = $this->order_endpoint->order( $order_id );
|
||||
}
|
||||
if ( ! $order ) {
|
||||
$order_id = $wc_order->get_meta( PayPalGateway::ORDER_ID_META_KEY );
|
||||
if ( ! $order_id ) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"scripts": {
|
||||
"postinstall": "run-s install:modules:* && run-s build:modules",
|
||||
|
||||
"install:modules:ppcp-blocks": "cd modules/ppcp-blocks && yarn install",
|
||||
"install:modules:ppcp-button": "cd modules/ppcp-button && yarn install",
|
||||
"install:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn install",
|
||||
"install:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn install",
|
||||
|
@ -17,6 +18,7 @@
|
|||
"install:modules:ppcp-compat": "cd modules/ppcp-compat && yarn install",
|
||||
"install:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn install",
|
||||
|
||||
"build:modules:ppcp-blocks": "cd modules/ppcp-blocks && yarn run build",
|
||||
"build:modules:ppcp-button": "cd modules/ppcp-button && yarn run build",
|
||||
"build:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run build",
|
||||
"build:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn run build",
|
||||
|
@ -27,6 +29,7 @@
|
|||
"build:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn run build",
|
||||
"build:modules": "run-p build:modules:*",
|
||||
|
||||
"watch:modules:ppcp-blocks": "cd modules/ppcp-blocks && yarn run watch",
|
||||
"watch:modules:ppcp-button": "cd modules/ppcp-button && yarn run watch",
|
||||
"watch:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run watch",
|
||||
"watch:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn run watch",
|
||||
|
|
|
@ -52,4 +52,5 @@
|
|||
<exclude-pattern>*/vendor/*</exclude-pattern>
|
||||
<exclude-pattern>./tests/*</exclude-pattern>
|
||||
<exclude-pattern>*/resources/*</exclude-pattern>
|
||||
<exclude-pattern>*.asset.php</exclude-pattern>
|
||||
</ruleset>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
<stubs>
|
||||
<file name=".psalm/stubs.php"/>
|
||||
<file name=".psalm/wcblocks.php"/>
|
||||
<file name=".psalm/wcs.php"/>
|
||||
<file name=".psalm/gzd.php"/>
|
||||
<file name="vendor/php-stubs/wordpress-stubs/wordpress-stubs.php"/>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue