Add express checkout block (wip)

This commit is contained in:
Alex P 2022-12-20 16:04:11 +02:00
parent 0bf18d67c5
commit ea3e5bbeb6
No known key found for this signature in database
GPG key ID: 54487A734A204D71
22 changed files with 3199 additions and 25 deletions

370
.psalm/wcblocks.php Normal file
View 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
View file

@ -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",

View file

@ -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;

View 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
View file

@ -0,0 +1,3 @@
node_modules
assets/js
assets/css

View 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
}

View file

@ -0,0 +1,12 @@
<?php
/**
* The blocks module extensions.
*
* @package WooCommerce\PayPalCommerce\Blocks
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Blocks;
return array();

View 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();
};

View 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"
}
}

View 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;
}

View 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'],
},
});

View 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' )
);
},
);

View 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() {
}
}

View 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(),
);
}
}

View 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'}
]
}]
}
};

File diff suppressed because it is too large Load diff

View file

@ -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() ) {

View file

@ -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,

View file

@ -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 ) {

View file

@ -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",

View file

@ -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>

View file

@ -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"/>