mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
Merge branch 'trunk'
# Conflicts: # modules/ppcp-button/resources/js/modules/OnApproveHandler/onApproveForContinue.js
This commit is contained in:
commit
010f5fbdf1
101 changed files with 10063 additions and 2015 deletions
|
@ -1,7 +1,11 @@
|
|||
{
|
||||
"extends": [ "plugin:@wordpress/eslint-plugin/recommended" ],
|
||||
"env": {
|
||||
"browser": true
|
||||
},
|
||||
"globals": {
|
||||
"wc": true
|
||||
"wc": true,
|
||||
"jQuery": "readonly"
|
||||
},
|
||||
"rules": {
|
||||
"no-console": ["error", { "allow": ["warn", "error"] }]
|
||||
|
|
20
.psalm/wc-bookings.php
Normal file
20
.psalm/wc-bookings.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Validate and create a new booking manually.
|
||||
*
|
||||
* @version 1.10.7
|
||||
* @see WC_Booking::new_booking() for available $new_booking_data args
|
||||
* @param int $product_id you are booking
|
||||
* @param array $new_booking_data
|
||||
* @param string $status
|
||||
* @param bool $exact If false, the function will look for the next available block after your start date if the date is unavailable.
|
||||
* @return mixed WC_Booking object on success or false on fail
|
||||
*/
|
||||
function create_wc_booking( $product_id, $new_booking_data = array(), $status = 'confirmed', $exact = false ) {}
|
||||
|
||||
/**
|
||||
* Returns true if the product is a booking product, false if not
|
||||
* @return bool
|
||||
*/
|
||||
function is_wc_booking_product( $product ) {}
|
|
@ -88,5 +88,12 @@ return function ( string $root_dir ): iterable {
|
|||
$modules[] = ( require "$modules_dir/ppcp-axo/module.php" )();
|
||||
}
|
||||
|
||||
if ( apply_filters(
|
||||
'woocommerce.feature-flags.woocommerce_paypal_payments.local_apms_enabled',
|
||||
getenv( 'PCP_LOCAL_APMS_ENABLED' ) === '1'
|
||||
) ) {
|
||||
$modules[] = ( require "$modules_dir/ppcp-local-alternative-payment-methods/module.php" )();
|
||||
}
|
||||
|
||||
return $modules;
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\ClientCredentials;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\SdkClientToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\UserIdToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentMethodTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\CardAuthenticationResult;
|
||||
|
@ -240,6 +241,13 @@ return array(
|
|||
$bn_code
|
||||
);
|
||||
},
|
||||
'api.endpoint.orders' => static function ( ContainerInterface $container ): Orders {
|
||||
return new Orders(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.billing-agreements' => static function ( ContainerInterface $container ): BillingAgreementsEndpoint {
|
||||
return new BillingAgreementsEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
|
@ -1444,7 +1452,6 @@ return array(
|
|||
'CN' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array(),
|
||||
),
|
||||
'CY' => array(
|
||||
'mastercard' => array(),
|
||||
|
|
108
modules/ppcp-api-client/src/Endpoint/Orders.php
Normal file
108
modules/ppcp-api-client/src/Endpoint/Orders.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
/**
|
||||
* Orders API endpoints.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Endpoint
|
||||
* @link https://developer.paypal.com/docs/api/orders/v2/ Orders API documentation.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class Orders
|
||||
*/
|
||||
class Orders {
|
||||
|
||||
use RequestTrait;
|
||||
|
||||
/**
|
||||
* The host.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* The bearer.
|
||||
*
|
||||
* @var Bearer
|
||||
*/
|
||||
private $bearer;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Orders constructor.
|
||||
*
|
||||
* @param string $host The host.
|
||||
* @param Bearer $bearer The bearer.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
string $host,
|
||||
Bearer $bearer,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->host = $host;
|
||||
$this->bearer = $bearer;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PayPal order.
|
||||
*
|
||||
* @param array $request_body The request body.
|
||||
* @param array $headers The request headers.
|
||||
* @return array
|
||||
* @throws RuntimeException If something went wrong with the request.
|
||||
* @throws PayPalApiException If something went wrong with the PayPal API request.
|
||||
*/
|
||||
public function create( array $request_body, array $headers = array() ): array {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/checkout/orders';
|
||||
|
||||
$default_headers = array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'PayPal-Request-Id' => uniqid( 'ppcp-', true ),
|
||||
);
|
||||
$headers = array_merge(
|
||||
$default_headers,
|
||||
$headers
|
||||
);
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => $headers,
|
||||
'body' => wp_json_encode( $request_body ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( $response instanceof WP_Error ) {
|
||||
throw new RuntimeException( $response->get_error_message() );
|
||||
}
|
||||
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( $status_code !== 200 ) {
|
||||
throw new PayPalApiException(
|
||||
json_decode( $response['body'] ),
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
|
@ -269,7 +269,7 @@ return array(
|
|||
'classes' => array( 'ppcp-field-indent' ),
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'pay',
|
||||
'default' => 'plain',
|
||||
'options' => PropertiesDictionary::button_types(),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'dcc',
|
||||
|
|
|
@ -52,3 +52,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ppc-button-ppcp-applepay {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* global ApplePaySession */
|
||||
/* global PayPalCommerceGateway */
|
||||
|
||||
import ContextHandlerFactory from './Context/ContextHandlerFactory';
|
||||
import { createAppleErrors } from './Helper/applePayError';
|
||||
import { setVisible } from '../../../ppcp-button/resources/js/modules/Helper/Hiding';
|
||||
|
@ -7,18 +10,95 @@ import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler
|
|||
import widgetBuilder from '../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder';
|
||||
import { apmButtonsInit } from '../../../ppcp-button/resources/js/modules/Helper/ApmButtons';
|
||||
|
||||
class ApplepayButton {
|
||||
constructor( context, externalHandler, buttonConfig, ppcpConfig ) {
|
||||
apmButtonsInit( ppcpConfig );
|
||||
/**
|
||||
* Plugin-specific styling.
|
||||
*
|
||||
* Note that most properties of this object do not apply to the Apple Pay button.
|
||||
*
|
||||
* @typedef {Object} PPCPStyle
|
||||
* @property {string} shape - Outline shape.
|
||||
* @property {?number} height - Button height in pixel.
|
||||
*/
|
||||
|
||||
this.isInitialized = false;
|
||||
/**
|
||||
* Style options that are defined by the Apple Pay SDK and are required to render the button.
|
||||
*
|
||||
* @typedef {Object} ApplePayStyle
|
||||
* @property {string} type - Defines the button label.
|
||||
* @property {string} color - Button color
|
||||
* @property {string} lang - The locale; an empty string will apply the user-agent's language.
|
||||
*/
|
||||
|
||||
/**
|
||||
* List of valid context values that the button can have.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const CONTEXT = {
|
||||
Product: 'product',
|
||||
Cart: 'cart',
|
||||
Checkout: 'checkout',
|
||||
PayNow: 'pay-now',
|
||||
MiniCart: 'mini-cart',
|
||||
BlockCart: 'cart-block',
|
||||
BlockCheckout: 'checkout-block',
|
||||
Preview: 'preview',
|
||||
|
||||
// Block editor contexts.
|
||||
Blocks: [ 'cart-block', 'checkout-block' ],
|
||||
|
||||
// Custom gateway contexts.
|
||||
Gateways: [ 'checkout', 'pay-now' ],
|
||||
};
|
||||
|
||||
/**
|
||||
* A payment button for Apple Pay.
|
||||
*
|
||||
* On a single page, multiple Apple Pay buttons can be displayed, which also means multiple
|
||||
* ApplePayButton instances exist. A typical case is on the product page, where one Apple Pay button
|
||||
* is located inside the minicart-popup, and another pay-now button is in the product context.
|
||||
*/
|
||||
class ApplePayButton {
|
||||
/**
|
||||
* Whether the payment button is initialized.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
#isInitialized = false;
|
||||
|
||||
#wrapperId = '';
|
||||
#ppcpButtonWrapperId = '';
|
||||
|
||||
/**
|
||||
* Context describes the button's location on the website and what details it submits.
|
||||
*
|
||||
* @type {''|'product'|'cart'|'checkout'|'pay-now'|'mini-cart'|'cart-block'|'checkout-block'|'preview'}
|
||||
*/
|
||||
context = '';
|
||||
|
||||
externalHandler = null;
|
||||
buttonConfig = null;
|
||||
ppcpConfig = null;
|
||||
paymentsClient = null;
|
||||
formData = null;
|
||||
contextHandler = null;
|
||||
updatedContactInfo = [];
|
||||
selectedShippingMethod = [];
|
||||
|
||||
/**
|
||||
* Stores initialization data sent to the button.
|
||||
*/
|
||||
initialPaymentRequest = null;
|
||||
|
||||
constructor( context, externalHandler, buttonConfig, ppcpConfig ) {
|
||||
this._initDebug( !! buttonConfig?.is_debug );
|
||||
|
||||
apmButtonsInit( ppcpConfig );
|
||||
|
||||
this.context = context;
|
||||
this.externalHandler = externalHandler;
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
this.paymentsClient = null;
|
||||
this.formData = null;
|
||||
|
||||
this.contextHandler = ContextHandlerFactory.create(
|
||||
this.context,
|
||||
|
@ -26,36 +106,226 @@ class ApplepayButton {
|
|||
this.ppcpConfig
|
||||
);
|
||||
|
||||
this.updatedContactInfo = [];
|
||||
this.selectedShippingMethod = [];
|
||||
this.nonce =
|
||||
document.getElementById( 'woocommerce-process-checkout-nonce' )
|
||||
?.value || buttonConfig.nonce;
|
||||
|
||||
// Stores initialization data sent to the button.
|
||||
this.initialPaymentRequest = null;
|
||||
|
||||
// Default eligibility status.
|
||||
this.isEligible = true;
|
||||
|
||||
this.log = function () {
|
||||
if ( this.buttonConfig.is_debug ) {
|
||||
//console.log('[ApplePayButton]', ...arguments);
|
||||
}
|
||||
};
|
||||
|
||||
this.refreshContextData();
|
||||
}
|
||||
|
||||
/**
|
||||
* NOOP log function to avoid errors when debugging is disabled.
|
||||
*/
|
||||
log() {}
|
||||
|
||||
/**
|
||||
* Enables debugging tools, when the button's is_debug flag is set.
|
||||
*
|
||||
* @param {boolean} enableDebugging If debugging features should be enabled for this instance.
|
||||
* @private
|
||||
*/
|
||||
_initDebug( enableDebugging ) {
|
||||
if ( ! enableDebugging || this.#isInitialized ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug helpers
|
||||
jQuery( document ).on( 'ppcp-applepay-debug', () => {
|
||||
console.log( 'ApplePayButton', this.context, this );
|
||||
} );
|
||||
document.ppcpApplepayButtons = document.ppcpApplepayButtons || {};
|
||||
document.ppcpApplepayButtons[ this.context ] = this;
|
||||
|
||||
this.log = ( ...args ) => {
|
||||
console.log( `[ApplePayButton | ${ this.context }]`, ...args );
|
||||
};
|
||||
|
||||
jQuery( document ).on( 'ppcp-applepay-debug', () => {
|
||||
this.log( this );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* The nonce for ajax requests.
|
||||
*
|
||||
* @return {string} The nonce value
|
||||
*/
|
||||
get nonce() {
|
||||
const input = document.getElementById(
|
||||
'woocommerce-process-checkout-nonce'
|
||||
);
|
||||
|
||||
return input?.value || this.buttonConfig.nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current page qualifies to use the Apple Pay button.
|
||||
*
|
||||
* In admin, the button is always eligible, to display an accurate preview.
|
||||
* On front-end, PayPal's response decides if customers can use Apple Pay.
|
||||
*
|
||||
* @return {boolean} True, if the button can be displayed.
|
||||
*/
|
||||
get isEligible() {
|
||||
if ( ! this.#isInitialized ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( CONTEXT.Preview === this.context ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the ApplePaySession is available and accepts payments
|
||||
* This check is required when using Apple Pay SDK v1; canMakePayments() returns false
|
||||
* if the current device is not liked to iCloud or the Apple Wallet is not available
|
||||
* for a different reason.
|
||||
*/
|
||||
try {
|
||||
if ( ! window.ApplePaySession?.canMakePayments() ) {
|
||||
return false;
|
||||
}
|
||||
} catch ( error ) {
|
||||
console.warn( error );
|
||||
return false;
|
||||
}
|
||||
|
||||
return !! this.applePayConfig.isEligible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current payment button should be rendered as a stand-alone gateway.
|
||||
* The return value `false` usually means, that the payment button is bundled with all available
|
||||
* payment buttons.
|
||||
*
|
||||
* The decision depends on the button context (placement) and the plugin settings.
|
||||
*
|
||||
* @return {boolean} True, if the current button represents a stand-alone gateway.
|
||||
*/
|
||||
get isSeparateGateway() {
|
||||
return (
|
||||
this.buttonConfig.is_wc_gateway_enabled &&
|
||||
CONTEXT.Gateways.includes( this.context )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapper ID for the current button context.
|
||||
* The ID varies for the MiniCart context.
|
||||
*
|
||||
* @return {string} The wrapper-element's ID (without the `#` prefix).
|
||||
*/
|
||||
get wrapperId() {
|
||||
if ( ! this.#wrapperId ) {
|
||||
let id;
|
||||
|
||||
if ( CONTEXT.MiniCart === this.context ) {
|
||||
id = this.buttonConfig.button.mini_cart_wrapper;
|
||||
} else if ( this.isSeparateGateway ) {
|
||||
id = 'ppc-button-ppcp-applepay';
|
||||
} else {
|
||||
id = this.buttonConfig.button.wrapper;
|
||||
}
|
||||
|
||||
this.#wrapperId = id.replace( /^#/, '' );
|
||||
}
|
||||
|
||||
return this.#wrapperId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapper ID for the ppcpButton
|
||||
*
|
||||
* @return {string} The wrapper-element's ID (without the `#` prefix).
|
||||
*/
|
||||
get ppcpButtonWrapperId() {
|
||||
if ( ! this.#ppcpButtonWrapperId ) {
|
||||
let id;
|
||||
|
||||
if ( CONTEXT.MiniCart === this.context ) {
|
||||
id = this.ppcpConfig.button.mini_cart_wrapper;
|
||||
} else if ( CONTEXT.Blocks.includes( this.context ) ) {
|
||||
id = '#express-payment-method-ppcp-gateway-paypal';
|
||||
} else {
|
||||
id = this.ppcpConfig.button.wrapper;
|
||||
}
|
||||
|
||||
this.#ppcpButtonWrapperId = id.replace( /^#/, '' );
|
||||
}
|
||||
|
||||
return this.#ppcpButtonWrapperId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context-relevant PPCP style object.
|
||||
* The style for the MiniCart context can be different.
|
||||
*
|
||||
* The PPCP style are custom style options, that are provided by this plugin.
|
||||
*
|
||||
* @return {PPCPStyle} The style object.
|
||||
*/
|
||||
get ppcpStyle() {
|
||||
if ( CONTEXT.MiniCart === this.context ) {
|
||||
return this.ppcpConfig.button.mini_cart_style;
|
||||
}
|
||||
|
||||
return this.ppcpConfig.button.style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default style options that are propagated to and rendered by the Apple Pay button.
|
||||
*
|
||||
* These styles are the official style options provided by the Apple Pay SDK.
|
||||
*
|
||||
* @return {ApplePayStyle} The style object.
|
||||
*/
|
||||
get buttonStyle() {
|
||||
return {
|
||||
type: this.buttonConfig.button.type,
|
||||
lang: this.buttonConfig.button.lang,
|
||||
color: this.buttonConfig.button.color,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML element that wraps the current button
|
||||
*
|
||||
* @return {HTMLElement|null} The wrapper element, or null.
|
||||
*/
|
||||
get wrapperElement() {
|
||||
return document.getElementById( this.wrapperId );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of HTMLElements that belong to the payment button.
|
||||
*
|
||||
* @return {HTMLElement[]} List of payment button wrapper elements.
|
||||
*/
|
||||
get allElements() {
|
||||
const selectors = [];
|
||||
|
||||
// Payment button (Pay now, smart button block)
|
||||
selectors.push( `#${ this.wrapperId }` );
|
||||
|
||||
// Block Checkout: Express checkout button.
|
||||
if ( CONTEXT.Blocks.includes( this.context ) ) {
|
||||
selectors.push( '#express-payment-method-ppcp-applepay' );
|
||||
}
|
||||
|
||||
// Classic Checkout: Apple Pay gateway.
|
||||
if ( CONTEXT.Gateways.includes( this.context ) ) {
|
||||
selectors.push( '.wc_payment_method.payment_method_ppcp-applepay' );
|
||||
}
|
||||
|
||||
this.log( 'Wrapper Elements:', selectors );
|
||||
return /** @type {HTMLElement[]} */ selectors.flatMap( ( selector ) =>
|
||||
Array.from( document.querySelectorAll( selector ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the main button-wrapper is present in the current DOM.
|
||||
*
|
||||
* @return {boolean} True, if the button context (wrapper element) is found.
|
||||
*/
|
||||
get isPresent() {
|
||||
return this.wrapperElement instanceof HTMLElement;
|
||||
}
|
||||
|
||||
init( config ) {
|
||||
if ( this.isInitialized ) {
|
||||
if ( this.#isInitialized ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -63,41 +333,35 @@ class ApplepayButton {
|
|||
return;
|
||||
}
|
||||
|
||||
this.log( 'Init', this.context );
|
||||
this.log( 'Init' );
|
||||
this.initEventHandlers();
|
||||
this.isInitialized = true;
|
||||
|
||||
this.#isInitialized = true;
|
||||
this.applePayConfig = config;
|
||||
this.isEligible =
|
||||
( this.applePayConfig.isEligible && window.ApplePaySession ) ||
|
||||
this.buttonConfig.is_admin;
|
||||
|
||||
if ( this.isEligible ) {
|
||||
this.fetchTransactionInfo().then( () => {
|
||||
this.addButton();
|
||||
const id_minicart =
|
||||
'#apple-' + this.buttonConfig.button.mini_cart_wrapper;
|
||||
const id = '#apple-' + this.buttonConfig.button.wrapper;
|
||||
|
||||
if ( this.context === 'mini-cart' ) {
|
||||
document
|
||||
.querySelector( id_minicart )
|
||||
?.addEventListener( 'click', ( evt ) => {
|
||||
evt.preventDefault();
|
||||
this.onButtonClick();
|
||||
} );
|
||||
} else {
|
||||
document
|
||||
.querySelector( id )
|
||||
?.addEventListener( 'click', ( evt ) => {
|
||||
evt.preventDefault();
|
||||
this.onButtonClick();
|
||||
} );
|
||||
}
|
||||
} );
|
||||
if ( ! this.isEligible ) {
|
||||
this.hide();
|
||||
} else {
|
||||
jQuery( '#' + this.buttonConfig.button.wrapper ).hide();
|
||||
jQuery( '#' + this.buttonConfig.button.mini_cart_wrapper ).hide();
|
||||
jQuery( '#express-payment-method-ppcp-applepay' ).hide();
|
||||
// Bail if the button wrapper is not present; handles mini-cart logic on checkout page.
|
||||
if ( ! this.isPresent ) {
|
||||
this.log( 'Abort init (no wrapper found)' );
|
||||
return;
|
||||
}
|
||||
|
||||
this.show();
|
||||
|
||||
this.fetchTransactionInfo().then( () => {
|
||||
const button = this.addButton();
|
||||
|
||||
if ( ! button ) {
|
||||
return;
|
||||
}
|
||||
|
||||
button.addEventListener( 'click', ( evt ) => {
|
||||
evt.preventDefault();
|
||||
this.onButtonClick();
|
||||
} );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,49 +370,51 @@ class ApplepayButton {
|
|||
return;
|
||||
}
|
||||
|
||||
this.isInitialized = false;
|
||||
this.#isInitialized = false;
|
||||
this.init( this.applePayConfig );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides all wrappers that belong to this ApplePayButton instance.
|
||||
*/
|
||||
hide() {
|
||||
this.log( 'Hide button' );
|
||||
this.allElements.forEach( ( element ) => {
|
||||
element.style.display = 'none';
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures all wrapper elements of this ApplePayButton instance are visible.
|
||||
*/
|
||||
show() {
|
||||
this.log( 'Show button' );
|
||||
if ( ! this.isPresent ) {
|
||||
this.log( '!! Cannot show button, wrapper is not present' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Classic Checkout/PayNow: Make the Apple Pay gateway visible after page load.
|
||||
document
|
||||
.querySelectorAll( 'style#ppcp-hide-apple-pay' )
|
||||
.forEach( ( el ) => el.remove() );
|
||||
|
||||
this.allElements.forEach( ( element ) => {
|
||||
element.style.display = '';
|
||||
} );
|
||||
}
|
||||
|
||||
async fetchTransactionInfo() {
|
||||
this.transactionInfo = await this.contextHandler.transactionInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns configurations relative to this button context.
|
||||
*/
|
||||
contextConfig() {
|
||||
const config = {
|
||||
wrapper: this.buttonConfig.button.wrapper,
|
||||
ppcpStyle: this.ppcpConfig.button.style,
|
||||
buttonStyle: this.buttonConfig.button.style,
|
||||
ppcpButtonWrapper: this.ppcpConfig.button.wrapper,
|
||||
};
|
||||
|
||||
if ( this.context === 'mini-cart' ) {
|
||||
config.wrapper = this.buttonConfig.button.mini_cart_wrapper;
|
||||
config.ppcpStyle = this.ppcpConfig.button.mini_cart_style;
|
||||
config.buttonStyle = this.buttonConfig.button.mini_cart_style;
|
||||
config.ppcpButtonWrapper = this.ppcpConfig.button.mini_cart_wrapper;
|
||||
}
|
||||
|
||||
if (
|
||||
[ 'cart-block', 'checkout-block' ].indexOf( this.context ) !== -1
|
||||
) {
|
||||
config.ppcpButtonWrapper =
|
||||
'#express-payment-method-ppcp-gateway-paypal';
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
initEventHandlers() {
|
||||
const { wrapper, ppcpButtonWrapper } = this.contextConfig();
|
||||
const wrapper_id = '#' + wrapper;
|
||||
const ppcpButtonWrapper = `#${ this.ppcpButtonWrapperId }`;
|
||||
const wrapperId = `#${ this.wrapperId }`;
|
||||
|
||||
if ( wrapper_id === ppcpButtonWrapper ) {
|
||||
if ( wrapperId === ppcpButtonWrapper ) {
|
||||
throw new Error(
|
||||
`[ApplePayButton] "wrapper" and "ppcpButtonWrapper" values must differ to avoid infinite loop. Current value: "${ wrapper_id }"`
|
||||
`[ApplePayButton] "wrapper" and "ppcpButtonWrapper" values must differ to avoid infinite loop. Current value: "${ wrapperId }"`
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -158,9 +424,9 @@ class ApplepayButton {
|
|||
}
|
||||
|
||||
const $ppcpButtonWrapper = jQuery( ppcpButtonWrapper );
|
||||
setVisible( wrapper_id, $ppcpButtonWrapper.is( ':visible' ) );
|
||||
setVisible( wrapperId, $ppcpButtonWrapper.is( ':visible' ) );
|
||||
setEnabled(
|
||||
wrapper_id,
|
||||
wrapperId,
|
||||
! $ppcpButtonWrapper.hasClass( 'ppcp-disabled' )
|
||||
);
|
||||
};
|
||||
|
@ -178,8 +444,9 @@ class ApplepayButton {
|
|||
}
|
||||
|
||||
/**
|
||||
* Starts an ApplePay session.
|
||||
* @param paymentRequest
|
||||
* Starts an Apple Pay session.
|
||||
*
|
||||
* @param {Object} paymentRequest The payment request object.
|
||||
*/
|
||||
applePaySession( paymentRequest ) {
|
||||
this.log( 'applePaySession', paymentRequest );
|
||||
|
@ -192,6 +459,7 @@ class ApplepayButton {
|
|||
session.onshippingcontactselected =
|
||||
this.onShippingContactSelected( session );
|
||||
}
|
||||
|
||||
session.onvalidatemerchant = this.onValidateMerchant( session );
|
||||
session.onpaymentauthorized = this.onPaymentAuthorized( session );
|
||||
return session;
|
||||
|
@ -199,32 +467,38 @@ class ApplepayButton {
|
|||
|
||||
/**
|
||||
* Adds an Apple Pay purchase button.
|
||||
*
|
||||
* @return {HTMLElement|null} The newly created `<apple-pay-button>` element. Null on failure.
|
||||
*/
|
||||
addButton() {
|
||||
this.log( 'addButton', this.context );
|
||||
this.log( 'addButton' );
|
||||
|
||||
const { wrapper, ppcpStyle } = this.contextConfig();
|
||||
const wrapper = this.wrapperElement;
|
||||
const style = this.buttonStyle;
|
||||
const id = 'apple-' + this.wrapperId;
|
||||
|
||||
const appleContainer = document.getElementById( wrapper );
|
||||
const type = this.buttonConfig.button.type;
|
||||
const language = this.buttonConfig.button.lang;
|
||||
const color = this.buttonConfig.button.color;
|
||||
const id = 'apple-' + wrapper;
|
||||
|
||||
if ( appleContainer ) {
|
||||
appleContainer.innerHTML = `<apple-pay-button id="${ id }" buttonstyle="${ color }" type="${ type }" locale="${ language }">`;
|
||||
if ( ! wrapper ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const $wrapper = jQuery( '#' + wrapper );
|
||||
$wrapper.addClass( 'ppcp-button-' + ppcpStyle.shape );
|
||||
const ppcpStyle = this.ppcpStyle;
|
||||
|
||||
wrapper.innerHTML = `<apple-pay-button id='${ id }' buttonstyle='${ style.color }' type='${ style.type }' locale='${ style.lang }' />`;
|
||||
wrapper.classList.add(
|
||||
`ppcp-button-${ ppcpStyle.shape }`,
|
||||
'ppcp-button-apm',
|
||||
'ppcp-button-applepay'
|
||||
);
|
||||
|
||||
if ( ppcpStyle.height ) {
|
||||
$wrapper.css(
|
||||
wrapper.style.setProperty(
|
||||
'--apple-pay-button-height',
|
||||
`${ ppcpStyle.height }px`
|
||||
);
|
||||
$wrapper.css( 'height', `${ ppcpStyle.height }px` );
|
||||
wrapper.style.height = `${ ppcpStyle.height }px`;
|
||||
}
|
||||
|
||||
return wrapper.querySelector( 'apple-pay-button' );
|
||||
}
|
||||
|
||||
//------------------------
|
||||
|
@ -235,19 +509,21 @@ class ApplepayButton {
|
|||
* Show Apple Pay payment sheet when Apple Pay payment button is clicked
|
||||
*/
|
||||
async onButtonClick() {
|
||||
this.log( 'onButtonClick', this.context );
|
||||
this.log( 'onButtonClick' );
|
||||
|
||||
const paymentRequest = this.paymentRequest();
|
||||
|
||||
window.ppcpFundingSource = 'apple_pay'; // Do this on another place like on create order endpoint handler.
|
||||
// Do this on another place like on create order endpoint handler.
|
||||
window.ppcpFundingSource = 'apple_pay';
|
||||
|
||||
// Trigger woocommerce validation if we are in the checkout page.
|
||||
if ( this.context === 'checkout' ) {
|
||||
if ( CONTEXT.Checkout === this.context ) {
|
||||
const checkoutFormSelector = 'form.woocommerce-checkout';
|
||||
const errorHandler = new ErrorHandler(
|
||||
PayPalCommerceGateway.labels.error.generic,
|
||||
document.querySelector( '.woocommerce-notices-wrapper' )
|
||||
);
|
||||
|
||||
try {
|
||||
const formData = new FormData(
|
||||
document.querySelector( checkoutFormSelector )
|
||||
|
@ -269,6 +545,7 @@ class ApplepayButton {
|
|||
PayPalCommerceGateway.ajax.validate_checkout.nonce
|
||||
)
|
||||
: null;
|
||||
|
||||
if ( formValidator ) {
|
||||
try {
|
||||
const errors = await formValidator.validate(
|
||||
|
@ -296,13 +573,13 @@ class ApplepayButton {
|
|||
/**
|
||||
* If the button should show the shipping fields.
|
||||
*
|
||||
* @return {false|*}
|
||||
* @return {boolean} True, if shipping fields should be captured by ApplePay.
|
||||
*/
|
||||
shouldRequireShippingInButton() {
|
||||
return (
|
||||
this.contextHandler.shippingAllowed() &&
|
||||
this.buttonConfig.product.needShipping &&
|
||||
( this.context !== 'checkout' ||
|
||||
( CONTEXT.Checkout !== this.context ||
|
||||
this.shouldUpdateButtonWithFormData() )
|
||||
);
|
||||
}
|
||||
|
@ -310,10 +587,10 @@ class ApplepayButton {
|
|||
/**
|
||||
* If the button should be updated with the form addresses.
|
||||
*
|
||||
* @return {boolean}
|
||||
* @return {boolean} True, when Apple Pay data should be submitted to WooCommerce.
|
||||
*/
|
||||
shouldUpdateButtonWithFormData() {
|
||||
if ( this.context !== 'checkout' ) {
|
||||
if ( CONTEXT.Checkout !== this.context ) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
|
@ -323,29 +600,28 @@ class ApplepayButton {
|
|||
}
|
||||
|
||||
/**
|
||||
* Indicates how payment completion should be handled if with the context handler default actions.
|
||||
* Or with ApplePay module specific completion.
|
||||
* Indicates how payment completion should be handled if with the context handler default
|
||||
* actions. Or with Apple Pay module specific completion.
|
||||
*
|
||||
* @return {boolean}
|
||||
* @return {boolean} True, when the Apple Pay data should be submitted to WooCommerce.
|
||||
*/
|
||||
shouldCompletePaymentWithContextHandler() {
|
||||
// Data already handled, ex: PayNow
|
||||
if ( ! this.contextHandler.shippingAllowed() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use WC form data mode in Checkout.
|
||||
if (
|
||||
this.context === 'checkout' &&
|
||||
return (
|
||||
CONTEXT.Checkout === this.context &&
|
||||
! this.shouldUpdateButtonWithFormData()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates ApplePay paymentRequest with form data.
|
||||
* @param paymentRequest
|
||||
* Updates Apple Pay paymentRequest with form data.
|
||||
*
|
||||
* @param {Object} paymentRequest Object to extend with form data.
|
||||
*/
|
||||
updateRequestDataWithForm( paymentRequest ) {
|
||||
if ( ! this.shouldUpdateButtonWithFormData() ) {
|
||||
|
@ -358,8 +634,9 @@ class ApplepayButton {
|
|||
);
|
||||
|
||||
// Add custom data.
|
||||
// "applicationData" is originating a "PayPalApplePayError: An internal server error has occurred" on paypal.Applepay().confirmOrder().
|
||||
// paymentRequest.applicationData = this.fillApplicationData(this.formData);
|
||||
// "applicationData" is originating a "PayPalApplePayError: An internal server error has
|
||||
// occurred" on paypal.Applepay().confirmOrder(). paymentRequest.applicationData =
|
||||
// this.fillApplicationData(this.formData);
|
||||
|
||||
if ( ! this.shouldRequireShippingInButton() ) {
|
||||
return;
|
||||
|
@ -425,7 +702,8 @@ class ApplepayButton {
|
|||
'email',
|
||||
'phone',
|
||||
],
|
||||
requiredBillingContactFields: [ 'postalAddress' ], // ApplePay does not implement billing email and phone fields.
|
||||
requiredBillingContactFields: [ 'postalAddress' ], // ApplePay does not implement billing
|
||||
// email and phone fields.
|
||||
};
|
||||
|
||||
if ( ! this.shouldRequireShippingInButton() ) {
|
||||
|
@ -453,14 +731,11 @@ class ApplepayButton {
|
|||
}
|
||||
|
||||
refreshContextData() {
|
||||
switch ( this.context ) {
|
||||
case 'product':
|
||||
// Refresh product data that makes the price change.
|
||||
this.productQuantity =
|
||||
document.querySelector( 'input.qty' )?.value;
|
||||
this.products = this.contextHandler.products();
|
||||
this.log( 'Products updated', this.products );
|
||||
break;
|
||||
if ( CONTEXT.Product === this.context ) {
|
||||
// Refresh product data that makes the price change.
|
||||
this.productQuantity = document.querySelector( 'input.qty' )?.value;
|
||||
this.products = this.contextHandler.products();
|
||||
this.log( 'Products updated', this.products );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,8 +743,36 @@ class ApplepayButton {
|
|||
// Payment process
|
||||
//------------------------
|
||||
|
||||
/**
|
||||
* Make ajax call to change the verification-status of the current domain.
|
||||
*
|
||||
* @param {boolean} isValid
|
||||
*/
|
||||
adminValidation( isValid ) {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const ignored = fetch( this.buttonConfig.ajax_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: new URLSearchParams( {
|
||||
action: 'ppcp_validate',
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
validation: isValid,
|
||||
} ).toString(),
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an event handler that Apple Pay calls when displaying the payment sheet.
|
||||
*
|
||||
* @see https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession/1778021-onvalidatemerchant
|
||||
*
|
||||
* @param {Object} session The ApplePaySession object.
|
||||
*
|
||||
* @return {(function(*): void)|*} Callback that runs after the merchant validation
|
||||
*/
|
||||
onValidateMerchant( session ) {
|
||||
this.log( 'onvalidatemerchant', this.buttonConfig.ajax_url );
|
||||
return ( applePayValidateMerchantEvent ) => {
|
||||
this.log( 'onvalidatemerchant call' );
|
||||
|
||||
|
@ -479,34 +782,15 @@ class ApplepayButton {
|
|||
validationUrl: applePayValidateMerchantEvent.validationURL,
|
||||
} )
|
||||
.then( ( validateResult ) => {
|
||||
this.log( 'onvalidatemerchant ok' );
|
||||
session.completeMerchantValidation(
|
||||
validateResult.merchantSession
|
||||
);
|
||||
//call backend to update validation to true
|
||||
jQuery.ajax( {
|
||||
url: this.buttonConfig.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'ppcp_validate',
|
||||
validation: true,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
},
|
||||
} );
|
||||
|
||||
this.adminValidation( true );
|
||||
} )
|
||||
.catch( ( validateError ) => {
|
||||
this.log( 'onvalidatemerchant error', validateError );
|
||||
console.error( validateError );
|
||||
//call backend to update validation to false
|
||||
jQuery.ajax( {
|
||||
url: this.buttonConfig.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'ppcp_validate',
|
||||
validation: false,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
},
|
||||
} );
|
||||
this.adminValidation( false );
|
||||
this.log( 'onvalidatemerchant session abort' );
|
||||
session.abort();
|
||||
} );
|
||||
|
@ -515,14 +799,14 @@ class ApplepayButton {
|
|||
|
||||
onShippingMethodSelected( session ) {
|
||||
this.log( 'onshippingmethodselected', this.buttonConfig.ajax_url );
|
||||
const ajax_url = this.buttonConfig.ajax_url;
|
||||
const ajaxUrl = this.buttonConfig.ajax_url;
|
||||
return ( event ) => {
|
||||
this.log( 'onshippingmethodselected call' );
|
||||
|
||||
const data = this.getShippingMethodData( event );
|
||||
|
||||
jQuery.ajax( {
|
||||
url: ajax_url,
|
||||
url: ajaxUrl,
|
||||
method: 'POST',
|
||||
data,
|
||||
success: (
|
||||
|
@ -537,7 +821,8 @@ class ApplepayButton {
|
|||
}
|
||||
this.selectedShippingMethod = event.shippingMethod;
|
||||
|
||||
// Sort the response shipping methods, so that the selected shipping method is the first one.
|
||||
// Sort the response shipping methods, so that the selected shipping method is
|
||||
// the first one.
|
||||
response.newShippingMethods =
|
||||
response.newShippingMethods.sort( ( a, b ) => {
|
||||
if (
|
||||
|
@ -565,7 +850,7 @@ class ApplepayButton {
|
|||
onShippingContactSelected( session ) {
|
||||
this.log( 'onshippingcontactselected', this.buttonConfig.ajax_url );
|
||||
|
||||
const ajax_url = this.buttonConfig.ajax_url;
|
||||
const ajaxUrl = this.buttonConfig.ajax_url;
|
||||
|
||||
return ( event ) => {
|
||||
this.log( 'onshippingcontactselected call' );
|
||||
|
@ -573,7 +858,7 @@ class ApplepayButton {
|
|||
const data = this.getShippingContactData( event );
|
||||
|
||||
jQuery.ajax( {
|
||||
url: ajax_url,
|
||||
url: ajaxUrl,
|
||||
method: 'POST',
|
||||
data,
|
||||
success: (
|
||||
|
@ -603,15 +888,15 @@ class ApplepayButton {
|
|||
}
|
||||
|
||||
getShippingContactData( event ) {
|
||||
const product_id = this.buttonConfig.product.id;
|
||||
const productId = this.buttonConfig.product.id;
|
||||
|
||||
this.refreshContextData();
|
||||
|
||||
switch ( this.context ) {
|
||||
case 'product':
|
||||
case CONTEXT.Product:
|
||||
return {
|
||||
action: 'ppcp_update_shipping_contact',
|
||||
product_id,
|
||||
product_id: productId,
|
||||
products: JSON.stringify( this.products ),
|
||||
caller_page: 'productDetail',
|
||||
product_quantity: this.productQuantity,
|
||||
|
@ -619,11 +904,12 @@ class ApplepayButton {
|
|||
need_shipping: this.shouldRequireShippingInButton(),
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
};
|
||||
case 'cart':
|
||||
case 'checkout':
|
||||
case 'cart-block':
|
||||
case 'checkout-block':
|
||||
case 'mini-cart':
|
||||
|
||||
case CONTEXT.Cart:
|
||||
case CONTEXT.Checkout:
|
||||
case CONTEXT.BlockCart:
|
||||
case CONTEXT.BlockCheckout:
|
||||
case CONTEXT.MiniCart:
|
||||
return {
|
||||
action: 'ppcp_update_shipping_contact',
|
||||
simplified_contact: event.shippingContact,
|
||||
|
@ -635,12 +921,12 @@ class ApplepayButton {
|
|||
}
|
||||
|
||||
getShippingMethodData( event ) {
|
||||
const product_id = this.buttonConfig.product.id;
|
||||
const productId = this.buttonConfig.product.id;
|
||||
|
||||
this.refreshContextData();
|
||||
|
||||
switch ( this.context ) {
|
||||
case 'product':
|
||||
case CONTEXT.Product:
|
||||
return {
|
||||
action: 'ppcp_update_shipping_method',
|
||||
shipping_method: event.shippingMethod,
|
||||
|
@ -650,17 +936,18 @@ class ApplepayButton {
|
|||
? this.updatedContactInfo
|
||||
: this.initialPaymentRequest?.shippingContact ??
|
||||
this.initialPaymentRequest?.billingContact,
|
||||
product_id,
|
||||
product_id: productId,
|
||||
products: JSON.stringify( this.products ),
|
||||
caller_page: 'productDetail',
|
||||
product_quantity: this.productQuantity,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
};
|
||||
case 'cart':
|
||||
case 'checkout':
|
||||
case 'cart-block':
|
||||
case 'checkout-block':
|
||||
case 'mini-cart':
|
||||
|
||||
case CONTEXT.Cart:
|
||||
case CONTEXT.Checkout:
|
||||
case CONTEXT.BlockCart:
|
||||
case CONTEXT.BlockCheckout:
|
||||
case CONTEXT.MiniCart:
|
||||
return {
|
||||
action: 'ppcp_update_shipping_method',
|
||||
shipping_method: event.shippingMethod,
|
||||
|
@ -681,9 +968,6 @@ class ApplepayButton {
|
|||
return async ( event ) => {
|
||||
this.log( 'onpaymentauthorized call' );
|
||||
|
||||
function form() {
|
||||
return document.querySelector( 'form.cart' );
|
||||
}
|
||||
const processInWooAndCapture = async ( data ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
try {
|
||||
|
@ -698,7 +982,7 @@ class ApplepayButton {
|
|||
( this.initialPaymentRequest.shippingMethods ||
|
||||
[] )[ 0 ];
|
||||
|
||||
const request_data = {
|
||||
const requestData = {
|
||||
action: 'ppcp_create_order',
|
||||
caller_page: this.context,
|
||||
product_id: this.buttonConfig.product.id ?? null,
|
||||
|
@ -723,7 +1007,7 @@ class ApplepayButton {
|
|||
jQuery.ajax( {
|
||||
url: this.buttonConfig.ajax_url,
|
||||
method: 'POST',
|
||||
data: request_data,
|
||||
data: requestData,
|
||||
complete: ( jqXHR, textStatus ) => {
|
||||
this.log( 'onpaymentauthorized complete' );
|
||||
},
|
||||
|
@ -785,7 +1069,8 @@ class ApplepayButton {
|
|||
if (
|
||||
this.shouldCompletePaymentWithContextHandler()
|
||||
) {
|
||||
// No shipping, expect immediate capture, ex: PayNow, Checkout with form data.
|
||||
// No shipping, expect immediate capture, ex: PayNow, Checkout with
|
||||
// form data.
|
||||
|
||||
let approveFailed = false;
|
||||
await this.contextHandler.approveOrder(
|
||||
|
@ -960,4 +1245,4 @@ class ApplepayButton {
|
|||
}
|
||||
}
|
||||
|
||||
export default ApplepayButton;
|
||||
export default ApplePayButton;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import buttonModuleWatcher from '../../../ppcp-button/resources/js/modules/ButtonModuleWatcher';
|
||||
import ApplepayButton from './ApplepayButton';
|
||||
/* global paypal */
|
||||
|
||||
class ApplepayManager {
|
||||
import buttonModuleWatcher from '../../../ppcp-button/resources/js/modules/ButtonModuleWatcher';
|
||||
import ApplePayButton from './ApplepayButton';
|
||||
|
||||
class ApplePayManager {
|
||||
constructor( buttonConfig, ppcpConfig ) {
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
|
@ -9,7 +11,7 @@ class ApplepayManager {
|
|||
this.buttons = [];
|
||||
|
||||
buttonModuleWatcher.watchContextBootstrap( ( bootstrap ) => {
|
||||
const button = new ApplepayButton(
|
||||
const button = new ApplePayButton(
|
||||
bootstrap.context,
|
||||
bootstrap.handler,
|
||||
buttonConfig,
|
||||
|
@ -40,8 +42,7 @@ class ApplepayManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets ApplePay configuration of the PayPal merchant.
|
||||
* @return {Promise<null>}
|
||||
* Gets Apple Pay configuration of the PayPal merchant.
|
||||
*/
|
||||
async config() {
|
||||
this.ApplePayConfig = await paypal.Applepay().config();
|
||||
|
@ -49,4 +50,4 @@ class ApplepayManager {
|
|||
}
|
||||
}
|
||||
|
||||
export default ApplepayManager;
|
||||
export default ApplePayManager;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import ApplepayButton from './ApplepayButton';
|
||||
/* global paypal */
|
||||
|
||||
class ApplepayManagerBlockEditor {
|
||||
import ApplePayButton from './ApplepayButton';
|
||||
|
||||
class ApplePayManagerBlockEditor {
|
||||
constructor( buttonConfig, ppcpConfig ) {
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
|
@ -17,7 +19,7 @@ class ApplepayManagerBlockEditor {
|
|||
try {
|
||||
this.applePayConfig = await paypal.Applepay().config();
|
||||
|
||||
const button = new ApplepayButton(
|
||||
const button = new ApplePayButton(
|
||||
this.ppcpConfig.context,
|
||||
null,
|
||||
this.buttonConfig,
|
||||
|
@ -31,4 +33,4 @@ class ApplepayManagerBlockEditor {
|
|||
}
|
||||
}
|
||||
|
||||
export default ApplepayManagerBlockEditor;
|
||||
export default ApplePayManagerBlockEditor;
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import BaseHandler from './BaseHandler';
|
||||
|
||||
class PreviewHandler extends BaseHandler {
|
||||
constructor( buttonConfig, ppcpConfig, externalHandler ) {
|
||||
super( buttonConfig, ppcpConfig, externalHandler );
|
||||
}
|
||||
|
||||
transactionInfo() {
|
||||
// We need to return something as ApplePay button initialization expects valid data.
|
||||
return {
|
||||
|
@ -19,7 +15,7 @@ class PreviewHandler extends BaseHandler {
|
|||
throw new Error( 'Create order fail. This is just a preview.' );
|
||||
}
|
||||
|
||||
approveOrder( data, actions ) {
|
||||
approveOrder() {
|
||||
throw new Error( 'Approve order fail. This is just a preview.' );
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export const buttonID = 'applepay-container';
|
||||
export const buttonID = 'ppc-button-applepay-container';
|
||||
export const endpoints = {
|
||||
validation: '_apple_pay_validation',
|
||||
createOrderCart: '_apple_pay_create_order_cart',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import ApplepayButton from './ApplepayButton';
|
||||
import ApplePayButton from './ApplepayButton';
|
||||
import PreviewButton from '../../../ppcp-button/resources/js/modules/Renderer/PreviewButton';
|
||||
import PreviewButtonManager from '../../../ppcp-button/resources/js/modules/Renderer/PreviewButtonManager';
|
||||
|
||||
|
@ -86,7 +86,7 @@ class ApplePayPreviewButton extends PreviewButton {
|
|||
}
|
||||
|
||||
createButton( buttonConfig ) {
|
||||
const button = new ApplepayButton(
|
||||
const button = new ApplePayButton(
|
||||
'preview',
|
||||
null,
|
||||
buttonConfig,
|
||||
|
|
|
@ -4,8 +4,8 @@ import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Help
|
|||
import { cartHasSubscriptionProducts } from '../../../ppcp-blocks/resources/js/Helper/Subscription';
|
||||
import { loadCustomScript } from '@paypal/paypal-js';
|
||||
import CheckoutHandler from './Context/CheckoutHandler';
|
||||
import ApplepayManager from './ApplepayManager';
|
||||
import ApplepayManagerBlockEditor from './ApplepayManagerBlockEditor';
|
||||
import ApplePayManager from './ApplepayManager';
|
||||
import ApplePayManagerBlockEditor from './ApplepayManagerBlockEditor';
|
||||
|
||||
const ppcpData = wc.wcSettings.getSetting( 'ppcp-gateway_data' );
|
||||
const ppcpConfig = ppcpData.scriptData;
|
||||
|
@ -24,8 +24,8 @@ const ApplePayComponent = ( props ) => {
|
|||
|
||||
const bootstrap = function () {
|
||||
const ManagerClass = props.isEditing
|
||||
? ApplepayManagerBlockEditor
|
||||
: ApplepayManager;
|
||||
? ApplePayManagerBlockEditor
|
||||
: ApplePayManager;
|
||||
const manager = new ManagerClass( buttonConfig, ppcpConfig );
|
||||
manager.init();
|
||||
};
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { loadCustomScript } from '@paypal/paypal-js';
|
||||
import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading';
|
||||
import ApplepayManager from './ApplepayManager';
|
||||
import ApplePayManager from './ApplepayManager';
|
||||
import { setupButtonEvents } from '../../../ppcp-button/resources/js/modules/Helper/ButtonRefreshHelper';
|
||||
|
||||
( function ( { buttonConfig, ppcpConfig, jQuery } ) {
|
||||
let manager;
|
||||
|
||||
const bootstrap = function () {
|
||||
manager = new ApplepayManager( buttonConfig, ppcpConfig );
|
||||
manager = new ApplePayManager( buttonConfig, ppcpConfig );
|
||||
manager.init();
|
||||
};
|
||||
|
||||
|
|
|
@ -299,5 +299,15 @@ return array(
|
|||
esc_html( $button_text )
|
||||
);
|
||||
},
|
||||
'applepay.wc-gateway' => static function ( ContainerInterface $container ): ApplePayGateway {
|
||||
return new ApplePayGateway(
|
||||
$container->get( 'wcgateway.order-processor' ),
|
||||
$container->get( 'api.factory.paypal-checkout-url' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'applepay.url' )
|
||||
);
|
||||
},
|
||||
|
||||
);
|
||||
|
|
231
modules/ppcp-applepay/src/ApplePayGateway.php
Normal file
231
modules/ppcp-applepay/src/ApplePayGateway.php
Normal file
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
/**
|
||||
* The Apple Pay Payment Gateway
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Applepay
|
||||
*/
|
||||
|
||||
declare( strict_types = 1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Applepay;
|
||||
|
||||
use Exception;
|
||||
use WC_Order;
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\ProcessPaymentTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\PayPalOrderMissingException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\Messages;
|
||||
|
||||
/**
|
||||
* Class ApplePayGateway
|
||||
*/
|
||||
class ApplePayGateway extends WC_Payment_Gateway {
|
||||
use ProcessPaymentTrait;
|
||||
|
||||
const ID = 'ppcp-applepay';
|
||||
|
||||
/**
|
||||
* The processor for orders.
|
||||
*
|
||||
* @var OrderProcessor
|
||||
*/
|
||||
protected $order_processor;
|
||||
|
||||
/**
|
||||
* The function return the PayPal checkout URL for the given order ID.
|
||||
*
|
||||
* @var callable(string):string
|
||||
*/
|
||||
private $paypal_checkout_url_factory;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* The Session Handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
protected $session_handler;
|
||||
|
||||
/**
|
||||
* The URL to the module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* ApplePayGateway constructor.
|
||||
*
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param callable(string):string $paypal_checkout_url_factory The function return the PayPal
|
||||
* checkout URL for the given order
|
||||
* ID.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction
|
||||
* view URL based on order.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param string $module_url The URL to the module.
|
||||
*/
|
||||
public function __construct(
|
||||
OrderProcessor $order_processor,
|
||||
callable $paypal_checkout_url_factory,
|
||||
RefundProcessor $refund_processor,
|
||||
TransactionUrlProvider $transaction_url_provider,
|
||||
SessionHandler $session_handler,
|
||||
string $module_url
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->method_title = __( 'Apple Pay (via PayPal) ', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'Display Apple Pay as a standalone payment option instead of bundling it with PayPal.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$this->title = $this->get_option( 'title', __( 'Apple Pay', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->module_url = $module_url;
|
||||
$this->icon = esc_url( $this->module_url ) . 'assets/images/applepay.png';
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
$this->order_processor = $order_processor;
|
||||
$this->paypal_checkout_url_factory = $paypal_checkout_url_factory;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->session_handler = $session_handler;
|
||||
|
||||
add_action(
|
||||
'woocommerce_update_options_payment_gateways_' . $this->id,
|
||||
array( $this, 'process_admin_options' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable Apple Pay', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable Apple Pay payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->title,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->description,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process payment for a WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) : array {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new GatewayGenericException( new Exception( 'WC order was not found.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_before_process_order', $wc_order );
|
||||
|
||||
try {
|
||||
try {
|
||||
$this->order_processor->process( $wc_order );
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_before_handle_payment_success', $wc_order );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalOrderMissingException $exc ) {
|
||||
$order = $this->order_processor->create_order( $wc_order );
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => ( $this->paypal_checkout_url_factory )( $order->id() ),
|
||||
);
|
||||
}
|
||||
} catch ( PayPalApiException $error ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
} catch ( Exception $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
* If the gateway declares 'refunds' support, this will allow it to refund.
|
||||
* a passed in amount.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
*
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) : bool {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, WC_Order::class ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return transaction url for this gateway and given order.
|
||||
*
|
||||
* @param WC_Order $order WC order to get transaction url by.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ) : string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Applepay;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Assets\ApplePayButton;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Assets\AppleProductStatus;
|
||||
|
@ -117,6 +118,48 @@ class ApplepayModule implements ModuleInterface {
|
|||
100,
|
||||
2
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_payment_gateways',
|
||||
/**
|
||||
* Param types removed to avoid third-party issues.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
static function ( $methods ) use ( $c ): array {
|
||||
if ( ! is_array( $methods ) ) {
|
||||
return $methods;
|
||||
}
|
||||
|
||||
$settings = $c->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
|
||||
if ( $settings->has( 'applepay_button_enabled' ) && $settings->get( 'applepay_button_enabled' ) ) {
|
||||
$applepay_gateway = $c->get( 'applepay.wc-gateway' );
|
||||
assert( $applepay_gateway instanceof WC_Payment_Gateway );
|
||||
|
||||
$methods[] = $applepay_gateway;
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_review_order_after_submit',
|
||||
function () {
|
||||
// Wrapper ID: #ppc-button-ppcp-applepay.
|
||||
echo '<div id="ppc-button-' . esc_attr( ApplePayGateway::ID ) . '"></div>';
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_pay_order_after_submit',
|
||||
function () {
|
||||
// Wrapper ID: #ppc-button-ppcp-applepay.
|
||||
echo '<div id="ppc-button-' . esc_attr( ApplePayGateway::ID ) . '"></div>';
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -306,7 +349,7 @@ class ApplepayModule implements ModuleInterface {
|
|||
* @param bool $is_sandbox The environment for this merchant.
|
||||
* @return string
|
||||
*/
|
||||
public function validation_string( bool $is_sandbox ) {
|
||||
public function validation_string( bool $is_sandbox ) : string {
|
||||
$sandbox_string = $this->sandbox_validation_string();
|
||||
$live_string = $this->live_validation_string();
|
||||
return $is_sandbox ? $sandbox_string : $live_string;
|
||||
|
|
|
@ -20,12 +20,13 @@ use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\RequestHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
|
||||
/**
|
||||
* Class ApplePayButton
|
||||
*/
|
||||
class ApplePayButton implements ButtonInterface {
|
||||
use RequestHandlerTrait;
|
||||
use RequestHandlerTrait, ContextTrait;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
|
@ -340,7 +341,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
}
|
||||
$response = $this->response_templates->apple_formatted_response( $payment_details );
|
||||
$this->response_templates->response_success( $response );
|
||||
} catch ( \Exception $e ) {
|
||||
} catch ( Exception $e ) {
|
||||
$this->response_templates->response_with_data_errors(
|
||||
array(
|
||||
array(
|
||||
|
@ -382,7 +383,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
}
|
||||
$response = $this->response_templates->apple_formatted_response( $payment_details );
|
||||
$this->response_templates->response_success( $response );
|
||||
} catch ( \Exception $e ) {
|
||||
} catch ( Exception $e ) {
|
||||
$this->response_templates->response_with_data_errors(
|
||||
array(
|
||||
array(
|
||||
|
@ -399,7 +400,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
* On error returns an array of errors to be handled by the script
|
||||
* On success returns the new order data
|
||||
*
|
||||
* @throws \Exception When validation fails.
|
||||
* @throws Exception When validation fails.
|
||||
*/
|
||||
public function create_wc_order(): void {
|
||||
$applepay_request_data_object = $this->applepay_data_object_http();
|
||||
|
@ -420,15 +421,18 @@ class ApplePayButton implements ButtonInterface {
|
|||
$applepay_request_data_object->order_data( $context );
|
||||
|
||||
$this->update_posted_data( $applepay_request_data_object );
|
||||
|
||||
if ( $context === 'product' ) {
|
||||
$cart_item_key = $this->prepare_cart( $applepay_request_data_object );
|
||||
$cart = WC()->cart;
|
||||
$address = $applepay_request_data_object->shipping_address();
|
||||
|
||||
$this->calculate_totals_single_product(
|
||||
$cart,
|
||||
$address,
|
||||
$applepay_request_data_object->shipping_method()
|
||||
);
|
||||
|
||||
if ( ! $cart_item_key ) {
|
||||
$this->response_templates->response_with_data_errors(
|
||||
array(
|
||||
|
@ -438,19 +442,16 @@ class ApplePayButton implements ButtonInterface {
|
|||
),
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
add_filter(
|
||||
'woocommerce_payment_successful_result',
|
||||
function ( array $result ) use ( $cart, $cart_item_key ) : array {
|
||||
if ( ! is_string( $cart_item_key ) ) {
|
||||
} else {
|
||||
add_filter(
|
||||
'woocommerce_payment_successful_result',
|
||||
function ( array $result ) use ( $cart, $cart_item_key ) : array {
|
||||
$this->clear_current_cart( $cart, $cart_item_key );
|
||||
$this->reload_cart( $cart );
|
||||
return $result;
|
||||
}
|
||||
$this->clear_current_cart( $cart, $cart_item_key );
|
||||
$this->reload_cart( $cart );
|
||||
return $result;
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
WC()->checkout()->process_checkout();
|
||||
|
@ -460,17 +461,20 @@ class ApplePayButton implements ButtonInterface {
|
|||
/**
|
||||
* Checks if the nonce in the data object is valid
|
||||
*
|
||||
* @return bool|int
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_nonce_valid(): bool {
|
||||
$nonce = filter_input( INPUT_POST, 'woocommerce-process-checkout-nonce', FILTER_SANITIZE_SPECIAL_CHARS );
|
||||
if ( ! $nonce ) {
|
||||
return false;
|
||||
}
|
||||
return wp_verify_nonce(
|
||||
|
||||
// Return value 1 indicates "valid nonce, generated in past 12 hours".
|
||||
// Return value 2 also indicated valid nonce, but older than 12 hours.
|
||||
return 1 === wp_verify_nonce(
|
||||
$nonce,
|
||||
'woocommerce-process_checkout'
|
||||
) === 1;
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -511,7 +515,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
$address,
|
||||
$applepay_request_data_object->shipping_method()
|
||||
);
|
||||
if ( is_string( $cart_item_key ) ) {
|
||||
if ( $cart_item_key ) {
|
||||
$this->clear_current_cart( $cart, $cart_item_key );
|
||||
$this->reload_cart( $cart );
|
||||
}
|
||||
|
@ -819,9 +823,9 @@ class ApplePayButton implements ButtonInterface {
|
|||
/**
|
||||
* Removes the old cart, saves it, and creates a new one
|
||||
*
|
||||
* @throws Exception If it cannot be added to cart.
|
||||
* @param ApplePayDataObjectHttp $applepay_request_data_object The request data object.
|
||||
* @return bool | string The cart item key after adding to the new cart.
|
||||
* @throws \Exception If it cannot be added to cart.
|
||||
* @return string The cart item key after adding to the new cart.
|
||||
*/
|
||||
public function prepare_cart( ApplePayDataObjectHttp $applepay_request_data_object ): string {
|
||||
$this->save_old_cart();
|
||||
|
@ -838,7 +842,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
);
|
||||
|
||||
$this->cart_products->add_products( array( $product ) );
|
||||
return $this->cart_products->cart_item_keys()[0];
|
||||
return $this->cart_products->cart_item_keys()[0] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -949,6 +953,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
$render_placeholder,
|
||||
function () {
|
||||
$this->applepay_button();
|
||||
$this->hide_gateway_until_eligible();
|
||||
},
|
||||
21
|
||||
);
|
||||
|
@ -961,6 +966,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
$render_placeholder,
|
||||
function () {
|
||||
$this->applepay_button();
|
||||
$this->hide_gateway_until_eligible();
|
||||
},
|
||||
21
|
||||
);
|
||||
|
@ -973,7 +979,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
add_action(
|
||||
$render_placeholder,
|
||||
function () {
|
||||
echo '<span id="applepay-container-minicart" class="ppcp-button-apm ppcp-button-applepay ppcp-button-minicart"></span>';
|
||||
echo '<span id="ppc-button-applepay-container-minicart" class="ppcp-button-apm ppcp-button-applepay ppcp-button-minicart"></span>';
|
||||
},
|
||||
21
|
||||
);
|
||||
|
@ -981,24 +987,29 @@ class ApplePayButton implements ButtonInterface {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ApplePay button markup
|
||||
*/
|
||||
protected function applepay_button(): void {
|
||||
?>
|
||||
<div id="applepay-container" class="ppcp-button-apm ppcp-button-applepay">
|
||||
<div id="ppc-button-applepay-container" class="ppcp-button-apm ppcp-button-applepay">
|
||||
<?php wp_nonce_field( 'woocommerce-process_checkout', 'woocommerce-process-checkout-nonce' ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the module should load the script.
|
||||
* Outputs an inline CSS style that hides the Apple Pay gateway (on Classic Checkout).
|
||||
* The style is removed by `ApplepayButton.js` once the eligibility of the payment method
|
||||
* is confirmed.
|
||||
*
|
||||
* @return bool
|
||||
* @return void
|
||||
*/
|
||||
public function should_load_script(): bool {
|
||||
return true;
|
||||
protected function hide_gateway_until_eligible(): void {
|
||||
?>
|
||||
<style id="ppcp-hide-apple-pay">.wc_payment_method.payment_method_ppcp-applepay{display:none}</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
* @package WooCommerce\PayPalCommerce\Applepay
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
declare( strict_types = 1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Applepay\Assets;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\Applepay\ApplePayGateway;
|
||||
use WC_Product;
|
||||
|
||||
/**
|
||||
* Class DataToAppleButtonScripts
|
||||
|
@ -33,7 +35,7 @@ class DataToAppleButtonScripts {
|
|||
/**
|
||||
* DataToAppleButtonScripts constructor.
|
||||
*
|
||||
* @param string $sdk_url The URL to the SDK.
|
||||
* @param string $sdk_url The URL to the SDK.
|
||||
* @param Settings $settings The settings.
|
||||
*/
|
||||
public function __construct( string $sdk_url, Settings $settings ) {
|
||||
|
@ -45,57 +47,92 @@ class DataToAppleButtonScripts {
|
|||
* Sets the appropriate data to send to ApplePay script
|
||||
* Data differs between product page and cart page
|
||||
*
|
||||
* @param bool $is_block Whether the button is in a block or not.
|
||||
* @return array
|
||||
* @throws NotFoundException When the setting is not found.
|
||||
*/
|
||||
public function apple_pay_script_data( bool $is_block = false ): array {
|
||||
$base_location = wc_get_base_location();
|
||||
$shop_country_code = $base_location['country'];
|
||||
$currency_code = get_woocommerce_currency();
|
||||
$total_label = get_bloginfo( 'name' );
|
||||
public function apple_pay_script_data() : array {
|
||||
if ( is_product() ) {
|
||||
return $this->data_for_product_page(
|
||||
$shop_country_code,
|
||||
$currency_code,
|
||||
$total_label
|
||||
);
|
||||
return $this->data_for_product_page();
|
||||
}
|
||||
|
||||
return $this->data_for_cart_page(
|
||||
$shop_country_code,
|
||||
$currency_code,
|
||||
$total_label
|
||||
);
|
||||
return $this->data_for_cart_page();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appropriate admin data to send to ApplePay script
|
||||
*
|
||||
* @return array
|
||||
* @throws NotFoundException When the setting is not found.
|
||||
*/
|
||||
public function apple_pay_script_data_for_admin() : array {
|
||||
return $this->data_for_admin_page();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full config array for the Apple Pay integration with default values.
|
||||
*
|
||||
* @param array $product - Optional. Product details for the payment button.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_apple_pay_data( array $product = array() ) : array {
|
||||
// true: Use Apple Pay as distinct gateway.
|
||||
// false: integrate it with the smart buttons.
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
$is_wc_gateway_enabled = isset( $available_gateways[ ApplePayGateway::ID ] );
|
||||
|
||||
// use_wc: Use WC checkout data
|
||||
// use_applepay: Use data provided by Apple Pay.
|
||||
$checkout_data_mode = $this->settings->has( 'applepay_checkout_data_mode' )
|
||||
? $this->settings->get( 'applepay_checkout_data_mode' )
|
||||
: PropertiesDictionary::BILLING_DATA_MODE_DEFAULT;
|
||||
|
||||
// Store country, currency and name.
|
||||
$base_location = wc_get_base_location();
|
||||
$shop_country_code = $base_location['country'];
|
||||
$currency_code = get_woocommerce_currency();
|
||||
$total_label = get_bloginfo( 'name' );
|
||||
|
||||
return $this->data_for_admin_page(
|
||||
$shop_country_code,
|
||||
$currency_code,
|
||||
$total_label
|
||||
// Button layout (label, color, language).
|
||||
$type = $this->settings->has( 'applepay_button_type' ) ? $this->settings->get( 'applepay_button_type' ) : '';
|
||||
$color = $this->settings->has( 'applepay_button_color' ) ? $this->settings->get( 'applepay_button_color' ) : '';
|
||||
$lang = $this->settings->has( 'applepay_button_language' ) ? $this->settings->get( 'applepay_button_language' ) : '';
|
||||
$lang = apply_filters( 'woocommerce_paypal_payments_applepay_button_language', $lang );
|
||||
$is_enabled = $this->settings->has( 'applepay_button_enabled' ) && $this->settings->get( 'applepay_button_enabled' );
|
||||
|
||||
return array(
|
||||
'sdk_url' => $this->sdk_url,
|
||||
'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG,
|
||||
'is_admin' => false,
|
||||
'is_enabled' => $is_enabled,
|
||||
'is_wc_gateway_enabled' => $is_wc_gateway_enabled,
|
||||
'preferences' => array(
|
||||
'checkout_data_mode' => $checkout_data_mode,
|
||||
),
|
||||
'button' => array(
|
||||
'wrapper' => 'ppc-button-applepay-container',
|
||||
'mini_cart_wrapper' => 'ppc-button-applepay-container-minicart',
|
||||
'type' => $type,
|
||||
'color' => $color,
|
||||
'lang' => $lang,
|
||||
),
|
||||
'product' => $product,
|
||||
'shop' => array(
|
||||
'countryCode' => $shop_country_code,
|
||||
'currencyCode' => $currency_code,
|
||||
'totalLabel' => $total_label,
|
||||
),
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'woocommerce-process_checkout' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the product needs shipping
|
||||
*
|
||||
* @param \WC_Product $product The product.
|
||||
* @param WC_Product $product Product to check.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function check_if_need_shipping( $product ) {
|
||||
protected function check_if_need_shipping( WC_Product $product ) : bool {
|
||||
if (
|
||||
! wc_shipping_enabled()
|
||||
|| 0 === wc_get_shipping_method_count(
|
||||
|
@ -104,30 +141,20 @@ class DataToAppleButtonScripts {
|
|||
) {
|
||||
return false;
|
||||
}
|
||||
$needs_shipping = false;
|
||||
|
||||
if ( $product->needs_shipping() ) {
|
||||
$needs_shipping = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return $needs_shipping;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the data for the product page.
|
||||
*
|
||||
* @param string $shop_country_code The shop country code.
|
||||
* @param string $currency_code The currency code.
|
||||
* @param string $total_label The label for the total amount.
|
||||
*
|
||||
* @return array
|
||||
* @throws NotFoundException When the setting is not found.
|
||||
*/
|
||||
protected function data_for_product_page(
|
||||
$shop_country_code,
|
||||
$currency_code,
|
||||
$total_label
|
||||
) {
|
||||
protected function data_for_product_page() : array {
|
||||
$product = wc_get_product( get_the_id() );
|
||||
if ( ! $product ) {
|
||||
return array();
|
||||
|
@ -136,146 +163,59 @@ class DataToAppleButtonScripts {
|
|||
if ( $product->get_type() === 'variable' || $product->get_type() === 'variable-subscription' ) {
|
||||
$is_variation = true;
|
||||
}
|
||||
|
||||
$product_need_shipping = $this->check_if_need_shipping( $product );
|
||||
$product_id = get_the_id();
|
||||
$product_price = $product->get_price();
|
||||
$product_stock = $product->get_stock_status();
|
||||
$type = $this->settings->has( 'applepay_button_type' ) ? $this->settings->get( 'applepay_button_type' ) : '';
|
||||
$color = $this->settings->has( 'applepay_button_color' ) ? $this->settings->get( 'applepay_button_color' ) : '';
|
||||
$lang = $this->settings->has( 'applepay_button_language' ) ? $this->settings->get( 'applepay_button_language' ) : '';
|
||||
$checkout_data_mode = $this->settings->has( 'applepay_checkout_data_mode' ) ? $this->settings->get( 'applepay_checkout_data_mode' ) : PropertiesDictionary::BILLING_DATA_MODE_DEFAULT;
|
||||
|
||||
return array(
|
||||
'sdk_url' => $this->sdk_url,
|
||||
'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false,
|
||||
'is_admin' => false,
|
||||
'preferences' => array(
|
||||
'checkout_data_mode' => $checkout_data_mode,
|
||||
),
|
||||
'button' => array(
|
||||
'wrapper' => 'applepay-container',
|
||||
'mini_cart_wrapper' => 'applepay-container-minicart',
|
||||
'type' => $type,
|
||||
'color' => $color,
|
||||
'lang' => $lang,
|
||||
),
|
||||
'product' => array(
|
||||
return $this->get_apple_pay_data(
|
||||
array(
|
||||
'needShipping' => $product_need_shipping,
|
||||
'id' => $product_id,
|
||||
'price' => $product_price,
|
||||
'isVariation' => $is_variation,
|
||||
'stock' => $product_stock,
|
||||
),
|
||||
'shop' => array(
|
||||
'countryCode' => $shop_country_code,
|
||||
'currencyCode' => $currency_code,
|
||||
'totalLabel' => $total_label,
|
||||
),
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'woocommerce-process_checkout' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the data for the cart page.
|
||||
*
|
||||
* @param string $shop_country_code The shop country code.
|
||||
* @param string $currency_code The currency code.
|
||||
* @param string $total_label The label for the total amount.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function data_for_cart_page(
|
||||
$shop_country_code,
|
||||
$currency_code,
|
||||
$total_label
|
||||
) {
|
||||
protected function data_for_cart_page() : array {
|
||||
$cart = WC()->cart;
|
||||
if ( ! $cart ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$type = $this->settings->has( 'applepay_button_type' ) ? $this->settings->get( 'applepay_button_type' ) : '';
|
||||
$color = $this->settings->has( 'applepay_button_color' ) ? $this->settings->get( 'applepay_button_color' ) : '';
|
||||
$lang = $this->settings->has( 'applepay_button_language' ) ? $this->settings->get( 'applepay_button_language' ) : '';
|
||||
$lang = apply_filters( 'woocommerce_paypal_payments_applepay_button_language', $lang );
|
||||
$checkout_data_mode = $this->settings->has( 'applepay_checkout_data_mode' ) ? $this->settings->get( 'applepay_checkout_data_mode' ) : PropertiesDictionary::BILLING_DATA_MODE_DEFAULT;
|
||||
|
||||
return array(
|
||||
'sdk_url' => $this->sdk_url,
|
||||
'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false,
|
||||
'is_admin' => false,
|
||||
'preferences' => array(
|
||||
'checkout_data_mode' => $checkout_data_mode,
|
||||
),
|
||||
'button' => array(
|
||||
'wrapper' => 'applepay-container',
|
||||
'mini_cart_wrapper' => 'applepay-container-minicart',
|
||||
'type' => $type,
|
||||
'color' => $color,
|
||||
'lang' => $lang,
|
||||
),
|
||||
'product' => array(
|
||||
return $this->get_apple_pay_data(
|
||||
array(
|
||||
'needShipping' => $cart->needs_shipping(),
|
||||
'subtotal' => $cart->get_subtotal(),
|
||||
),
|
||||
'shop' => array(
|
||||
'countryCode' => $shop_country_code,
|
||||
'currencyCode' => $currency_code,
|
||||
'totalLabel' => $total_label,
|
||||
),
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'woocommerce-process_checkout' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the data for the cart page.
|
||||
* Consider refactoring this method along with data_for_cart_page() and data_for_product_page() methods.
|
||||
*
|
||||
* @param string $shop_country_code The shop country code.
|
||||
* @param string $currency_code The currency code.
|
||||
* @param string $total_label The label for the total amount.
|
||||
* Consider refactoring this method along with data_for_cart_page() and data_for_product_page()
|
||||
* methods.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function data_for_admin_page(
|
||||
$shop_country_code,
|
||||
$currency_code,
|
||||
$total_label
|
||||
) {
|
||||
$type = $this->settings->has( 'applepay_button_type' ) ? $this->settings->get( 'applepay_button_type' ) : '';
|
||||
$color = $this->settings->has( 'applepay_button_color' ) ? $this->settings->get( 'applepay_button_color' ) : '';
|
||||
$lang = $this->settings->has( 'applepay_button_language' ) ? $this->settings->get( 'applepay_button_language' ) : '';
|
||||
$lang = apply_filters( 'woocommerce_paypal_payments_applepay_button_language', $lang );
|
||||
$checkout_data_mode = $this->settings->has( 'applepay_checkout_data_mode' ) ? $this->settings->get( 'applepay_checkout_data_mode' ) : PropertiesDictionary::BILLING_DATA_MODE_DEFAULT;
|
||||
$is_enabled = $this->settings->has( 'applepay_button_enabled' ) && $this->settings->get( 'applepay_button_enabled' );
|
||||
|
||||
return array(
|
||||
'sdk_url' => $this->sdk_url,
|
||||
'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG,
|
||||
'is_admin' => true,
|
||||
'is_enabled' => $is_enabled,
|
||||
'preferences' => array(
|
||||
'checkout_data_mode' => $checkout_data_mode,
|
||||
),
|
||||
'button' => array(
|
||||
'wrapper' => 'applepay-container',
|
||||
'mini_cart_wrapper' => 'applepay-container-minicart',
|
||||
'type' => $type,
|
||||
'color' => $color,
|
||||
'lang' => $lang,
|
||||
),
|
||||
'product' => array(
|
||||
protected function data_for_admin_page() : array {
|
||||
$data = $this->get_apple_pay_data(
|
||||
array(
|
||||
'needShipping' => false,
|
||||
'subtotal' => 0,
|
||||
),
|
||||
'shop' => array(
|
||||
'countryCode' => $shop_country_code,
|
||||
'currencyCode' => $currency_code,
|
||||
'totalLabel' => $total_label,
|
||||
),
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
)
|
||||
);
|
||||
|
||||
$data['is_admin'] = true;
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ return array(
|
|||
'title' => __( 'Require final confirmation on checkout', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => $label,
|
||||
'default' => false,
|
||||
'default' => true,
|
||||
'screens' => array( State::STATE_START, State::STATE_ONBOARDED ),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"Edge >= 14"
|
||||
],
|
||||
"dependencies": {
|
||||
"@paypal/react-paypal-js": "^8.3.0",
|
||||
"@paypal/react-paypal-js": "^8.5.0",
|
||||
"core-js": "^3.25.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0"
|
||||
|
|
|
@ -7,7 +7,12 @@ import {
|
|||
} from '@paypal/react-paypal-js';
|
||||
|
||||
import { CheckoutHandler } from './checkout-handler';
|
||||
import { createOrder, onApprove } from '../card-fields-config';
|
||||
import {
|
||||
createOrder,
|
||||
onApprove,
|
||||
createVaultSetupToken,
|
||||
onApproveSavePayment,
|
||||
} from '../card-fields-config';
|
||||
import { cartHasSubscriptionProducts } from '../Helper/Subscription';
|
||||
|
||||
export function CardFields( {
|
||||
|
@ -70,8 +75,21 @@ export function CardFields( {
|
|||
} }
|
||||
>
|
||||
<PayPalCardFieldsProvider
|
||||
createOrder={ createOrder }
|
||||
onApprove={ onApprove }
|
||||
createVaultSetupToken={
|
||||
config.scriptData.is_free_trial_cart
|
||||
? createVaultSetupToken
|
||||
: undefined
|
||||
}
|
||||
createOrder={
|
||||
config.scriptData.is_free_trial_cart
|
||||
? undefined
|
||||
: createOrder
|
||||
}
|
||||
onApprove={
|
||||
config.scriptData.is_free_trial_cart
|
||||
? onApproveSavePayment
|
||||
: onApprove
|
||||
}
|
||||
onError={ ( err ) => {
|
||||
console.error( err );
|
||||
} }
|
||||
|
|
|
@ -44,3 +44,61 @@ export async function onApprove( data ) {
|
|||
console.error( err );
|
||||
} );
|
||||
}
|
||||
|
||||
export async function createVaultSetupToken() {
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-credit-card-gateway_data' );
|
||||
|
||||
return fetch( config.scriptData.ajax.create_setup_token.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: config.scriptData.ajax.create_setup_token.nonce,
|
||||
payment_method: 'ppcp-credit-card-gateway',
|
||||
} ),
|
||||
} )
|
||||
.then( ( response ) => response.json() )
|
||||
.then( ( result ) => {
|
||||
console.log( result );
|
||||
return result.data.id;
|
||||
} )
|
||||
.catch( ( err ) => {
|
||||
console.error( err );
|
||||
} );
|
||||
}
|
||||
|
||||
export async function onApproveSavePayment( { vaultSetupToken } ) {
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-credit-card-gateway_data' );
|
||||
|
||||
let endpoint =
|
||||
config.scriptData.ajax.create_payment_token_for_guest.endpoint;
|
||||
let bodyContent = {
|
||||
nonce: config.scriptData.ajax.create_payment_token_for_guest.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
};
|
||||
|
||||
if ( config.scriptData.user.is_logged_in ) {
|
||||
endpoint = config.scriptData.ajax.create_payment_token.endpoint;
|
||||
|
||||
bodyContent = {
|
||||
nonce: config.scriptData.ajax.create_payment_token.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
is_free_trial_cart: config.scriptData.is_free_trial_cart,
|
||||
};
|
||||
}
|
||||
|
||||
const response = await fetch( endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( bodyContent ),
|
||||
} );
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.success !== true ) {
|
||||
console.error( result );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ const PayPalComponent = ( {
|
|||
throw new Error( config.scriptData.labels.error.generic );
|
||||
}
|
||||
|
||||
if ( ! shouldHandleShippingInPayPal() ) {
|
||||
if ( ! shouldskipFinalConfirmation() ) {
|
||||
location.href = getCheckoutRedirectUrl();
|
||||
} else {
|
||||
setGotoContinuationOnError( true );
|
||||
|
@ -318,7 +318,7 @@ const PayPalComponent = ( {
|
|||
throw new Error( config.scriptData.labels.error.generic );
|
||||
}
|
||||
|
||||
if ( ! shouldHandleShippingInPayPal() ) {
|
||||
if ( ! shouldskipFinalConfirmation() ) {
|
||||
location.href = getCheckoutRedirectUrl();
|
||||
} else {
|
||||
setGotoContinuationOnError( true );
|
||||
|
@ -364,16 +364,20 @@ const PayPalComponent = ( {
|
|||
};
|
||||
|
||||
const shouldHandleShippingInPayPal = () => {
|
||||
if ( config.finalReviewEnabled ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
window.ppcpFundingSource !== 'venmo' ||
|
||||
! config.scriptData.vaultingEnabled
|
||||
);
|
||||
return shouldskipFinalConfirmation() && config.needShipping
|
||||
};
|
||||
|
||||
const shouldskipFinalConfirmation = () => {
|
||||
if ( config.finalReviewEnabled ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
window.ppcpFundingSource !== 'venmo' ||
|
||||
! config.scriptData.vaultingEnabled
|
||||
);
|
||||
};
|
||||
|
||||
let handleShippingOptionsChange = null;
|
||||
let handleShippingAddressChange = null;
|
||||
let handleSubscriptionShippingOptionsChange = null;
|
||||
|
@ -544,7 +548,7 @@ const PayPalComponent = ( {
|
|||
if ( config.scriptData.continuation ) {
|
||||
return true;
|
||||
}
|
||||
if ( shouldHandleShippingInPayPal() ) {
|
||||
if ( shouldskipFinalConfirmation() ) {
|
||||
location.href = getCheckoutRedirectUrl();
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -13,6 +13,7 @@ use WooCommerce\PayPalCommerce\Blocks\Endpoint\GetPayPalOrderFromSession;
|
|||
use WooCommerce\PayPalCommerce\Blocks\Endpoint\UpdateShippingEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
use WC_Cart;
|
||||
|
||||
return array(
|
||||
'blocks.url' => static function ( ContainerInterface $container ): string {
|
||||
|
@ -27,6 +28,13 @@ return array(
|
|||
);
|
||||
},
|
||||
'blocks.method' => static function ( ContainerInterface $container ): PayPalPaymentMethod {
|
||||
/**
|
||||
* Cart instance; might be null, esp. in customizer or in Block Editor.
|
||||
*
|
||||
* @var null|WC_Cart $cart
|
||||
*/
|
||||
$cart = WC()->cart;
|
||||
|
||||
return new PayPalPaymentMethod(
|
||||
$container->get( 'blocks.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
|
@ -43,7 +51,8 @@ return array(
|
|||
$container->get( 'wcgateway.use-place-order-button' ),
|
||||
$container->get( 'wcgateway.place-order-button-text' ),
|
||||
$container->get( 'wcgateway.place-order-button-description' ),
|
||||
$container->get( 'wcgateway.all-funding-sources' )
|
||||
$container->get( 'wcgateway.all-funding-sources' ),
|
||||
$cart && $cart->needs_shipping()
|
||||
);
|
||||
},
|
||||
'blocks.advanced-card-method' => static function( ContainerInterface $container ): AdvancedCardPaymentMethod {
|
||||
|
|
|
@ -97,15 +97,6 @@ class UpdateShippingEndpoint implements EndpointInterface {
|
|||
$pu = $this->purchase_unit_factory->from_wc_cart( null, true );
|
||||
$pu_data = $pu->to_array();
|
||||
|
||||
if ( ! isset( $pu_data['shipping']['options'] ) ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'message' => 'No shipping methods.',
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: maybe should patch only if methods changed.
|
||||
// But it seems a bit difficult to detect,
|
||||
// e.g. ->order($id) may not have Shipping because we drop it when address or name are missing.
|
||||
|
|
|
@ -122,6 +122,13 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
*/
|
||||
private $all_funding_sources;
|
||||
|
||||
/**
|
||||
* Whether shipping details must be collected during checkout; i.e. paying for physical goods?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $need_shipping;
|
||||
|
||||
/**
|
||||
* Assets constructor.
|
||||
*
|
||||
|
@ -139,6 +146,7 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
* @param string $place_order_button_text The text for the standard "Place order" button.
|
||||
* @param string $place_order_button_description The text for additional "Place order" description.
|
||||
* @param array $all_funding_sources All existing funding sources for PayPal buttons.
|
||||
* @param bool $need_shipping Whether shipping details are required for the purchase.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
|
@ -154,7 +162,8 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
bool $use_place_order,
|
||||
string $place_order_button_text,
|
||||
string $place_order_button_description,
|
||||
array $all_funding_sources
|
||||
array $all_funding_sources,
|
||||
bool $need_shipping
|
||||
) {
|
||||
$this->name = PayPalGateway::ID;
|
||||
$this->module_url = $module_url;
|
||||
|
@ -171,6 +180,7 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
$this->place_order_button_text = $place_order_button_text;
|
||||
$this->place_order_button_description = $place_order_button_description;
|
||||
$this->all_funding_sources = $all_funding_sources;
|
||||
$this->need_shipping = $need_shipping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -254,6 +264,7 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
),
|
||||
),
|
||||
'scriptData' => $script_data,
|
||||
'needShipping' => $this->need_shipping,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1005,19 +1005,19 @@
|
|||
"@jridgewell/resolve-uri" "3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "1.4.14"
|
||||
|
||||
"@paypal/paypal-js@^8.0.5":
|
||||
version "8.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-8.0.5.tgz#77bc461b4d1e5a2c6f081269e3ef0b2e3331a68c"
|
||||
integrity sha512-yQNV7rOILeaVCNU4aVDRPqEnbIlzfxgQfFsxzsBuZW1ouqRD/4kYBWJDzczCiscSr2xOeA/Pkm7e3a9fRfnuMQ==
|
||||
"@paypal/paypal-js@^8.1.0":
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-8.1.0.tgz#4e7d10e0a0b4164985029cfdac748e5694d117e9"
|
||||
integrity sha512-f64bom5xYwmxyeKPJUFS/XpM0tXojQEgjRIADPqe1R9WmK+PFqL4SEkT85cGU0ZXLVx4EGbjwREHhqEOR+OstA==
|
||||
dependencies:
|
||||
promise-polyfill "^8.3.0"
|
||||
|
||||
"@paypal/react-paypal-js@^8.3.0":
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@paypal/react-paypal-js/-/react-paypal-js-8.3.0.tgz#a103080b752766b8ff59b8620887abf802e1a01b"
|
||||
integrity sha512-SX17d2h1CMNFGI+wtjb329AEDaBR8Ziy2LCV076eDcY1Q0MFKRkfQ/v0HOAvZtk3sJoydRmYez2pq47BRblwqQ==
|
||||
"@paypal/react-paypal-js@^8.5.0":
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@paypal/react-paypal-js/-/react-paypal-js-8.5.0.tgz#cf17483202c8fa7a33dae86798d50a102705f182"
|
||||
integrity sha512-YIAyLw4OiUoHHoUgXvibrBDdluzqnqVMGsJXyBcoOzlWHQIe5zhh8dgYezNNRXjXwy6t22YmPljjw7lr+eD9cw==
|
||||
dependencies:
|
||||
"@paypal/paypal-js" "^8.0.5"
|
||||
"@paypal/paypal-js" "^8.1.0"
|
||||
"@paypal/sdk-constants" "^1.0.122"
|
||||
|
||||
"@paypal/sdk-constants@^1.0.122":
|
||||
|
|
|
@ -7,6 +7,7 @@ import Renderer from './modules/Renderer/Renderer';
|
|||
import ErrorHandler from './modules/ErrorHandler';
|
||||
import HostedFieldsRenderer from './modules/Renderer/HostedFieldsRenderer';
|
||||
import CardFieldsRenderer from './modules/Renderer/CardFieldsRenderer';
|
||||
import CardFieldsFreeTrialRenderer from './modules/Renderer/CardFieldsFreeTrialRenderer';
|
||||
import MessageRenderer from './modules/Renderer/MessageRenderer';
|
||||
import Spinner from './modules/Helper/Spinner';
|
||||
import {
|
||||
|
@ -215,12 +216,23 @@ const bootstrap = () => {
|
|||
spinner
|
||||
);
|
||||
if ( typeof paypal.CardFields !== 'undefined' ) {
|
||||
creditCardRenderer = new CardFieldsRenderer(
|
||||
PayPalCommerceGateway,
|
||||
errorHandler,
|
||||
spinner,
|
||||
onCardFieldsBeforeSubmit
|
||||
);
|
||||
if (
|
||||
PayPalCommerceGateway.is_free_trial_cart &&
|
||||
PayPalCommerceGateway.user?.has_wc_card_payment_tokens !== true
|
||||
) {
|
||||
creditCardRenderer = new CardFieldsFreeTrialRenderer(
|
||||
PayPalCommerceGateway,
|
||||
errorHandler,
|
||||
spinner
|
||||
);
|
||||
} else {
|
||||
creditCardRenderer = new CardFieldsRenderer(
|
||||
PayPalCommerceGateway,
|
||||
errorHandler,
|
||||
spinner,
|
||||
onCardFieldsBeforeSubmit
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const renderer = new Renderer(
|
||||
|
|
|
@ -173,61 +173,6 @@ class CheckoutActionHandler {
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
addPaymentMethodConfiguration() {
|
||||
return {
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(
|
||||
this.config.ajax.create_setup_token.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.create_setup_token.nonce,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.data.id ) {
|
||||
return result.data.id;
|
||||
}
|
||||
|
||||
console.error( result );
|
||||
},
|
||||
onApprove: async ( { vaultSetupToken } ) => {
|
||||
const response = await fetch(
|
||||
this.config.ajax.create_payment_token_for_guest.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax
|
||||
.create_payment_token_for_guest.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.success === true ) {
|
||||
document.querySelector( '#place_order' ).click();
|
||||
return;
|
||||
}
|
||||
|
||||
console.error( result );
|
||||
},
|
||||
onError: ( error ) => {
|
||||
console.error( error );
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default CheckoutActionHandler;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* global PayPalCommerceGateway */
|
||||
|
||||
import CheckoutActionHandler from '../ActionHandler/CheckoutActionHandler';
|
||||
import { setVisible, setVisibleByClass } from '../Helper/Hiding';
|
||||
import {
|
||||
|
@ -7,6 +9,7 @@ import {
|
|||
PaymentMethods,
|
||||
} from '../Helper/CheckoutMethodState';
|
||||
import BootstrapHelper from '../Helper/BootstrapHelper';
|
||||
import { addPaymentMethodConfiguration } from '../../../../../ppcp-save-payment-methods/resources/js/Configuration';
|
||||
import {
|
||||
ButtonEvents,
|
||||
dispatchButtonEvent,
|
||||
|
@ -165,7 +168,7 @@ class CheckoutBootstap {
|
|||
PayPalCommerceGateway.vault_v3_enabled
|
||||
) {
|
||||
this.renderer.render(
|
||||
actionHandler.addPaymentMethodConfiguration(),
|
||||
addPaymentMethodConfiguration( PayPalCommerceGateway ),
|
||||
{},
|
||||
actionHandler.configuration()
|
||||
);
|
||||
|
@ -196,12 +199,15 @@ class CheckoutBootstap {
|
|||
);
|
||||
const isGooglePayMethod =
|
||||
currentPaymentMethod === PaymentMethods.GOOGLEPAY;
|
||||
const isApplePayMethod =
|
||||
currentPaymentMethod === PaymentMethods.APPLEPAY;
|
||||
const isSavedCard = isCard && isSavedCardSelected();
|
||||
const isNotOurGateway =
|
||||
! isPaypal &&
|
||||
! isCard &&
|
||||
! isSeparateButtonGateway &&
|
||||
! isGooglePayMethod;
|
||||
! isGooglePayMethod &&
|
||||
! isApplePayMethod;
|
||||
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
|
||||
const hasVaultedPaypal =
|
||||
PayPalCommerceGateway.vaulted_paypal_email !== '';
|
||||
|
@ -256,6 +262,8 @@ class CheckoutBootstap {
|
|||
paymentMethod: currentPaymentMethod,
|
||||
} );
|
||||
|
||||
setVisible( '#ppc-button-ppcp-applepay', isApplePayMethod );
|
||||
|
||||
document.body.dispatchEvent( new Event( 'ppcp_checkout_rendered' ) );
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ export const PaymentMethods = {
|
|||
OXXO: 'ppcp-oxxo-gateway',
|
||||
CARD_BUTTON: 'ppcp-card-button-gateway',
|
||||
GOOGLEPAY: 'ppcp-googlepay',
|
||||
APPLEPAY: 'ppcp-applepay',
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
import { show } from '../Helper/Hiding';
|
||||
import { renderFields } from '../../../../../ppcp-card-fields/resources/js/Render';
|
||||
import {
|
||||
addPaymentMethodConfiguration,
|
||||
cardFieldsConfiguration,
|
||||
} from '../../../../../ppcp-save-payment-methods/resources/js/Configuration';
|
||||
|
||||
class CardFieldsFreeTrialRenderer {
|
||||
constructor( defaultConfig, errorHandler, spinner ) {
|
||||
this.defaultConfig = defaultConfig;
|
||||
this.errorHandler = errorHandler;
|
||||
this.spinner = spinner;
|
||||
}
|
||||
|
||||
render( wrapper, contextConfig ) {
|
||||
if (
|
||||
( this.defaultConfig.context !== 'checkout' &&
|
||||
this.defaultConfig.context !== 'pay-now' ) ||
|
||||
wrapper === null ||
|
||||
document.querySelector( wrapper ) === null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const buttonSelector = wrapper + ' button';
|
||||
|
||||
const gateWayBox = document.querySelector(
|
||||
'.payment_box.payment_method_ppcp-credit-card-gateway'
|
||||
);
|
||||
if ( ! gateWayBox ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldDisplayStyle = gateWayBox.style.display;
|
||||
gateWayBox.style.display = 'block';
|
||||
|
||||
const hideDccGateway = document.querySelector( '#ppcp-hide-dcc' );
|
||||
if ( hideDccGateway ) {
|
||||
hideDccGateway.parentNode.removeChild( hideDccGateway );
|
||||
}
|
||||
|
||||
this.errorHandler.clear();
|
||||
|
||||
let cardFields = paypal.CardFields(
|
||||
addPaymentMethodConfiguration( this.defaultConfig )
|
||||
);
|
||||
if ( this.defaultConfig.user.is_logged ) {
|
||||
cardFields = paypal.CardFields(
|
||||
cardFieldsConfiguration( this.defaultConfig, this.errorHandler )
|
||||
);
|
||||
}
|
||||
|
||||
if ( cardFields.isEligible() ) {
|
||||
renderFields( cardFields );
|
||||
}
|
||||
|
||||
gateWayBox.style.display = oldDisplayStyle;
|
||||
|
||||
show( buttonSelector );
|
||||
|
||||
if ( this.defaultConfig.cart_contains_subscription ) {
|
||||
const saveToAccount = document.querySelector(
|
||||
'#wc-ppcp-credit-card-gateway-new-payment-method'
|
||||
);
|
||||
if ( saveToAccount ) {
|
||||
saveToAccount.checked = true;
|
||||
saveToAccount.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
document
|
||||
.querySelector( buttonSelector )
|
||||
?.addEventListener( 'click', ( event ) => {
|
||||
event.preventDefault();
|
||||
this.spinner.block();
|
||||
this.errorHandler.clear();
|
||||
|
||||
cardFields.submit().catch( ( error ) => {
|
||||
console.error( error );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
disableFields() {}
|
||||
enableFields() {}
|
||||
}
|
||||
|
||||
export default CardFieldsFreeTrialRenderer;
|
|
@ -1,5 +1,5 @@
|
|||
import { show } from '../Helper/Hiding';
|
||||
import { cardFieldStyles } from '../Helper/CardFieldsHelper';
|
||||
import { renderFields } from '../../../../../ppcp-card-fields/resources/js/Render';
|
||||
|
||||
class CardFieldsRenderer {
|
||||
constructor(
|
||||
|
@ -45,7 +45,7 @@ class CardFieldsRenderer {
|
|||
hideDccGateway.parentNode.removeChild( hideDccGateway );
|
||||
}
|
||||
|
||||
const cardField = paypal.CardFields( {
|
||||
const cardFields = paypal.CardFields( {
|
||||
createOrder: contextConfig.createOrder,
|
||||
onApprove( data ) {
|
||||
return contextConfig.onApprove( data );
|
||||
|
@ -56,79 +56,8 @@ class CardFieldsRenderer {
|
|||
},
|
||||
} );
|
||||
|
||||
if ( cardField.isEligible() ) {
|
||||
const nameField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-name'
|
||||
);
|
||||
if ( nameField ) {
|
||||
const styles = cardFieldStyles( nameField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( nameField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder =
|
||||
nameField.getAttribute( 'placeholder' );
|
||||
}
|
||||
cardField
|
||||
.NameField( fieldOptions )
|
||||
.render( nameField.parentNode );
|
||||
nameField.remove();
|
||||
}
|
||||
|
||||
const numberField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-number'
|
||||
);
|
||||
if ( numberField ) {
|
||||
const styles = cardFieldStyles( numberField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( numberField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder =
|
||||
numberField.getAttribute( 'placeholder' );
|
||||
}
|
||||
cardField
|
||||
.NumberField( fieldOptions )
|
||||
.render( numberField.parentNode );
|
||||
numberField.remove();
|
||||
}
|
||||
|
||||
const expiryField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-expiry'
|
||||
);
|
||||
if ( expiryField ) {
|
||||
const styles = cardFieldStyles( expiryField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( expiryField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder =
|
||||
expiryField.getAttribute( 'placeholder' );
|
||||
}
|
||||
cardField
|
||||
.ExpiryField( fieldOptions )
|
||||
.render( expiryField.parentNode );
|
||||
expiryField.remove();
|
||||
}
|
||||
|
||||
const cvvField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-cvc'
|
||||
);
|
||||
if ( cvvField ) {
|
||||
const styles = cardFieldStyles( cvvField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( cvvField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder =
|
||||
cvvField.getAttribute( 'placeholder' );
|
||||
}
|
||||
cardField
|
||||
.CVVField( fieldOptions )
|
||||
.render( cvvField.parentNode );
|
||||
cvvField.remove();
|
||||
}
|
||||
|
||||
if ( cardFields.isEligible() ) {
|
||||
renderFields( cardFields );
|
||||
document.dispatchEvent( new CustomEvent( 'hosted_fields_loaded' ) );
|
||||
}
|
||||
|
||||
|
@ -169,7 +98,7 @@ class CardFieldsRenderer {
|
|||
return;
|
||||
}
|
||||
|
||||
cardField.submit().catch( ( error ) => {
|
||||
cardFields.submit().catch( ( error ) => {
|
||||
this.spinner.unblock();
|
||||
console.error( error );
|
||||
this.errorHandler.message(
|
||||
|
|
|
@ -139,7 +139,7 @@ class Renderer {
|
|||
};
|
||||
|
||||
// Check the condition and add the handler if needed
|
||||
if ( this.defaultSettings.should_handle_shipping_in_paypal ) {
|
||||
if ( this.shouldEnableShippingCallback() ) {
|
||||
options.onShippingOptionsChange = ( data, actions ) => {
|
||||
let shippingOptionsChange =
|
||||
! this.isVenmoButtonClickedWhenVaultingIsEnabled(
|
||||
|
@ -227,6 +227,12 @@ class Renderer {
|
|||
return venmoButtonClicked && this.defaultSettings.vaultingEnabled;
|
||||
};
|
||||
|
||||
shouldEnableShippingCallback = () => {
|
||||
console.log(this.defaultSettings.context, this.defaultSettings)
|
||||
let needShipping = this.defaultSettings.needShipping || this.defaultSettings.context === 'product'
|
||||
return this.defaultSettings.should_handle_shipping_in_paypal && needShipping
|
||||
};
|
||||
|
||||
isAlreadyRendered( wrapper, fundingSource ) {
|
||||
return this.renderedSources.has( wrapper + ( fundingSource ?? '' ) );
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Button\Assets;
|
|||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WC_Payment_Tokens;
|
||||
use WC_Product;
|
||||
use WC_Product_Variation;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
|
@ -50,6 +51,8 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WC_Shipping_Method;
|
||||
use WC_Cart;
|
||||
|
||||
/**
|
||||
* Class SmartButton
|
||||
|
@ -1084,6 +1087,22 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
return apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $contingency );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current cart contains a product that requires physical shipping.
|
||||
*
|
||||
* @return bool True, if any cart item requires shipping.
|
||||
*/
|
||||
private function need_shipping() : bool {
|
||||
/**
|
||||
* Cart instance; might be null, esp. in customizer or in Block Editor.
|
||||
*
|
||||
* @var null|WC_Cart $cart
|
||||
*/
|
||||
$cart = WC()->cart;
|
||||
|
||||
return $cart && $cart->needs_shipping();
|
||||
}
|
||||
|
||||
/**
|
||||
* The configuration for the smart buttons.
|
||||
*
|
||||
|
@ -1292,9 +1311,11 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
'early_checkout_validation_enabled' => $this->early_validation_enabled,
|
||||
'funding_sources_without_redirect' => $this->funding_sources_without_redirect,
|
||||
'user' => array(
|
||||
'is_logged' => is_user_logged_in(),
|
||||
'is_logged' => is_user_logged_in(),
|
||||
'has_wc_card_payment_tokens' => $this->user_has_wc_card_payment_tokens( get_current_user_id() ),
|
||||
),
|
||||
'should_handle_shipping_in_paypal' => $this->should_handle_shipping_in_paypal && ! $this->is_checkout(),
|
||||
'needShipping' => $this->need_shipping(),
|
||||
'vaultingEnabled' => $this->settings->has( 'vault_enabled' ) && $this->settings->get( 'vault_enabled' ),
|
||||
);
|
||||
|
||||
|
@ -2132,4 +2153,19 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
return $location;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the given user has WC card payment tokens.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @return bool
|
||||
*/
|
||||
private function user_has_wc_card_payment_tokens( int $user_id ): bool {
|
||||
$tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, CreditCardGateway::ID );
|
||||
if ( $tokens ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
||||
|
||||
use Exception;
|
||||
use RuntimeException;
|
||||
use WC_Cart;
|
||||
use WC_Data_Exception;
|
||||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Order_Item_Shipping;
|
||||
|
@ -85,17 +87,24 @@ class WooCommerceOrderCreator {
|
|||
throw new RuntimeException( 'Problem creating WC order.' );
|
||||
}
|
||||
|
||||
$payer = $order->payer();
|
||||
$shipping = $order->purchase_units()[0]->shipping();
|
||||
try {
|
||||
$payer = $order->payer();
|
||||
$shipping = $order->purchase_units()[0]->shipping();
|
||||
|
||||
$this->configure_payment_source( $wc_order );
|
||||
$this->configure_customer( $wc_order );
|
||||
$this->configure_line_items( $wc_order, $wc_cart, $payer, $shipping );
|
||||
$this->configure_shipping( $wc_order, $payer, $shipping );
|
||||
$this->configure_coupons( $wc_order, $wc_cart->get_applied_coupons() );
|
||||
$this->configure_payment_source( $wc_order );
|
||||
$this->configure_customer( $wc_order );
|
||||
$this->configure_line_items( $wc_order, $wc_cart, $payer, $shipping );
|
||||
$this->configure_shipping( $wc_order, $payer, $shipping, $wc_cart );
|
||||
$this->configure_coupons( $wc_order, $wc_cart->get_applied_coupons() );
|
||||
|
||||
$wc_order->calculate_totals();
|
||||
$wc_order->save();
|
||||
$wc_order->calculate_totals();
|
||||
$wc_order->save();
|
||||
} catch ( Exception $exception ) {
|
||||
$wc_order->delete( true );
|
||||
throw new RuntimeException( 'Failed to create WooCommerce order: ' . $exception->getMessage() );
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_shipping_callback_woocommerce_order_created', $wc_order, $wc_cart );
|
||||
|
||||
return $wc_order;
|
||||
}
|
||||
|
@ -153,7 +162,7 @@ class WooCommerceOrderCreator {
|
|||
$item->set_total( $subscription_total );
|
||||
|
||||
$subscription->add_product( $product );
|
||||
$this->configure_shipping( $subscription, $payer, $shipping );
|
||||
$this->configure_shipping( $subscription, $payer, $shipping, $wc_cart );
|
||||
$this->configure_payment_source( $subscription );
|
||||
$this->configure_coupons( $subscription, $wc_cart->get_applied_coupons() );
|
||||
|
||||
|
@ -178,9 +187,11 @@ class WooCommerceOrderCreator {
|
|||
* @param WC_Order $wc_order The WC order.
|
||||
* @param Payer|null $payer The payer.
|
||||
* @param Shipping|null $shipping The shipping.
|
||||
* @param WC_Cart $wc_cart The Cart.
|
||||
* @return void
|
||||
* @throws WC_Data_Exception|RuntimeException When failing to configure shipping.
|
||||
*/
|
||||
protected function configure_shipping( WC_Order $wc_order, ?Payer $payer, ?Shipping $shipping ): void {
|
||||
protected function configure_shipping( WC_Order $wc_order, ?Payer $payer, ?Shipping $shipping, WC_Cart $wc_cart ): void {
|
||||
$shipping_address = null;
|
||||
$billing_address = null;
|
||||
$shipping_options = null;
|
||||
|
@ -218,6 +229,10 @@ class WooCommerceOrderCreator {
|
|||
$shipping_options = $shipping->options()[0] ?? '';
|
||||
}
|
||||
|
||||
if ( $wc_cart->needs_shipping() && empty( $shipping_options ) ) {
|
||||
throw new RuntimeException( 'No shipping method has been selected.' );
|
||||
}
|
||||
|
||||
if ( $shipping_address ) {
|
||||
$wc_order->set_shipping_address( $shipping_address );
|
||||
}
|
||||
|
|
31
modules/ppcp-card-fields/package.json
Normal file
31
modules/ppcp-card-fields/package.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "ppcp-card-fields",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"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.76",
|
||||
"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"
|
||||
}
|
||||
}
|
47
modules/ppcp-card-fields/resources/js/Render.js
Normal file
47
modules/ppcp-card-fields/resources/js/Render.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { cardFieldStyles } from './CardFieldsHelper';
|
||||
|
||||
export function renderFields( cardFields ) {
|
||||
const nameField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-name'
|
||||
);
|
||||
if ( nameField && nameField.hidden !== true ) {
|
||||
const styles = cardFieldStyles( nameField );
|
||||
cardFields
|
||||
.NameField( { style: { input: styles } } )
|
||||
.render( nameField.parentNode );
|
||||
nameField.hidden = true;
|
||||
}
|
||||
|
||||
const numberField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-number'
|
||||
);
|
||||
if ( numberField && numberField.hidden !== true ) {
|
||||
const styles = cardFieldStyles( numberField );
|
||||
cardFields
|
||||
.NumberField( { style: { input: styles } } )
|
||||
.render( numberField.parentNode );
|
||||
numberField.hidden = true;
|
||||
}
|
||||
|
||||
const expiryField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-expiry'
|
||||
);
|
||||
if ( expiryField && expiryField.hidden !== true ) {
|
||||
const styles = cardFieldStyles( expiryField );
|
||||
cardFields
|
||||
.ExpiryField( { style: { input: styles } } )
|
||||
.render( expiryField.parentNode );
|
||||
expiryField.hidden = true;
|
||||
}
|
||||
|
||||
const cvvField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-cvc'
|
||||
);
|
||||
if ( cvvField && cvvField.hidden !== true ) {
|
||||
const styles = cardFieldStyles( cvvField );
|
||||
cardFields
|
||||
.CVVField( { style: { input: styles } } )
|
||||
.render( cvvField.parentNode );
|
||||
cvvField.hidden = true;
|
||||
}
|
||||
}
|
|
@ -17,795 +17,51 @@ return array(
|
|||
$save_payment_methods_applies = $container->get( 'card-fields.helpers.save-payment-methods-applies' );
|
||||
assert( $save_payment_methods_applies instanceof CardFieldsApplies );
|
||||
|
||||
return $save_payment_methods_applies->for_country_currency();
|
||||
return $save_payment_methods_applies->for_country();
|
||||
},
|
||||
'card-fields.helpers.save-payment-methods-applies' => static function ( ContainerInterface $container ) : CardFieldsApplies {
|
||||
return new CardFieldsApplies(
|
||||
$container->get( 'card-fields.supported-country-currency-matrix' ),
|
||||
$container->get( 'api.shop.currency' ),
|
||||
$container->get( 'card-fields.supported-country-matrix' ),
|
||||
$container->get( 'api.shop.country' )
|
||||
);
|
||||
},
|
||||
'card-fields.supported-country-currency-matrix' => static function ( ContainerInterface $container ) : array {
|
||||
'card-fields.supported-country-matrix' => static function ( ContainerInterface $container ) : array {
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_card_fields_supported_country_currency_matrix',
|
||||
'woocommerce_paypal_payments_card_fields_supported_country_matrix',
|
||||
array(
|
||||
'AU' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'AT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'BE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'BG' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'CA' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'CN' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'CY' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'CZ' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'DK' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'EE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'FI' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'FR' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'DE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'GR' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'HU' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LV' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LI' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LU' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'MT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'NL' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'PL' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'PT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'RO' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'SK' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'SI' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'ES' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'SE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'GB' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'US' => array(
|
||||
'AUD',
|
||||
'CAD',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'JPY',
|
||||
'USD',
|
||||
),
|
||||
'NO' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'AU',
|
||||
'AT',
|
||||
'BE',
|
||||
'BG',
|
||||
'CA',
|
||||
'CN',
|
||||
'CY',
|
||||
'CZ',
|
||||
'DK',
|
||||
'EE',
|
||||
'FI',
|
||||
'FR',
|
||||
'DE',
|
||||
'GR',
|
||||
'HU',
|
||||
'IE',
|
||||
'IT',
|
||||
'LV',
|
||||
'LI',
|
||||
'LT',
|
||||
'LU',
|
||||
'MT',
|
||||
'NL',
|
||||
'PL',
|
||||
'PT',
|
||||
'RO',
|
||||
'SK',
|
||||
'SI',
|
||||
'ES',
|
||||
'SE',
|
||||
'GB',
|
||||
'US',
|
||||
'NO',
|
||||
)
|
||||
);
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Service for checking whether Card Fields can be used in the current country and the current currency.
|
||||
* Service for checking whether Card Fields can be used in the current country.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\CardFields\Helper
|
||||
*/
|
||||
|
@ -15,18 +15,11 @@ namespace WooCommerce\PayPalCommerce\CardFields\Helper;
|
|||
class CardFieldsApplies {
|
||||
|
||||
/**
|
||||
* The matrix which countries and currency combinations can be used.
|
||||
* The matrix which countries can be used.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $allowed_country_currency_matrix;
|
||||
|
||||
/**
|
||||
* 3-letter currency code of the shop.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $currency;
|
||||
private $allowed_country_matrix;
|
||||
|
||||
/**
|
||||
* 2-letter country code of the shop.
|
||||
|
@ -38,29 +31,23 @@ class CardFieldsApplies {
|
|||
/**
|
||||
* CardFieldsApplies constructor.
|
||||
*
|
||||
* @param array $allowed_country_currency_matrix The matrix which countries and currency combinations can be used.
|
||||
* @param string $currency 3-letter currency code of the shop.
|
||||
* @param array $allowed_country_matrix The matrix which countries can be used.
|
||||
* @param string $country 2-letter country code of the shop.
|
||||
*/
|
||||
public function __construct(
|
||||
array $allowed_country_currency_matrix,
|
||||
string $currency,
|
||||
array $allowed_country_matrix,
|
||||
string $country
|
||||
) {
|
||||
$this->allowed_country_currency_matrix = $allowed_country_currency_matrix;
|
||||
$this->currency = $currency;
|
||||
$this->country = $country;
|
||||
$this->allowed_country_matrix = $allowed_country_matrix;
|
||||
$this->country = $country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether Card Fields can be used in the current country and the current currency.
|
||||
* Returns whether Card Fields can be used in the current country.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function for_country_currency(): bool {
|
||||
if ( ! in_array( $this->country, array_keys( $this->allowed_country_currency_matrix ), true ) ) {
|
||||
return false;
|
||||
}
|
||||
return in_array( $this->currency, $this->allowed_country_currency_matrix[ $this->country ], true );
|
||||
public function for_country(): bool {
|
||||
return in_array( $this->country, $this->allowed_country_matrix, true );
|
||||
}
|
||||
}
|
||||
|
|
38
modules/ppcp-card-fields/webpack.config.js
Normal file
38
modules/ppcp-card-fields/webpack.config.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
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: {
|
||||
render: path.resolve( './resources/js/Render.js' ),
|
||||
helper: path.resolve( './resources/js/CardFieldsHelper.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' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
2194
modules/ppcp-card-fields/yarn.lock
Normal file
2194
modules/ppcp-card-fields/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
|
@ -15,6 +15,8 @@ document.addEventListener( 'DOMContentLoaded', () => {
|
|||
);
|
||||
const wcShipmentTaxBuyLabelButtonSelector =
|
||||
'.components-modal__screen-overlay .label-purchase-modal__sidebar .purchase-section button.components-button';
|
||||
const dhlGenerateLabelButton =
|
||||
document.getElementById( 'dhl-label-button' );
|
||||
|
||||
const toggleLoaderVisibility = function () {
|
||||
const loader = document.querySelector( '.ppcp-tracking-loader' );
|
||||
|
@ -44,6 +46,20 @@ document.addEventListener( 'DOMContentLoaded', () => {
|
|||
}
|
||||
};
|
||||
|
||||
const waitForButtonRemoval = function ( button ) {
|
||||
if ( document.body.contains( button ) ) {
|
||||
setTimeout( () => waitForButtonRemoval( button ), 100 );
|
||||
} else {
|
||||
jQuery( orderTrackingContainerSelector ).load(
|
||||
loadLocation,
|
||||
'',
|
||||
function () {
|
||||
toggleLoaderVisibility();
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (
|
||||
gzdSyncEnabled &&
|
||||
typeof gzdSaveButton !== 'undefined' &&
|
||||
|
@ -66,10 +82,30 @@ document.addEventListener( 'DOMContentLoaded', () => {
|
|||
} );
|
||||
}
|
||||
|
||||
if (
|
||||
typeof dhlGenerateLabelButton !== 'undefined' &&
|
||||
dhlGenerateLabelButton != null
|
||||
) {
|
||||
dhlGenerateLabelButton.addEventListener( 'click', function ( event ) {
|
||||
toggleLoaderVisibility();
|
||||
waitForButtonRemoval( dhlGenerateLabelButton );
|
||||
} );
|
||||
}
|
||||
|
||||
jQuery( document ).on(
|
||||
'mouseover mouseout',
|
||||
'#dhl_delete_label',
|
||||
function ( event ) {
|
||||
jQuery( '#ppcp-shipment-status' )
|
||||
.val( 'CANCELLED' )
|
||||
.trigger( 'change' );
|
||||
document.querySelector( '.update_shipment' ).click();
|
||||
}
|
||||
);
|
||||
|
||||
if (
|
||||
wcShippingTaxSyncEnabled &&
|
||||
typeof wcShippingTaxSyncEnabled !== 'undefined' &&
|
||||
wcShippingTaxSyncEnabled != null
|
||||
typeof wcShippingTaxSyncEnabled !== 'undefined'
|
||||
) {
|
||||
document.addEventListener( 'click', function ( event ) {
|
||||
const wcShipmentTaxBuyLabelButton = event.target.closest(
|
||||
|
|
|
@ -77,6 +77,9 @@ return array(
|
|||
'compat.ywot.is_supported_plugin_version_active' => function (): bool {
|
||||
return function_exists( 'yith_ywot_init' );
|
||||
},
|
||||
'compat.dhl.is_supported_plugin_version_active' => function (): bool {
|
||||
return function_exists( 'PR_DHL' );
|
||||
},
|
||||
'compat.shipstation.is_supported_plugin_version_active' => function (): bool {
|
||||
return function_exists( 'woocommerce_shipstation_init' );
|
||||
},
|
||||
|
@ -86,6 +89,9 @@ return array(
|
|||
'compat.nyp.is_supported_plugin_version_active' => function (): bool {
|
||||
return function_exists( 'wc_nyp_init' );
|
||||
},
|
||||
'compat.wc_bookings.is_supported_plugin_version_active' => function (): bool {
|
||||
return class_exists( 'WC_Bookings' );
|
||||
},
|
||||
|
||||
'compat.module.url' => static function ( ContainerInterface $container ): string {
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,11 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Compat;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Cart;
|
||||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
|
@ -61,6 +66,13 @@ class CompatModule implements ModuleInterface {
|
|||
if ( $is_nyp_active ) {
|
||||
$this->initialize_nyp_compat_layer();
|
||||
}
|
||||
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
|
||||
$is_wc_bookings_active = $c->get( 'compat.wc_bookings.is_supported_plugin_version_active' );
|
||||
if ( $is_wc_bookings_active ) {
|
||||
$this->initialize_wc_bookings_compat_layer( $logger );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -412,4 +424,62 @@ class CompatModule implements ModuleInterface {
|
|||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the compatibility layer for WooCommerce Bookings plugin.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @return void
|
||||
*/
|
||||
protected function initialize_wc_bookings_compat_layer( LoggerInterface $logger ): void {
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_shipping_callback_woocommerce_order_created',
|
||||
static function ( WC_Order $wc_order, WC_Cart $wc_cart ) use ( $logger ): void {
|
||||
try {
|
||||
$cart_contents = $wc_cart->get_cart();
|
||||
foreach ( $cart_contents as $cart_item ) {
|
||||
if ( empty( $cart_item['booking'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $wc_order->get_items() as $wc_order_item ) {
|
||||
if ( ! is_a( $wc_order_item, WC_Order_Item_Product::class ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$product_id = $wc_order_item->get_variation_id() ?: $wc_order_item->get_product_id();
|
||||
$product = wc_get_product( $product_id );
|
||||
|
||||
if ( ! is_wc_booking_product( $product ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$booking_data = array(
|
||||
'cost' => $cart_item['booking']['_cost'] ?? 0,
|
||||
'start_date' => $cart_item['booking']['_start_date'] ?? 0,
|
||||
'end_date' => $cart_item['booking']['_end_date'] ?? 0,
|
||||
'all_day' => $cart_item['booking']['_all_day'] ?? 0,
|
||||
'local_timezone' => $cart_item['booking']['_local_timezone'] ?? 0,
|
||||
'order_item_id' => $wc_order_item->get_id(),
|
||||
);
|
||||
|
||||
if ( isset( $cart_item['booking']['_resource_id'] ) ) {
|
||||
$booking_data['resource_id'] = $cart_item['booking']['_resource_id'];
|
||||
}
|
||||
|
||||
if ( isset( $cart_item['booking']['_persons'] ) ) {
|
||||
$booking_data['persons'] = $cart_item['booking']['_persons'];
|
||||
}
|
||||
|
||||
create_wc_booking( $cart_item['product_id'], $booking_data, 'unpaid' );
|
||||
}
|
||||
}
|
||||
} catch ( Exception $exception ) {
|
||||
$logger->warning( 'Failed to create booking for WooCommerce Bookings plugin: ' . $exception->getMessage() );
|
||||
}
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ return array(
|
|||
'classes' => array( 'ppcp-field-indent' ),
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'pay',
|
||||
'default' => 'plain',
|
||||
'options' => PropertiesDictionary::button_types(),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'dcc',
|
||||
|
|
|
@ -92,6 +92,11 @@ class GooglePayGateway extends WC_Payment_Gateway {
|
|||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
);
|
||||
|
||||
$this->method_title = __( 'Google Pay (via PayPal) ', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'The separate payment gateway with the Google Pay button. If disabled, the button is included in the PayPal gateway.', 'woocommerce-paypal-payments' );
|
||||
|
||||
|
|
14
modules/ppcp-local-alternative-payment-methods/.babelrc
Normal file
14
modules/ppcp-local-alternative-payment-methods/.babelrc
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"useBuiltIns": "usage",
|
||||
"corejs": "3.25.0"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@babel/preset-react"
|
||||
]
|
||||
]
|
||||
}
|
3
modules/ppcp-local-alternative-payment-methods/.gitignore
vendored
Normal file
3
modules/ppcp-local-alternative-payment-methods/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
node_modules
|
||||
assets/js
|
||||
assets/css
|
17
modules/ppcp-local-alternative-payment-methods/composer.json
Normal file
17
modules/ppcp-local-alternative-payment-methods/composer.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "woocommerce/ppcp-local-alternative-payment-methods",
|
||||
"type": "dhii-mod",
|
||||
"description": "Country based Alternative Payment Methods module",
|
||||
"license": "GPL-2.0",
|
||||
"require": {
|
||||
"php": "^7.2 | ^8.0",
|
||||
"dhii/module-interface": "^0.3.0-alpha1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"WooCommerce\\PayPalCommerce\\LocalAlternativePaymentMethods\\": "src"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* The local alternative payment methods module extensions.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
return array();
|
16
modules/ppcp-local-alternative-payment-methods/module.php
Normal file
16
modules/ppcp-local-alternative-payment-methods/module.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* The local alternative payment methods module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
|
||||
return static function (): ModuleInterface {
|
||||
return new LocalAlternativePaymentMethodsModule();
|
||||
};
|
33
modules/ppcp-local-alternative-payment-methods/package.json
Normal file
33
modules/ppcp-local-alternative-payment-methods/package.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "ppcp-local-alternative-payment-methods",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"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/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.76",
|
||||
"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"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
export function APM( { config, components } ) {
|
||||
const { PaymentMethodIcons } = components;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PaymentMethodIcons icons={ [ config.icon ] } align="right" />
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
import { APM } from './apm-block';
|
||||
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-bancontact_data' );
|
||||
|
||||
registerPaymentMethod( {
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={ { __html: config.title } } />,
|
||||
content: <APM config={ config } />,
|
||||
edit: <div></div>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => {
|
||||
return true;
|
||||
},
|
||||
supports: {
|
||||
features: config.supports,
|
||||
},
|
||||
} );
|
|
@ -0,0 +1,18 @@
|
|||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
import { APM } from './apm-block';
|
||||
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-blik_data' );
|
||||
|
||||
registerPaymentMethod( {
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={ { __html: config.title } } />,
|
||||
content: <APM config={ config } />,
|
||||
edit: <div></div>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => {
|
||||
return true;
|
||||
},
|
||||
supports: {
|
||||
features: config.supports,
|
||||
},
|
||||
} );
|
|
@ -0,0 +1,18 @@
|
|||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
import { APM } from './apm-block';
|
||||
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-eps_data' );
|
||||
|
||||
registerPaymentMethod( {
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={ { __html: config.title } } />,
|
||||
content: <APM config={ config } />,
|
||||
edit: <div></div>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => {
|
||||
return true;
|
||||
},
|
||||
supports: {
|
||||
features: config.supports,
|
||||
},
|
||||
} );
|
|
@ -0,0 +1,18 @@
|
|||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
import { APM } from './apm-block';
|
||||
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-ideal_data' );
|
||||
|
||||
registerPaymentMethod( {
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={ { __html: config.title } } />,
|
||||
content: <APM config={ config } />,
|
||||
edit: <div></div>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => {
|
||||
return true;
|
||||
},
|
||||
supports: {
|
||||
features: config.supports,
|
||||
},
|
||||
} );
|
|
@ -0,0 +1,18 @@
|
|||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
import { APM } from './apm-block';
|
||||
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-mybank_data' );
|
||||
|
||||
registerPaymentMethod( {
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={ { __html: config.title } } />,
|
||||
content: <APM config={ config } />,
|
||||
edit: <div></div>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => {
|
||||
return true;
|
||||
},
|
||||
supports: {
|
||||
features: config.supports,
|
||||
},
|
||||
} );
|
|
@ -0,0 +1,18 @@
|
|||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
import { APM } from './apm-block';
|
||||
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-p24_data' );
|
||||
|
||||
registerPaymentMethod( {
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={ { __html: config.title } } />,
|
||||
content: <APM config={ config } />,
|
||||
edit: <div></div>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => {
|
||||
return true;
|
||||
},
|
||||
supports: {
|
||||
features: config.supports,
|
||||
},
|
||||
} );
|
|
@ -0,0 +1,18 @@
|
|||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
import { APM } from './apm-block';
|
||||
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-trustly_data' );
|
||||
|
||||
registerPaymentMethod( {
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={ { __html: config.title } } />,
|
||||
content: <APM config={ config } />,
|
||||
edit: <div></div>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => {
|
||||
return true;
|
||||
},
|
||||
supports: {
|
||||
features: config.supports,
|
||||
},
|
||||
} );
|
170
modules/ppcp-local-alternative-payment-methods/services.php
Normal file
170
modules/ppcp-local-alternative-payment-methods/services.php
Normal file
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
/**
|
||||
* The local alternative payment methods module services.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
return array(
|
||||
'ppcp-local-apms.url' => static function ( ContainerInterface $container ): string {
|
||||
/**
|
||||
* The path cannot be false.
|
||||
*
|
||||
* @psalm-suppress PossiblyFalseArgument
|
||||
*/
|
||||
return plugins_url(
|
||||
'/modules/ppcp-local-alternative-payment-methods/',
|
||||
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.payment-methods' => static function( ContainerInterface $container ): array {
|
||||
return array(
|
||||
'bancontact' => array(
|
||||
'id' => BancontactGateway::ID,
|
||||
'countries' => array( 'BE' ),
|
||||
'currencies' => array( 'EUR' ),
|
||||
),
|
||||
'blik' => array(
|
||||
'id' => BlikGateway::ID,
|
||||
'countries' => array( 'PL' ),
|
||||
'currencies' => array( 'PLN' ),
|
||||
),
|
||||
'eps' => array(
|
||||
'id' => EPSGateway::ID,
|
||||
'countries' => array( 'AT' ),
|
||||
'currencies' => array( 'EUR' ),
|
||||
),
|
||||
'ideal' => array(
|
||||
'id' => IDealGateway::ID,
|
||||
'countries' => array( 'NL' ),
|
||||
'currencies' => array( 'EUR' ),
|
||||
),
|
||||
'mybank' => array(
|
||||
'id' => MyBankGateway::ID,
|
||||
'countries' => array( 'IT' ),
|
||||
'currencies' => array( 'EUR' ),
|
||||
),
|
||||
'p24' => array(
|
||||
'id' => P24Gateway::ID,
|
||||
'countries' => array( 'PL' ),
|
||||
'currencies' => array( 'EUR', 'PLN' ),
|
||||
),
|
||||
'trustly' => array(
|
||||
'id' => TrustlyGateway::ID,
|
||||
'countries' => array( 'AT', 'DE', 'DK', 'EE', 'ES', 'FI', 'GB', 'LT', 'LV', 'NL', 'NO', 'SE' ),
|
||||
'currencies' => array( 'EUR', 'DKK', 'SEK', 'GBP', 'NOK' ),
|
||||
),
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.bancontact.wc-gateway' => static function ( ContainerInterface $container ): BancontactGateway {
|
||||
return new BancontactGateway(
|
||||
$container->get( 'api.endpoint.orders' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.blik.wc-gateway' => static function ( ContainerInterface $container ): BlikGateway {
|
||||
return new BlikGateway(
|
||||
$container->get( 'api.endpoint.orders' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.eps.wc-gateway' => static function ( ContainerInterface $container ): EPSGateway {
|
||||
return new EPSGateway(
|
||||
$container->get( 'api.endpoint.orders' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.ideal.wc-gateway' => static function ( ContainerInterface $container ): IDealGateway {
|
||||
return new IDealGateway(
|
||||
$container->get( 'api.endpoint.orders' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.mybank.wc-gateway' => static function ( ContainerInterface $container ): MyBankGateway {
|
||||
return new MyBankGateway(
|
||||
$container->get( 'api.endpoint.orders' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.p24.wc-gateway' => static function ( ContainerInterface $container ): P24Gateway {
|
||||
return new P24Gateway(
|
||||
$container->get( 'api.endpoint.orders' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.trustly.wc-gateway' => static function ( ContainerInterface $container ): TrustlyGateway {
|
||||
return new TrustlyGateway(
|
||||
$container->get( 'api.endpoint.orders' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.bancontact.payment-method' => static function( ContainerInterface $container ): BancontactPaymentMethod {
|
||||
return new BancontactPaymentMethod(
|
||||
$container->get( 'ppcp-local-apms.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
$container->get( 'ppcp-local-apms.bancontact.wc-gateway' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.blik.payment-method' => static function( ContainerInterface $container ): BlikPaymentMethod {
|
||||
return new BlikPaymentMethod(
|
||||
$container->get( 'ppcp-local-apms.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
$container->get( 'ppcp-local-apms.blik.wc-gateway' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.eps.payment-method' => static function( ContainerInterface $container ): EPSPaymentMethod {
|
||||
return new EPSPaymentMethod(
|
||||
$container->get( 'ppcp-local-apms.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
$container->get( 'ppcp-local-apms.eps.wc-gateway' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.ideal.payment-method' => static function( ContainerInterface $container ): IDealPaymentMethod {
|
||||
return new IDealPaymentMethod(
|
||||
$container->get( 'ppcp-local-apms.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
$container->get( 'ppcp-local-apms.ideal.wc-gateway' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.mybank.payment-method' => static function( ContainerInterface $container ): MyBankPaymentMethod {
|
||||
return new MyBankPaymentMethod(
|
||||
$container->get( 'ppcp-local-apms.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
$container->get( 'ppcp-local-apms.mybank.wc-gateway' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.p24.payment-method' => static function( ContainerInterface $container ): P24PaymentMethod {
|
||||
return new P24PaymentMethod(
|
||||
$container->get( 'ppcp-local-apms.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
$container->get( 'ppcp-local-apms.p24.wc-gateway' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.trustly.payment-method' => static function( ContainerInterface $container ): TrustlyPaymentMethod {
|
||||
return new TrustlyPaymentMethod(
|
||||
$container->get( 'ppcp-local-apms.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
$container->get( 'ppcp-local-apms.trustly.wc-gateway' )
|
||||
);
|
||||
},
|
||||
);
|
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
/**
|
||||
* The Bancontact payment gateway.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
||||
/**
|
||||
* Class BancontactGateway
|
||||
*/
|
||||
class BancontactGateway extends WC_Payment_Gateway {
|
||||
|
||||
const ID = 'ppcp-bancontact';
|
||||
|
||||
/**
|
||||
* PayPal Orders endpoint.
|
||||
*
|
||||
* @var Orders
|
||||
*/
|
||||
private $orders_endpoint;
|
||||
|
||||
/**
|
||||
* Purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* BancontactGateway constructor.
|
||||
*
|
||||
* @param Orders $orders_endpoint PayPal Orders endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory Purchase unit factory.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
*/
|
||||
public function __construct(
|
||||
Orders $orders_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
RefundProcessor $refund_processor,
|
||||
TransactionUrlProvider $transaction_url_provider
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
);
|
||||
|
||||
$this->method_title = __( 'Bancontact', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'A popular and trusted electronic payment method in Belgium, used by Belgian customers with Bancontact cards issued by local banks. Transactions are processed in EUR.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$this->title = $this->get_option( 'title', __( 'Bancontact', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->icon = esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_bancontact_color.svg' );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
|
||||
$this->orders_endpoint = $orders_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Bancontact', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable Bancontact payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->title,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->description,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the order.
|
||||
*
|
||||
* @param int $order_id The WC order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_status( 'on-hold', __( 'Awaiting Bancontact to confirm the payment.', 'woocommerce-paypal-payments' ) );
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$amount = $purchase_unit->amount()->to_array();
|
||||
|
||||
$request_body = array(
|
||||
'intent' => 'CAPTURE',
|
||||
'payment_source' => array(
|
||||
'bancontact' => array(
|
||||
'country_code' => $wc_order->get_billing_country(),
|
||||
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
||||
),
|
||||
),
|
||||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
'purchase_units' => array(
|
||||
array(
|
||||
'reference_id' => $purchase_unit->reference_id(),
|
||||
'amount' => array(
|
||||
'currency_code' => $amount['currency_code'],
|
||||
'value' => $amount['value'],
|
||||
),
|
||||
'custom_id' => $purchase_unit->custom_id(),
|
||||
'invoice_id' => $purchase_unit->invoice_id(),
|
||||
),
|
||||
),
|
||||
'application_context' => array(
|
||||
'locale' => 'en-BE',
|
||||
'return_url' => $this->get_return_url( $wc_order ),
|
||||
'cancel_url' => add_query_arg( 'cancelled', 'true', $this->get_return_url( $wc_order ) ),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
$response = $this->orders_endpoint->create( $request_body );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$exception->getMessage()
|
||||
);
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
$body = json_decode( $response['body'] );
|
||||
|
||||
$payer_action = '';
|
||||
foreach ( $body->links as $link ) {
|
||||
if ( $link->rel === 'payer-action' ) {
|
||||
$payer_action = $link->href;
|
||||
}
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => esc_url( $payer_action ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
* If the gateway declares 'refunds' support, this will allow it to refund.
|
||||
* a passed in amount.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, \WC_Order::class ) ) {
|
||||
return false;
|
||||
}
|
||||
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return transaction url for this gateway and given order.
|
||||
*
|
||||
* @param \WC_Order $order WC order to get transaction url by.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ): string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/**
|
||||
* Bancontact payment method.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
|
||||
|
||||
/**
|
||||
* Class BancontactPaymentMethod
|
||||
*/
|
||||
class BancontactPaymentMethod extends AbstractPaymentMethodType {
|
||||
|
||||
/**
|
||||
* The URL of this module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The assets version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* Bancontact WC gateway.
|
||||
*
|
||||
* @var BancontactGateway
|
||||
*/
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* BancontactPaymentMethod constructor.
|
||||
*
|
||||
* @param string $module_url The URL of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param BancontactGateway $gateway Bancontact WC gateway.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
string $version,
|
||||
BancontactGateway $gateway
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->gateway = $gateway;
|
||||
|
||||
$this->name = BancontactGateway::ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initialize() {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function is_active() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_script_handles() {
|
||||
wp_register_script(
|
||||
'ppcp-bancontact-payment-method',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/bancontact-payment-method.js',
|
||||
array(),
|
||||
$this->version,
|
||||
true
|
||||
);
|
||||
|
||||
return array( 'ppcp-bancontact-payment-method' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_data() {
|
||||
return array(
|
||||
'id' => $this->name,
|
||||
'title' => $this->gateway->title,
|
||||
'description' => $this->gateway->description,
|
||||
'icon' => esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_bancontact_color.svg' ),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
/**
|
||||
* The Blik payment gateway.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
||||
/**
|
||||
* Class BlikGateway
|
||||
*/
|
||||
class BlikGateway extends WC_Payment_Gateway {
|
||||
|
||||
const ID = 'ppcp-blik';
|
||||
|
||||
/**
|
||||
* PayPal Orders endpoint.
|
||||
*
|
||||
* @var Orders
|
||||
*/
|
||||
private $orders_endpoint;
|
||||
|
||||
/**
|
||||
* Purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* BlikGateway constructor.
|
||||
*
|
||||
* @param Orders $orders_endpoint PayPal Orders endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory Purchase unit factory.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
*/
|
||||
public function __construct(
|
||||
Orders $orders_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
RefundProcessor $refund_processor,
|
||||
TransactionUrlProvider $transaction_url_provider
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
);
|
||||
|
||||
$this->method_title = __( 'Blik', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'A widely used mobile payment method in Poland, allowing Polish customers to pay directly via their banking apps. Transactions are processed in PLN.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$this->title = $this->get_option( 'title', __( 'Blik', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->icon = esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_blik_color.svg' );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
|
||||
$this->orders_endpoint = $orders_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Blik', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable Blik payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->title,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->description,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the order.
|
||||
*
|
||||
* @param int $order_id The WC order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_status( 'on-hold', __( 'Awaiting Blik to confirm the payment.', 'woocommerce-paypal-payments' ) );
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$amount = $purchase_unit->amount()->to_array();
|
||||
|
||||
$request_body = array(
|
||||
'intent' => 'CAPTURE',
|
||||
'payment_source' => array(
|
||||
'blik' => array(
|
||||
'country_code' => $wc_order->get_billing_country(),
|
||||
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
||||
'email' => $wc_order->get_billing_email(),
|
||||
),
|
||||
),
|
||||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
'purchase_units' => array(
|
||||
array(
|
||||
'reference_id' => $purchase_unit->reference_id(),
|
||||
'amount' => array(
|
||||
'currency_code' => $amount['currency_code'],
|
||||
'value' => $amount['value'],
|
||||
),
|
||||
'custom_id' => $purchase_unit->custom_id(),
|
||||
'invoice_id' => $purchase_unit->invoice_id(),
|
||||
),
|
||||
),
|
||||
'application_context' => array(
|
||||
'locale' => 'en-PL',
|
||||
'return_url' => $this->get_return_url( $wc_order ),
|
||||
'cancel_url' => add_query_arg( 'cancelled', 'true', $this->get_return_url( $wc_order ) ),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
$response = $this->orders_endpoint->create( $request_body );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$exception->getMessage()
|
||||
);
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
$body = json_decode( $response['body'] );
|
||||
|
||||
$payer_action = '';
|
||||
foreach ( $body->links as $link ) {
|
||||
if ( $link->rel === 'payer-action' ) {
|
||||
$payer_action = $link->href;
|
||||
}
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => esc_url( $payer_action ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
* If the gateway declares 'refunds' support, this will allow it to refund.
|
||||
* a passed in amount.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, \WC_Order::class ) ) {
|
||||
return false;
|
||||
}
|
||||
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return transaction url for this gateway and given order.
|
||||
*
|
||||
* @param \WC_Order $order WC order to get transaction url by.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ): string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/**
|
||||
* Blik payment method.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
|
||||
|
||||
/**
|
||||
* Class BlikPaymentMethod
|
||||
*/
|
||||
class BlikPaymentMethod extends AbstractPaymentMethodType {
|
||||
|
||||
/**
|
||||
* The URL of this module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The assets version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* Blik WC gateway.
|
||||
*
|
||||
* @var BlikGateway
|
||||
*/
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* BlikPaymentMethod constructor.
|
||||
*
|
||||
* @param string $module_url The URL of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param BlikGateway $gateway Blik WC gateway.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
string $version,
|
||||
BlikGateway $gateway
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->gateway = $gateway;
|
||||
|
||||
$this->name = BlikGateway::ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initialize() {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function is_active() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_script_handles() {
|
||||
wp_register_script(
|
||||
'ppcp-blick-payment-method',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/blik-payment-method.js',
|
||||
array(),
|
||||
$this->version,
|
||||
true
|
||||
);
|
||||
|
||||
return array( 'ppcp-blick-payment-method' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_data() {
|
||||
return array(
|
||||
'id' => $this->name,
|
||||
'title' => $this->gateway->title,
|
||||
'description' => $this->gateway->description,
|
||||
'icon' => esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_blik_color.svg' ),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
/**
|
||||
* The EPS payment gateway.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
||||
/**
|
||||
* Class EPSGateway
|
||||
*/
|
||||
class EPSGateway extends WC_Payment_Gateway {
|
||||
|
||||
const ID = 'ppcp-eps';
|
||||
|
||||
/**
|
||||
* PayPal Orders endpoint.
|
||||
*
|
||||
* @var Orders
|
||||
*/
|
||||
private $orders_endpoint;
|
||||
|
||||
/**
|
||||
* Purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* EPSGateway constructor.
|
||||
*
|
||||
* @param Orders $orders_endpoint PayPal Orders endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory Purchase unit factory.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
*/
|
||||
public function __construct(
|
||||
Orders $orders_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
RefundProcessor $refund_processor,
|
||||
TransactionUrlProvider $transaction_url_provider
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
);
|
||||
|
||||
$this->method_title = __( 'EPS', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'An online payment method in Austria, enabling Austrian buyers to make secure payments directly through their bank accounts. Transactions are processed in EUR.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$this->title = $this->get_option( 'title', __( 'EPS', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->icon = esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_eps_color.svg' );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
|
||||
$this->orders_endpoint = $orders_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'EPS', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable EPS payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->title,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->description,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the order.
|
||||
*
|
||||
* @param int $order_id The WC order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_status( 'on-hold', __( 'Awaiting EPS to confirm the payment.', 'woocommerce-paypal-payments' ) );
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$amount = $purchase_unit->amount()->to_array();
|
||||
|
||||
$request_body = array(
|
||||
'intent' => 'CAPTURE',
|
||||
'payment_source' => array(
|
||||
'eps' => array(
|
||||
'country_code' => $wc_order->get_billing_country(),
|
||||
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
||||
),
|
||||
),
|
||||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
'purchase_units' => array(
|
||||
array(
|
||||
'reference_id' => $purchase_unit->reference_id(),
|
||||
'amount' => array(
|
||||
'currency_code' => $amount['currency_code'],
|
||||
'value' => $amount['value'],
|
||||
),
|
||||
'custom_id' => $purchase_unit->custom_id(),
|
||||
'invoice_id' => $purchase_unit->invoice_id(),
|
||||
),
|
||||
),
|
||||
'application_context' => array(
|
||||
'locale' => 'en-AT',
|
||||
'return_url' => $this->get_return_url( $wc_order ),
|
||||
'cancel_url' => add_query_arg( 'cancelled', 'true', $this->get_return_url( $wc_order ) ),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
$response = $this->orders_endpoint->create( $request_body );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$exception->getMessage()
|
||||
);
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
$body = json_decode( $response['body'] );
|
||||
|
||||
$payer_action = '';
|
||||
foreach ( $body->links as $link ) {
|
||||
if ( $link->rel === 'payer-action' ) {
|
||||
$payer_action = $link->href;
|
||||
}
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => esc_url( $payer_action ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
* If the gateway declares 'refunds' support, this will allow it to refund.
|
||||
* a passed in amount.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, \WC_Order::class ) ) {
|
||||
return false;
|
||||
}
|
||||
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return transaction url for this gateway and given order.
|
||||
*
|
||||
* @param \WC_Order $order WC order to get transaction url by.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ): string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/**
|
||||
* EPS payment method.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
|
||||
|
||||
/**
|
||||
* Class EPSPaymentMethod
|
||||
*/
|
||||
class EPSPaymentMethod extends AbstractPaymentMethodType {
|
||||
|
||||
/**
|
||||
* The URL of this module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The assets version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* EPS WC gateway.
|
||||
*
|
||||
* @var EPSGateway
|
||||
*/
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* EPSPaymentMethod constructor.
|
||||
*
|
||||
* @param string $module_url The URL of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param EPSGateway $gateway EPS WC gateway.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
string $version,
|
||||
EPSGateway $gateway
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->gateway = $gateway;
|
||||
|
||||
$this->name = EPSGateway::ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initialize() {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function is_active() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_script_handles() {
|
||||
wp_register_script(
|
||||
'ppcp-eps-payment-method',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/eps-payment-method.js',
|
||||
array(),
|
||||
$this->version,
|
||||
true
|
||||
);
|
||||
|
||||
return array( 'ppcp-eps-payment-method' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_data() {
|
||||
return array(
|
||||
'id' => $this->name,
|
||||
'title' => $this->gateway->title,
|
||||
'description' => $this->gateway->description,
|
||||
'icon' => esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_eps_color.svg' ),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
<?php
|
||||
/**
|
||||
* The iDeal payment gateway.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
||||
/**
|
||||
* Class IDealGateway
|
||||
*/
|
||||
class IDealGateway extends WC_Payment_Gateway {
|
||||
|
||||
const ID = 'ppcp-ideal';
|
||||
|
||||
/**
|
||||
* PayPal Orders endpoint.
|
||||
*
|
||||
* @var Orders
|
||||
*/
|
||||
private $orders_endpoint;
|
||||
|
||||
/**
|
||||
* Purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* IDealGateway constructor.
|
||||
*
|
||||
* @param Orders $orders_endpoint PayPal Orders endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory Purchase unit factory.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
*/
|
||||
public function __construct(
|
||||
Orders $orders_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
RefundProcessor $refund_processor,
|
||||
TransactionUrlProvider $transaction_url_provider
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
);
|
||||
|
||||
$this->method_title = __( 'iDeal', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'The most common payment method in the Netherlands, allowing Dutch buyers to pay directly through their preferred bank. Transactions are processed in EUR.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$this->title = $this->get_option( 'title', __( 'iDeal', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->icon = esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_ideal_color.svg' );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
|
||||
$this->orders_endpoint = $orders_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'iDeal', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable iDeal payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->title,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->description,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the order.
|
||||
*
|
||||
* @param int $order_id The WC order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_status( 'on-hold', __( 'Awaiting iDeal to confirm the payment.', 'woocommerce-paypal-payments' ) );
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$amount = $purchase_unit->amount()->to_array();
|
||||
|
||||
$payment_source = array(
|
||||
'country_code' => $wc_order->get_billing_country(),
|
||||
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
||||
);
|
||||
// TODO get "bic" from gateway settings.
|
||||
|
||||
$request_body = array(
|
||||
'intent' => 'CAPTURE',
|
||||
'payment_source' => array(
|
||||
'ideal' => $payment_source,
|
||||
),
|
||||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
'purchase_units' => array(
|
||||
array(
|
||||
'reference_id' => $purchase_unit->reference_id(),
|
||||
'amount' => array(
|
||||
'currency_code' => $amount['currency_code'],
|
||||
'value' => $amount['value'],
|
||||
),
|
||||
'custom_id' => $purchase_unit->custom_id(),
|
||||
'invoice_id' => $purchase_unit->invoice_id(),
|
||||
),
|
||||
),
|
||||
'application_context' => array(
|
||||
'return_url' => $this->get_return_url( $wc_order ),
|
||||
'cancel_url' => add_query_arg( 'cancelled', 'true', $this->get_return_url( $wc_order ) ),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
$response = $this->orders_endpoint->create( $request_body );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$exception->getMessage()
|
||||
);
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
$body = json_decode( $response['body'] );
|
||||
|
||||
$payer_action = '';
|
||||
foreach ( $body->links as $link ) {
|
||||
if ( $link->rel === 'payer-action' ) {
|
||||
$payer_action = $link->href;
|
||||
}
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => esc_url( $payer_action ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
* If the gateway declares 'refunds' support, this will allow it to refund.
|
||||
* a passed in amount.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, \WC_Order::class ) ) {
|
||||
return false;
|
||||
}
|
||||
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return transaction url for this gateway and given order.
|
||||
*
|
||||
* @param \WC_Order $order WC order to get transaction url by.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ): string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/**
|
||||
* IDeal payment method.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
|
||||
|
||||
/**
|
||||
* Class IDealPaymentMethod
|
||||
*/
|
||||
class IDealPaymentMethod extends AbstractPaymentMethodType {
|
||||
|
||||
/**
|
||||
* The URL of this module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The assets version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* IDeal WC gateway.
|
||||
*
|
||||
* @var IDealGateway
|
||||
*/
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* IDealPaymentMethod constructor.
|
||||
*
|
||||
* @param string $module_url The URL of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param IDealGateway $gateway IDeal WC gateway.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
string $version,
|
||||
IDealGateway $gateway
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->gateway = $gateway;
|
||||
|
||||
$this->name = IDealGateway::ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initialize() {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function is_active() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_script_handles() {
|
||||
wp_register_script(
|
||||
'ppcp-ideal-payment-method',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/ideal-payment-method.js',
|
||||
array(),
|
||||
$this->version,
|
||||
true
|
||||
);
|
||||
|
||||
return array( 'ppcp-ideal-payment-method' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_data() {
|
||||
return array(
|
||||
'id' => $this->name,
|
||||
'title' => $this->gateway->title,
|
||||
'description' => $this->gateway->description,
|
||||
'icon' => esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_ideal_color.svg' ),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
/**
|
||||
* The local alternative payment methods module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
|
||||
use WC_Order;
|
||||
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 LocalAlternativePaymentMethodsModule
|
||||
*/
|
||||
class LocalAlternativePaymentMethodsModule 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 {
|
||||
add_filter(
|
||||
'woocommerce_payment_gateways',
|
||||
/**
|
||||
* Param types removed to avoid third-party issues.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function ( $methods ) use ( $c ) {
|
||||
if ( ! is_array( $methods ) ) {
|
||||
return $methods;
|
||||
}
|
||||
|
||||
$payment_methods = $c->get( 'ppcp-local-apms.payment-methods' );
|
||||
foreach ( $payment_methods as $key => $value ) {
|
||||
$methods[] = $c->get( 'ppcp-local-apms.' . $key . '.wc-gateway' );
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_available_payment_gateways',
|
||||
/**
|
||||
* Param types removed to avoid third-party issues.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function ( $methods ) use ( $c ) {
|
||||
if ( ! is_array( $methods ) ) {
|
||||
return $methods;
|
||||
}
|
||||
|
||||
if ( ! is_admin() ) {
|
||||
if ( ! isset( WC()->customer ) ) {
|
||||
return $methods;
|
||||
}
|
||||
|
||||
$customer_country = WC()->customer->get_billing_country() ?: WC()->customer->get_shipping_country();
|
||||
$site_currency = get_woocommerce_currency();
|
||||
|
||||
$payment_methods = $c->get( 'ppcp-local-apms.payment-methods' );
|
||||
foreach ( $payment_methods as $payment_method ) {
|
||||
if (
|
||||
! in_array( $customer_country, $payment_method['countries'], true )
|
||||
|| ! in_array( $site_currency, $payment_method['currencies'], true )
|
||||
) {
|
||||
unset( $methods[ $payment_method['id'] ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_blocks_payment_method_type_registration',
|
||||
function( PaymentMethodRegistry $payment_method_registry ) use ( $c ): void {
|
||||
$payment_methods = $c->get( 'ppcp-local-apms.payment-methods' );
|
||||
foreach ( $payment_methods as $key => $value ) {
|
||||
$payment_method_registry->register( $c->get( 'ppcp-local-apms.' . $key . '.payment-method' ) );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_paypal_payments_localized_script_data',
|
||||
function ( array $data ) use ( $c ) {
|
||||
$payment_methods = $c->get( 'ppcp-local-apms.payment-methods' );
|
||||
|
||||
$default_disable_funding = $data['url_params']['disable-funding'] ?? '';
|
||||
$disable_funding = array_merge( array_keys( $payment_methods ), array_filter( explode( ',', $default_disable_funding ) ) );
|
||||
$data['url_params']['disable-funding'] = implode( ',', array_unique( $disable_funding ) );
|
||||
|
||||
return $data;
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_before_thankyou',
|
||||
/**
|
||||
* Activate is_checkout() on woocommerce/classic-shortcode checkout blocks.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function( $order_id ) use ( $c ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! $order instanceof WC_Order ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
$cancelled = wc_clean( wp_unslash( $_GET['cancelled'] ?? '' ) );
|
||||
$order_key = wc_clean( wp_unslash( $_GET['key'] ?? '' ) );
|
||||
// phpcs:enable
|
||||
|
||||
$payment_methods = $c->get( 'ppcp-local-apms.payment-methods' );
|
||||
if (
|
||||
! $this->is_local_apm( $order->get_payment_method(), $payment_methods )
|
||||
|| ! $cancelled
|
||||
|| $order->get_order_key() !== $order_key
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$error_code = wc_clean( wp_unslash( $_GET['errorcode'] ?? '' ) );
|
||||
if ( $error_code === 'processing_error' || $error_code === 'payment_error' ) {
|
||||
$order->update_status( 'failed', __( "The payment can't be processed because of an error.", 'woocommerce-paypal-payments' ) );
|
||||
|
||||
add_filter( 'woocommerce_order_has_status', '__return_true' );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given payment method is a local APM.
|
||||
*
|
||||
* @param string $selected_payment_method Selected payment method.
|
||||
* @param array $payment_methods Available local APMs.
|
||||
* @return bool
|
||||
*/
|
||||
private function is_local_apm( string $selected_payment_method, array $payment_methods ): bool {
|
||||
foreach ( $payment_methods as $payment_method ) {
|
||||
if ( $payment_method['id'] === $selected_payment_method ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
/**
|
||||
* The MyBank payment gateway.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
||||
/**
|
||||
* Class MyBankGateway
|
||||
*/
|
||||
class MyBankGateway extends WC_Payment_Gateway {
|
||||
|
||||
const ID = 'ppcp-mybank';
|
||||
|
||||
/**
|
||||
* PayPal Orders endpoint.
|
||||
*
|
||||
* @var Orders
|
||||
*/
|
||||
private $orders_endpoint;
|
||||
|
||||
/**
|
||||
* Purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* MyBankGateway constructor.
|
||||
*
|
||||
* @param Orders $orders_endpoint PayPal Orders endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory Purchase unit factory.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
*/
|
||||
public function __construct(
|
||||
Orders $orders_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
RefundProcessor $refund_processor,
|
||||
TransactionUrlProvider $transaction_url_provider
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
);
|
||||
|
||||
$this->method_title = __( 'MyBank', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'A European online banking payment solution primarily used in Italy, enabling customers to make secure bank transfers during checkout. Transactions are processed in EUR.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$this->title = $this->get_option( 'title', __( 'MyBank', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->icon = esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_mybank_color.svg' );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
|
||||
$this->orders_endpoint = $orders_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'MyBank', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable MyBank payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->title,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->description,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the order.
|
||||
*
|
||||
* @param int $order_id The WC order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_status( 'on-hold', __( 'Awaiting MyBank to confirm the payment.', 'woocommerce-paypal-payments' ) );
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$amount = $purchase_unit->amount()->to_array();
|
||||
|
||||
$request_body = array(
|
||||
'intent' => 'CAPTURE',
|
||||
'payment_source' => array(
|
||||
'mybank' => array(
|
||||
'country_code' => $wc_order->get_billing_country(),
|
||||
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
||||
),
|
||||
),
|
||||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
'purchase_units' => array(
|
||||
array(
|
||||
'reference_id' => $purchase_unit->reference_id(),
|
||||
'amount' => array(
|
||||
'currency_code' => $amount['currency_code'],
|
||||
'value' => $amount['value'],
|
||||
),
|
||||
'custom_id' => $purchase_unit->custom_id(),
|
||||
'invoice_id' => $purchase_unit->invoice_id(),
|
||||
),
|
||||
),
|
||||
'application_context' => array(
|
||||
'locale' => 'en-IT',
|
||||
'return_url' => $this->get_return_url( $wc_order ),
|
||||
'cancel_url' => add_query_arg( 'cancelled', 'true', $this->get_return_url( $wc_order ) ),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
$response = $this->orders_endpoint->create( $request_body );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$exception->getMessage()
|
||||
);
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
$body = json_decode( $response['body'] );
|
||||
|
||||
$payer_action = '';
|
||||
foreach ( $body->links as $link ) {
|
||||
if ( $link->rel === 'payer-action' ) {
|
||||
$payer_action = $link->href;
|
||||
}
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => esc_url( $payer_action ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
* If the gateway declares 'refunds' support, this will allow it to refund.
|
||||
* a passed in amount.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, \WC_Order::class ) ) {
|
||||
return false;
|
||||
}
|
||||
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return transaction url for this gateway and given order.
|
||||
*
|
||||
* @param \WC_Order $order WC order to get transaction url by.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ): string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/**
|
||||
* MyBank payment method.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
|
||||
|
||||
/**
|
||||
* Class MyBankPaymentMethod
|
||||
*/
|
||||
class MyBankPaymentMethod extends AbstractPaymentMethodType {
|
||||
|
||||
/**
|
||||
* The URL of this module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The assets version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* MyBank WC gateway.
|
||||
*
|
||||
* @var MyBankGateway
|
||||
*/
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* MyBankPaymentMethod constructor.
|
||||
*
|
||||
* @param string $module_url The URL of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param MyBankGateway $gateway MyBank WC gateway.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
string $version,
|
||||
MyBankGateway $gateway
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->gateway = $gateway;
|
||||
|
||||
$this->name = MyBankGateway::ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initialize() {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function is_active() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_script_handles() {
|
||||
wp_register_script(
|
||||
'ppcp-mybank-payment-method',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/mybank-payment-method.js',
|
||||
array(),
|
||||
$this->version,
|
||||
true
|
||||
);
|
||||
|
||||
return array( 'ppcp-mybank-payment-method' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_data() {
|
||||
return array(
|
||||
'id' => $this->name,
|
||||
'title' => $this->gateway->title,
|
||||
'description' => $this->gateway->description,
|
||||
'icon' => esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_mybank_color.svg' ),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
/**
|
||||
* The P24 payment gateway.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
||||
/**
|
||||
* Class P24Gateway
|
||||
*/
|
||||
class P24Gateway extends WC_Payment_Gateway {
|
||||
|
||||
const ID = 'ppcp-p24';
|
||||
|
||||
/**
|
||||
* PayPal Orders endpoint.
|
||||
*
|
||||
* @var Orders
|
||||
*/
|
||||
private $orders_endpoint;
|
||||
|
||||
/**
|
||||
* Purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* P24Gateway constructor.
|
||||
*
|
||||
* @param Orders $orders_endpoint PayPal Orders endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory Purchase unit factory.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
*/
|
||||
public function __construct(
|
||||
Orders $orders_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
RefundProcessor $refund_processor,
|
||||
TransactionUrlProvider $transaction_url_provider
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
);
|
||||
|
||||
$this->method_title = __( 'Przelewy24', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'A popular online payment gateway in Poland, offering various payment options for Polish customers. Transactions can be processed in PLN or EUR.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$this->title = $this->get_option( 'title', __( 'Przelewy24', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->icon = esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_przelewy24_color.svg' );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
|
||||
$this->orders_endpoint = $orders_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Przelewy24', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable Przelewy24 payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->title,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->description,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the order.
|
||||
*
|
||||
* @param int $order_id The WC order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_status( 'on-hold', __( 'Awaiting Przelewy24 to confirm the payment.', 'woocommerce-paypal-payments' ) );
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$amount = $purchase_unit->amount()->to_array();
|
||||
|
||||
$request_body = array(
|
||||
'intent' => 'CAPTURE',
|
||||
'payment_source' => array(
|
||||
'p24' => array(
|
||||
'country_code' => $wc_order->get_billing_country(),
|
||||
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
||||
'email' => $wc_order->get_billing_email(),
|
||||
),
|
||||
),
|
||||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
'purchase_units' => array(
|
||||
array(
|
||||
'reference_id' => $purchase_unit->reference_id(),
|
||||
'amount' => array(
|
||||
'currency_code' => $amount['currency_code'],
|
||||
'value' => $amount['value'],
|
||||
),
|
||||
'custom_id' => $purchase_unit->custom_id(),
|
||||
'invoice_id' => $purchase_unit->invoice_id(),
|
||||
),
|
||||
),
|
||||
'application_context' => array(
|
||||
'locale' => 'en-PL',
|
||||
'return_url' => $this->get_return_url( $wc_order ),
|
||||
'cancel_url' => add_query_arg( 'cancelled', 'true', $this->get_return_url( $wc_order ) ),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
$response = $this->orders_endpoint->create( $request_body );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$exception->getMessage()
|
||||
);
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
$body = json_decode( $response['body'] );
|
||||
|
||||
$payer_action = '';
|
||||
foreach ( $body->links as $link ) {
|
||||
if ( $link->rel === 'payer-action' ) {
|
||||
$payer_action = $link->href;
|
||||
}
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => esc_url( $payer_action ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
* If the gateway declares 'refunds' support, this will allow it to refund.
|
||||
* a passed in amount.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, \WC_Order::class ) ) {
|
||||
return false;
|
||||
}
|
||||
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return transaction url for this gateway and given order.
|
||||
*
|
||||
* @param \WC_Order $order WC order to get transaction url by.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ): string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/**
|
||||
* Przelewy24 payment method.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
|
||||
|
||||
/**
|
||||
* Class P24PaymentMethod
|
||||
*/
|
||||
class P24PaymentMethod extends AbstractPaymentMethodType {
|
||||
|
||||
/**
|
||||
* The URL of this module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The assets version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* P24Gateway WC gateway.
|
||||
*
|
||||
* @var P24Gateway
|
||||
*/
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* P24PaymentMethod constructor.
|
||||
*
|
||||
* @param string $module_url The URL of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param P24Gateway $gateway Przelewy24 WC gateway.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
string $version,
|
||||
P24Gateway $gateway
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->gateway = $gateway;
|
||||
|
||||
$this->name = P24Gateway::ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initialize() {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function is_active() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_script_handles() {
|
||||
wp_register_script(
|
||||
'ppcp-p24-payment-method',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/p24-payment-method.js',
|
||||
array(),
|
||||
$this->version,
|
||||
true
|
||||
);
|
||||
|
||||
return array( 'ppcp-p24-payment-method' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_data() {
|
||||
return array(
|
||||
'id' => $this->name,
|
||||
'title' => $this->gateway->title,
|
||||
'description' => $this->gateway->description,
|
||||
'icon' => esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_przelewy24_color.svg' ),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
<?php
|
||||
/**
|
||||
* The Trustly payment gateway.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
||||
/**
|
||||
* Class TrustlyGateway
|
||||
*/
|
||||
class TrustlyGateway extends WC_Payment_Gateway {
|
||||
|
||||
const ID = 'ppcp-trustly';
|
||||
|
||||
/**
|
||||
* PayPal Orders endpoint.
|
||||
*
|
||||
* @var Orders
|
||||
*/
|
||||
private $orders_endpoint;
|
||||
|
||||
/**
|
||||
* Purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* TrustlyGateway constructor.
|
||||
*
|
||||
* @param Orders $orders_endpoint PayPal Orders endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory Purchase unit factory.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
*/
|
||||
public function __construct(
|
||||
Orders $orders_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
RefundProcessor $refund_processor,
|
||||
TransactionUrlProvider $transaction_url_provider
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
);
|
||||
|
||||
$this->method_title = __( 'Trustly', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'A European payment method that allows buyers to make payments directly from their bank accounts, suitable for customers across multiple European countries. Supported currencies include EUR, DKK, SEK, GBP, and NOK.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$this->title = $this->get_option( 'title', __( 'Trustly', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->icon = esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_trustly_color.svg' );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
|
||||
$this->orders_endpoint = $orders_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Trustly', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable Trustly payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->title,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->description,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the order.
|
||||
*
|
||||
* @param int $order_id The WC order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_status( 'on-hold', __( 'Awaiting Trustly to confirm the payment.', 'woocommerce-paypal-payments' ) );
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$amount = $purchase_unit->amount()->to_array();
|
||||
|
||||
$request_body = array(
|
||||
'intent' => 'CAPTURE',
|
||||
'payment_source' => array(
|
||||
'trustly' => array(
|
||||
'country_code' => $wc_order->get_billing_country(),
|
||||
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
||||
),
|
||||
),
|
||||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
'purchase_units' => array(
|
||||
array(
|
||||
'reference_id' => $purchase_unit->reference_id(),
|
||||
'amount' => array(
|
||||
'currency_code' => $amount['currency_code'],
|
||||
'value' => $amount['value'],
|
||||
),
|
||||
'custom_id' => $purchase_unit->custom_id(),
|
||||
'invoice_id' => $purchase_unit->invoice_id(),
|
||||
),
|
||||
),
|
||||
'application_context' => array(
|
||||
'locale' => $this->valid_bcp47_code(),
|
||||
'return_url' => $this->get_return_url( $wc_order ),
|
||||
'cancel_url' => add_query_arg( 'cancelled', 'true', $this->get_return_url( $wc_order ) ),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
$response = $this->orders_endpoint->create( $request_body );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$exception->getMessage()
|
||||
);
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
$body = json_decode( $response['body'] );
|
||||
|
||||
$payer_action = '';
|
||||
foreach ( $body->links as $link ) {
|
||||
if ( $link->rel === 'payer-action' ) {
|
||||
$payer_action = $link->href;
|
||||
}
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => esc_url( $payer_action ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
* If the gateway declares 'refunds' support, this will allow it to refund.
|
||||
* a passed in amount.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, \WC_Order::class ) ) {
|
||||
return false;
|
||||
}
|
||||
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return transaction url for this gateway and given order.
|
||||
*
|
||||
* @param \WC_Order $order WC order to get transaction url by.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ): string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PayPal-supported BCP-47 code, for example de-DE-formal becomes de-DE.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function valid_bcp47_code() {
|
||||
$locale = str_replace( '_', '-', get_user_locale() );
|
||||
|
||||
if ( preg_match( '/^[a-z]{2}(?:-[A-Z][a-z]{3})?(?:-(?:[A-Z]{2}))?$/', $locale ) ) {
|
||||
return $locale;
|
||||
}
|
||||
|
||||
$parts = explode( '-', $locale );
|
||||
if ( count( $parts ) === 3 ) {
|
||||
$ret = substr( $locale, 0, strrpos( $locale, '-' ) );
|
||||
if ( false !== $ret ) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 'en';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/**
|
||||
* Trustly payment method.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
|
||||
|
||||
/**
|
||||
* Class TrustlyPaymentMethod
|
||||
*/
|
||||
class TrustlyPaymentMethod extends AbstractPaymentMethodType {
|
||||
|
||||
/**
|
||||
* The URL of this module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The assets version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* TrustlyGateway WC gateway.
|
||||
*
|
||||
* @var TrustlyGateway
|
||||
*/
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* TrustlyPaymentMethod constructor.
|
||||
*
|
||||
* @param string $module_url The URL of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param TrustlyGateway $gateway Trustly WC gateway.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
string $version,
|
||||
TrustlyGateway $gateway
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->gateway = $gateway;
|
||||
|
||||
$this->name = TrustlyGateway::ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initialize() {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function is_active() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_script_handles() {
|
||||
wp_register_script(
|
||||
'ppcp-trustly-payment-method',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/trustly-payment-method.js',
|
||||
array(),
|
||||
$this->version,
|
||||
true
|
||||
);
|
||||
|
||||
return array( 'ppcp-trustly-payment-method' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_data() {
|
||||
return array(
|
||||
'id' => $this->name,
|
||||
'title' => $this->gateway->title,
|
||||
'description' => $this->gateway->description,
|
||||
'icon' => esc_url( 'https://www.paypalobjects.com/images/checkout/alternative_payments/paypal_trustly_color.svg' ),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
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: {
|
||||
'bancontact-payment-method': path.resolve(
|
||||
'./resources/js/bancontact-payment-method.js'
|
||||
),
|
||||
'blik-payment-method': path.resolve(
|
||||
'./resources/js/blik-payment-method.js'
|
||||
),
|
||||
'eps-payment-method': path.resolve(
|
||||
'./resources/js/eps-payment-method.js'
|
||||
),
|
||||
'ideal-payment-method': path.resolve(
|
||||
'./resources/js/ideal-payment-method.js'
|
||||
),
|
||||
'mybank-payment-method': path.resolve(
|
||||
'./resources/js/mybank-payment-method.js'
|
||||
),
|
||||
'p24-payment-method': path.resolve(
|
||||
'./resources/js/p24-payment-method.js'
|
||||
),
|
||||
'trustly-payment-method': path.resolve(
|
||||
'./resources/js/trustly-payment-method.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' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
2247
modules/ppcp-local-alternative-payment-methods/yarn.lock
Normal file
2247
modules/ppcp-local-alternative-payment-methods/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\OrderTracking;
|
||||
|
||||
use WooCommerce\PayPalCommerce\OrderTracking\Integration\DhlShipmentIntegration;
|
||||
use WooCommerce\PayPalCommerce\OrderTracking\Integration\GermanizedShipmentIntegration;
|
||||
use WooCommerce\PayPalCommerce\OrderTracking\Integration\ShipmentTrackingIntegration;
|
||||
use WooCommerce\PayPalCommerce\OrderTracking\Integration\ShipStationIntegration;
|
||||
|
@ -118,6 +119,7 @@ return array(
|
|||
$is_gzd_active = $container->get( 'compat.gzd.is_supported_plugin_version_active' );
|
||||
$is_wc_shipment_active = $container->get( 'compat.wc_shipment_tracking.is_supported_plugin_version_active' );
|
||||
$is_yith_ywot_active = $container->get( 'compat.ywot.is_supported_plugin_version_active' );
|
||||
$is_dhl_de_active = $container->get( 'compat.dhl.is_supported_plugin_version_active' );
|
||||
$is_ship_station_active = $container->get( 'compat.shipstation.is_supported_plugin_version_active' );
|
||||
$is_wc_shipping_tax_active = $container->get( 'compat.wc_shipping_tax.is_supported_plugin_version_active' );
|
||||
|
||||
|
@ -135,6 +137,10 @@ return array(
|
|||
$integrations[] = new YithShipmentIntegration( $shipment_factory, $logger, $endpoint );
|
||||
}
|
||||
|
||||
if ( $is_dhl_de_active ) {
|
||||
$integrations[] = new DhlShipmentIntegration( $shipment_factory, $logger, $endpoint );
|
||||
}
|
||||
|
||||
if ( $is_ship_station_active ) {
|
||||
$integrations[] = new ShipStationIntegration( $shipment_factory, $logger, $endpoint );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
/**
|
||||
* The Shipment integration for DHL Shipping Germany for WooCommerce plugin.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\OrderTracking\Integration
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\OrderTracking\Integration;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\Compat\Integration;
|
||||
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
|
||||
use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentFactoryInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use function WooCommerce\PayPalCommerce\Api\ppcp_get_paypal_order;
|
||||
|
||||
/**
|
||||
* Class DhlShipmentIntegration
|
||||
*/
|
||||
class DhlShipmentIntegration implements Integration {
|
||||
|
||||
use TransactionIdHandlingTrait;
|
||||
|
||||
/**
|
||||
* The shipment factory.
|
||||
*
|
||||
* @var ShipmentFactoryInterface
|
||||
*/
|
||||
protected $shipment_factory;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* The order tracking endpoint.
|
||||
*
|
||||
* @var OrderTrackingEndpoint
|
||||
*/
|
||||
protected $endpoint;
|
||||
|
||||
/**
|
||||
* The DhlShipmentIntegration constructor.
|
||||
*
|
||||
* @param ShipmentFactoryInterface $shipment_factory The shipment factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param OrderTrackingEndpoint $endpoint The order tracking endpoint.
|
||||
*/
|
||||
public function __construct(
|
||||
ShipmentFactoryInterface $shipment_factory,
|
||||
LoggerInterface $logger,
|
||||
OrderTrackingEndpoint $endpoint
|
||||
) {
|
||||
$this->shipment_factory = $shipment_factory;
|
||||
$this->logger = $logger;
|
||||
$this->endpoint = $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function integrate(): void {
|
||||
add_action(
|
||||
'pr_save_dhl_label_tracking',
|
||||
function( int $order_id, array $tracking_details ) {
|
||||
try {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
|
||||
$tracking_number = $tracking_details['tracking_number'];
|
||||
$carrier = $tracking_details['carrier'];
|
||||
|
||||
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ppcp_shipment = $this->shipment_factory->create_shipment(
|
||||
$order_id,
|
||||
$capture_id,
|
||||
$tracking_number,
|
||||
'SHIPPED',
|
||||
'DE_DHL',
|
||||
$carrier,
|
||||
array()
|
||||
);
|
||||
|
||||
$tracking_information = $this->endpoint->get_tracking_information( $order_id, $tracking_number );
|
||||
|
||||
$tracking_information
|
||||
? $this->endpoint->update_tracking_information( $ppcp_shipment, $order_id )
|
||||
: $this->endpoint->add_tracking_information( $ppcp_shipment, $order_id );
|
||||
|
||||
} catch ( Exception $exception ) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
600,
|
||||
2
|
||||
);
|
||||
}
|
||||
}
|
230
modules/ppcp-save-payment-methods/resources/js/Configuration.js
Normal file
230
modules/ppcp-save-payment-methods/resources/js/Configuration.js
Normal file
|
@ -0,0 +1,230 @@
|
|||
import {
|
||||
getCurrentPaymentMethod,
|
||||
PaymentMethods,
|
||||
} from '../../../ppcp-button/resources/js/modules/Helper/CheckoutMethodState';
|
||||
|
||||
export function buttonConfiguration( ppcp_add_payment_method, errorHandler ) {
|
||||
return {
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax.create_setup_token.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax.create_setup_token
|
||||
.nonce,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.data.id ) {
|
||||
return result.data.id;
|
||||
}
|
||||
|
||||
errorHandler.message( ppcp_add_payment_method.error_message );
|
||||
},
|
||||
onApprove: async ( { vaultSetupToken } ) => {
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax.create_payment_token.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax.create_payment_token
|
||||
.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.success === true ) {
|
||||
window.location.href =
|
||||
ppcp_add_payment_method.payment_methods_page;
|
||||
return;
|
||||
}
|
||||
|
||||
errorHandler.message( ppcp_add_payment_method.error_message );
|
||||
},
|
||||
onError: ( error ) => {
|
||||
console.error( error );
|
||||
errorHandler.message( ppcp_add_payment_method.error_message );
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function cardFieldsConfiguration(
|
||||
ppcp_add_payment_method,
|
||||
errorHandler
|
||||
) {
|
||||
return {
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax.create_setup_token.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax.create_setup_token
|
||||
.nonce,
|
||||
payment_method: PaymentMethods.CARDS,
|
||||
verification_method:
|
||||
ppcp_add_payment_method.verification_method,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.data.id ) {
|
||||
return result.data.id;
|
||||
}
|
||||
|
||||
errorHandler.message( ppcp_add_payment_method.error_message );
|
||||
},
|
||||
onApprove: async ( { vaultSetupToken } ) => {
|
||||
const isFreeTrialCart =
|
||||
ppcp_add_payment_method?.is_free_trial_cart ?? false;
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax.create_payment_token.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax.create_payment_token
|
||||
.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
payment_method: PaymentMethods.CARDS,
|
||||
is_free_trial_cart: isFreeTrialCart,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.success === true ) {
|
||||
const context = ppcp_add_payment_method?.context ?? '';
|
||||
if ( context === 'checkout' ) {
|
||||
document.querySelector( '#place_order' ).click();
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
ppcp_add_payment_method.is_subscription_change_payment_page
|
||||
) {
|
||||
const subscriptionId =
|
||||
ppcp_add_payment_method.subscription_id_to_change_payment;
|
||||
if ( subscriptionId && result.data ) {
|
||||
const req = await fetch(
|
||||
ppcp_add_payment_method.ajax
|
||||
.subscription_change_payment_method.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax
|
||||
.subscription_change_payment_method
|
||||
.nonce,
|
||||
subscription_id: subscriptionId,
|
||||
payment_method: getCurrentPaymentMethod(),
|
||||
wc_payment_token_id: result.data,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const res = await req.json();
|
||||
if ( res.success === true ) {
|
||||
window.location.href = `${ ppcp_add_payment_method.view_subscriptions_page }/${ subscriptionId }`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href =
|
||||
ppcp_add_payment_method.payment_methods_page;
|
||||
return;
|
||||
}
|
||||
|
||||
this.errorHandler.message( ppcp_add_payment_method.error_message );
|
||||
},
|
||||
onError: ( error ) => {
|
||||
console.error( error );
|
||||
errorHandler.message( ppcp_add_payment_method.error_message );
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function addPaymentMethodConfiguration( ppcp_add_payment_method ) {
|
||||
return {
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax.create_setup_token.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax.create_setup_token
|
||||
.nonce,
|
||||
payment_method: getCurrentPaymentMethod(),
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.data.id ) {
|
||||
return result.data.id;
|
||||
}
|
||||
|
||||
console.error( result );
|
||||
},
|
||||
onApprove: async ( { vaultSetupToken } ) => {
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax.create_payment_token_for_guest
|
||||
.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax
|
||||
.create_payment_token_for_guest.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.success === true ) {
|
||||
document.querySelector( '#place_order' ).click();
|
||||
return;
|
||||
}
|
||||
|
||||
console.error( result );
|
||||
},
|
||||
onError: ( error ) => {
|
||||
console.error( error );
|
||||
},
|
||||
};
|
||||
}
|
|
@ -4,303 +4,108 @@ import {
|
|||
PaymentMethods,
|
||||
} from '../../../ppcp-button/resources/js/modules/Helper/CheckoutMethodState';
|
||||
import { loadScript } from '@paypal/paypal-js';
|
||||
import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler';
|
||||
import { buttonConfiguration, cardFieldsConfiguration } from './Configuration';
|
||||
import { renderFields } from '../../../ppcp-card-fields/resources/js/Render';
|
||||
import {
|
||||
setVisible,
|
||||
setVisibleByClass,
|
||||
} from '../../../ppcp-button/resources/js/modules/Helper/Hiding';
|
||||
import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler';
|
||||
import { cardFieldStyles } from '../../../ppcp-button/resources/js/modules/Helper/CardFieldsHelper';
|
||||
|
||||
const errorHandler = new ErrorHandler(
|
||||
ppcp_add_payment_method.labels.error.generic,
|
||||
document.querySelector( '.woocommerce-notices-wrapper' )
|
||||
);
|
||||
|
||||
const init = () => {
|
||||
setVisibleByClass(
|
||||
ORDER_BUTTON_SELECTOR,
|
||||
getCurrentPaymentMethod() !== PaymentMethods.PAYPAL,
|
||||
'ppcp-hidden'
|
||||
);
|
||||
setVisible(
|
||||
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`,
|
||||
getCurrentPaymentMethod() === PaymentMethods.PAYPAL
|
||||
);
|
||||
};
|
||||
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
jQuery( document.body ).on(
|
||||
'click init_add_payment_method',
|
||||
'.payment_methods input.input-radio',
|
||||
function () {
|
||||
init();
|
||||
}
|
||||
);
|
||||
|
||||
if ( ppcp_add_payment_method.is_subscription_change_payment_page ) {
|
||||
const saveToAccount = document.querySelector(
|
||||
'#wc-ppcp-credit-card-gateway-new-payment-method'
|
||||
);
|
||||
if ( saveToAccount ) {
|
||||
saveToAccount.checked = true;
|
||||
saveToAccount.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout( () => {
|
||||
loadScript( {
|
||||
clientId: ppcp_add_payment_method.client_id,
|
||||
merchantId: ppcp_add_payment_method.merchant_id,
|
||||
dataUserIdToken: ppcp_add_payment_method.id_token,
|
||||
components: 'buttons,card-fields',
|
||||
} ).then( ( paypal ) => {
|
||||
errorHandler.clear();
|
||||
|
||||
const paypalButtonContainer = document.querySelector(
|
||||
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`
|
||||
);
|
||||
if ( paypalButtonContainer ) {
|
||||
paypal
|
||||
.Buttons( {
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax.create_setup_token
|
||||
.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax
|
||||
.create_setup_token.nonce,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.data.id ) {
|
||||
return result.data.id;
|
||||
}
|
||||
|
||||
errorHandler.message(
|
||||
ppcp_add_payment_method.error_message
|
||||
);
|
||||
},
|
||||
onApprove: async ( { vaultSetupToken } ) => {
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax
|
||||
.create_payment_token.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax
|
||||
.create_payment_token.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.success === true ) {
|
||||
window.location.href =
|
||||
ppcp_add_payment_method.payment_methods_page;
|
||||
return;
|
||||
}
|
||||
|
||||
errorHandler.message(
|
||||
ppcp_add_payment_method.error_message
|
||||
);
|
||||
},
|
||||
onError: ( error ) => {
|
||||
console.error( error );
|
||||
errorHandler.message(
|
||||
ppcp_add_payment_method.error_message
|
||||
);
|
||||
},
|
||||
} )
|
||||
.render(
|
||||
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`
|
||||
);
|
||||
( function ( { ppcp_add_payment_method, jQuery } ) {
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
jQuery( document.body ).on(
|
||||
'click init_add_payment_method',
|
||||
'.payment_methods input.input-radio',
|
||||
function () {
|
||||
setVisibleByClass(
|
||||
ORDER_BUTTON_SELECTOR,
|
||||
getCurrentPaymentMethod() !== PaymentMethods.PAYPAL,
|
||||
'ppcp-hidden'
|
||||
);
|
||||
setVisible(
|
||||
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`,
|
||||
getCurrentPaymentMethod() === PaymentMethods.PAYPAL
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const cardField = paypal.CardFields( {
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax.create_setup_token
|
||||
.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax
|
||||
.create_setup_token.nonce,
|
||||
payment_method: PaymentMethods.CARDS,
|
||||
verification_method:
|
||||
ppcp_add_payment_method.verification_method,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
// TODO move to wc subscriptions module
|
||||
if ( ppcp_add_payment_method.is_subscription_change_payment_page ) {
|
||||
const saveToAccount = document.querySelector(
|
||||
'#wc-ppcp-credit-card-gateway-new-payment-method'
|
||||
);
|
||||
if ( saveToAccount ) {
|
||||
saveToAccount.checked = true;
|
||||
saveToAccount.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.data.id ) {
|
||||
return result.data.id;
|
||||
}
|
||||
setTimeout( () => {
|
||||
loadScript( {
|
||||
clientId: ppcp_add_payment_method.client_id,
|
||||
merchantId: ppcp_add_payment_method.merchant_id,
|
||||
dataUserIdToken: ppcp_add_payment_method.id_token,
|
||||
components: 'buttons,card-fields',
|
||||
} ).then( ( paypal ) => {
|
||||
const errorHandler = new ErrorHandler(
|
||||
ppcp_add_payment_method.labels.error.generic,
|
||||
document.querySelector( '.woocommerce-notices-wrapper' )
|
||||
);
|
||||
errorHandler.clear();
|
||||
|
||||
errorHandler.message(
|
||||
ppcp_add_payment_method.error_message
|
||||
);
|
||||
},
|
||||
onApprove: async ( { vaultSetupToken } ) => {
|
||||
const response = await fetch(
|
||||
ppcp_add_payment_method.ajax.create_payment_token
|
||||
.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax
|
||||
.create_payment_token.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
payment_method: PaymentMethods.CARDS,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
const paypalButtonContainer = document.querySelector(
|
||||
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.success === true ) {
|
||||
if ( paypalButtonContainer ) {
|
||||
paypal
|
||||
.Buttons(
|
||||
buttonConfiguration(
|
||||
ppcp_add_payment_method,
|
||||
errorHandler
|
||||
)
|
||||
)
|
||||
.render(
|
||||
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`
|
||||
);
|
||||
}
|
||||
|
||||
const cardFields = paypal.CardFields(
|
||||
cardFieldsConfiguration(
|
||||
ppcp_add_payment_method,
|
||||
errorHandler
|
||||
)
|
||||
);
|
||||
|
||||
if ( cardFields.isEligible() ) {
|
||||
renderFields( cardFields );
|
||||
}
|
||||
|
||||
document
|
||||
.querySelector( '#place_order' )
|
||||
?.addEventListener( 'click', ( event ) => {
|
||||
const cardPaymentToken = document.querySelector(
|
||||
'input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked'
|
||||
)?.value;
|
||||
if (
|
||||
ppcp_add_payment_method.is_subscription_change_payment_page
|
||||
getCurrentPaymentMethod() !==
|
||||
'ppcp-credit-card-gateway' ||
|
||||
( cardPaymentToken && cardPaymentToken !== 'new' )
|
||||
) {
|
||||
const subscriptionId =
|
||||
ppcp_add_payment_method.subscription_id_to_change_payment;
|
||||
if ( subscriptionId && result.data ) {
|
||||
const req = await fetch(
|
||||
ppcp_add_payment_method.ajax
|
||||
.subscription_change_payment_method
|
||||
.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: ppcp_add_payment_method.ajax
|
||||
.subscription_change_payment_method
|
||||
.nonce,
|
||||
subscription_id: subscriptionId,
|
||||
payment_method:
|
||||
getCurrentPaymentMethod(),
|
||||
wc_payment_token_id: result.data,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const res = await req.json();
|
||||
if ( res.success === true ) {
|
||||
window.location.href = `${ ppcp_add_payment_method.view_subscriptions_page }/${ subscriptionId }`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href =
|
||||
ppcp_add_payment_method.payment_methods_page;
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
|
||||
errorHandler.message(
|
||||
ppcp_add_payment_method.error_message
|
||||
);
|
||||
},
|
||||
onError: ( error ) => {
|
||||
console.error( error );
|
||||
errorHandler.message(
|
||||
ppcp_add_payment_method.error_message
|
||||
);
|
||||
},
|
||||
} );
|
||||
|
||||
if ( cardField.isEligible() ) {
|
||||
const nameField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-name'
|
||||
);
|
||||
if ( nameField ) {
|
||||
const styles = cardFieldStyles( nameField );
|
||||
cardField
|
||||
.NameField( { style: { input: styles } } )
|
||||
.render( nameField.parentNode );
|
||||
nameField.hidden = true;
|
||||
}
|
||||
|
||||
const numberField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-number'
|
||||
);
|
||||
if ( numberField ) {
|
||||
const styles = cardFieldStyles( numberField );
|
||||
cardField
|
||||
.NumberField( { style: { input: styles } } )
|
||||
.render( numberField.parentNode );
|
||||
numberField.hidden = true;
|
||||
}
|
||||
|
||||
const expiryField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-expiry'
|
||||
);
|
||||
if ( expiryField ) {
|
||||
const styles = cardFieldStyles( expiryField );
|
||||
cardField
|
||||
.ExpiryField( { style: { input: styles } } )
|
||||
.render( expiryField.parentNode );
|
||||
expiryField.hidden = true;
|
||||
}
|
||||
|
||||
const cvvField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-cvc'
|
||||
);
|
||||
if ( cvvField ) {
|
||||
const styles = cardFieldStyles( cvvField );
|
||||
cardField
|
||||
.CVVField( { style: { input: styles } } )
|
||||
.render( cvvField.parentNode );
|
||||
cvvField.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
document
|
||||
.querySelector( '#place_order' )
|
||||
?.addEventListener( 'click', ( event ) => {
|
||||
const cardPaymentToken = document.querySelector(
|
||||
'input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked'
|
||||
)?.value;
|
||||
if (
|
||||
getCurrentPaymentMethod() !==
|
||||
'ppcp-credit-card-gateway' ||
|
||||
( cardPaymentToken && cardPaymentToken !== 'new' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
cardField.submit().catch( ( error ) => {
|
||||
console.error( error );
|
||||
cardFields.submit().catch( ( error ) => {
|
||||
console.error( error );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
}, 1000 );
|
||||
} );
|
||||
}, 1000 );
|
||||
} );
|
||||
} )( {
|
||||
ppcp_add_payment_method: window.ppcp_add_payment_method,
|
||||
jQuery: window.jQuery,
|
||||
} );
|
||||
|
|
|
@ -115,6 +115,11 @@ class CreatePaymentToken implements EndpointInterface {
|
|||
|
||||
if ( isset( $result->payment_source->card ) ) {
|
||||
$wc_token_id = $this->wc_payment_tokens->create_payment_token_card( $current_user_id, $result );
|
||||
|
||||
$is_free_trial_cart = $data['is_free_trial_cart'] ?? '';
|
||||
if ( $is_free_trial_cart === '1' ) {
|
||||
WC()->session->set( 'ppcp_card_payment_token_for_free_trial', $wc_token_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
use WooCommerce\PayPalCommerce\Applepay\ApplePayGateway;
|
||||
|
||||
return array(
|
||||
'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
|
||||
|
@ -198,6 +199,7 @@ return array(
|
|||
Settings::PAY_LATER_TAB_ID,
|
||||
AxoGateway::ID,
|
||||
GooglePayGateway::ID,
|
||||
ApplePayGateway::ID,
|
||||
),
|
||||
true
|
||||
);
|
||||
|
@ -220,6 +222,7 @@ return array(
|
|||
Settings::PAY_LATER_TAB_ID,
|
||||
Settings::CONNECTION_TAB_ID,
|
||||
GooglePayGateway::ID,
|
||||
ApplePayGateway::ID,
|
||||
),
|
||||
true
|
||||
);
|
||||
|
@ -1411,10 +1414,10 @@ return array(
|
|||
return $label;
|
||||
},
|
||||
'wcgateway.enable-dcc-url-sandbox' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://www.sandbox.paypal.com/bizsignup/entry/product/ppcp';
|
||||
return 'https://www.sandbox.paypal.com/bizsignup/entry?product=ppcp';
|
||||
},
|
||||
'wcgateway.enable-dcc-url-live' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://www.paypal.com/bizsignup/entry/product/ppcp';
|
||||
return 'https://www.paypal.com/bizsignup/entry?product=ppcp';
|
||||
},
|
||||
'wcgateway.enable-pui-url-sandbox' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://www.sandbox.paypal.com/bizsignup/entry?country.x=DE&product=payment_methods&capabilities=PAY_UPON_INVOICE';
|
||||
|
|
|
@ -426,12 +426,42 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
WC()->session->set( 'ppcp_card_payment_token_for_free_trial', null );
|
||||
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new GatewayGenericException( new Exception( 'WC order was not found.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
$guest_card_payment_for_free_trial = WC()->session->get( 'ppcp_guest_payment_for_free_trial' ) ?? null;
|
||||
WC()->session->get( 'ppcp_guest_payment_for_free_trial', null );
|
||||
if ( $guest_card_payment_for_free_trial ) {
|
||||
$customer_id = $guest_card_payment_for_free_trial->customer->id ?? '';
|
||||
if ( $customer_id ) {
|
||||
update_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', $customer_id );
|
||||
}
|
||||
|
||||
if ( isset( $guest_card_payment_for_free_trial->payment_source->card ) ) {
|
||||
$this->wc_payment_tokens->create_payment_token_card( $wc_order->get_customer_id(), $guest_card_payment_for_free_trial );
|
||||
|
||||
$wc_order->payment_complete();
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
|
||||
$card_payment_token_for_free_trial = WC()->session->get( 'ppcp_card_payment_token_for_free_trial' ) ?? null;
|
||||
WC()->session->set( 'ppcp_card_payment_token_for_free_trial', null );
|
||||
if ( $card_payment_token_for_free_trial ) {
|
||||
$tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id() );
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->get_id() === (int) $card_payment_token_for_free_trial ) {
|
||||
$wc_order->payment_complete();
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$card_payment_token_id = wc_clean( wp_unslash( $_POST['wc-ppcp-credit-card-gateway-payment-token'] ?? '' ) );
|
||||
|
||||
|
|
|
@ -118,18 +118,15 @@ class Settings implements ContainerInterface {
|
|||
* Stores the settings to the database.
|
||||
*/
|
||||
public function persist() {
|
||||
|
||||
return update_option( self::KEY, $this->settings );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the settings.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function load(): bool {
|
||||
|
||||
if ( $this->settings ) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"install:modules:ppcp-paylater-configurator": "cd modules/ppcp-paylater-configurator && yarn install",
|
||||
"install:modules:ppcp-button": "cd modules/ppcp-button && yarn install",
|
||||
"install:modules:ppcp-googlepay": "cd modules/ppcp-googlepay && yarn install",
|
||||
"install:modules:ppcp-local-alternative-payment-methods": "cd modules/ppcp-local-alternative-payment-methods && yarn install",
|
||||
"install:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn install",
|
||||
"install:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn install",
|
||||
"install:modules:ppcp-order-tracking": "cd modules/ppcp-order-tracking && yarn install",
|
||||
|
@ -21,6 +22,7 @@
|
|||
"install:modules:ppcp-save-payment-methods": "cd modules/ppcp-save-payment-methods && yarn install",
|
||||
"install:modules:ppcp-axo": "cd modules/ppcp-axo && yarn install",
|
||||
"install:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn install",
|
||||
"install:modules:ppcp-card-fields": "cd modules/ppcp-card-fields && yarn install",
|
||||
"install:modules:ppcp-compat": "cd modules/ppcp-compat && yarn install",
|
||||
"install:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn install",
|
||||
"build:modules:ppcp-applepay": "cd modules/ppcp-applepay && yarn run build",
|
||||
|
@ -30,6 +32,7 @@
|
|||
"build:modules:ppcp-paylater-configurator": "cd modules/ppcp-paylater-configurator && yarn run build",
|
||||
"build:modules:ppcp-button": "cd modules/ppcp-button && yarn run build",
|
||||
"build:modules:ppcp-googlepay": "cd modules/ppcp-googlepay && yarn run build",
|
||||
"build:modules:ppcp-local-alternative-payment-methods": "cd modules/ppcp-local-alternative-payment-methods && 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",
|
||||
"build:modules:ppcp-order-tracking": "cd modules/ppcp-order-tracking && yarn run build",
|
||||
|
@ -37,6 +40,7 @@
|
|||
"build:modules:ppcp-axo": "cd modules/ppcp-axo && yarn run build",
|
||||
"build:modules:ppcp-paypal-subscriptions": "cd modules/ppcp-paypal-subscriptions && yarn run build",
|
||||
"build:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn run build",
|
||||
"build:modules:ppcp-card-fields": "cd modules/ppcp-card-fields && yarn run build",
|
||||
"build:modules:ppcp-compat": "cd modules/ppcp-compat && yarn run build",
|
||||
"build:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn run build",
|
||||
"build:modules": "run-p build:modules:*",
|
||||
|
@ -47,6 +51,7 @@
|
|||
"watch:modules:ppcp-paylater-configurator": "cd modules/ppcp-paylater-configurator && yarn run watch",
|
||||
"watch:modules:ppcp-button": "cd modules/ppcp-button && yarn run watch",
|
||||
"watch:modules:ppcp-googlepay": "cd modules/ppcp-googlepay && yarn run watch",
|
||||
"watch:modules:ppcp-local-alternative-payment-methods": "cd modules/ppcp-local-alternative-payment-methods && 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",
|
||||
"watch:modules:ppcp-order-tracking": "cd modules/ppcp-order-tracking && yarn run watch",
|
||||
|
@ -54,6 +59,7 @@
|
|||
"watch:modules:ppcp-save-payment-methods": "cd modules/ppcp-save-payment-methods && yarn run watch",
|
||||
"watch:modules:ppcp-axo": "cd modules/ppcp-axo && yarn run watch",
|
||||
"watch:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn run watch",
|
||||
"watch:modules:ppcp-card-fields": "cd modules/ppcp-card-fields && yarn run watch",
|
||||
"watch:modules:ppcp-compat": "cd modules/ppcp-compat && yarn run watch",
|
||||
"watch:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn run watch",
|
||||
"watch:modules": "run-p watch:modules:*",
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<file name=".psalm/wcblocks.php"/>
|
||||
<file name=".psalm/wcs.php"/>
|
||||
<file name=".psalm/gzd.php"/>
|
||||
<file name=".psalm/wc-bookings.php"/>
|
||||
<file name=".psalm/wpcli.php"/>
|
||||
<file name="vendor/php-stubs/wordpress-stubs/wordpress-stubs.php"/>
|
||||
<file name="vendor/php-stubs/woocommerce-stubs/woocommerce-stubs.php"/>
|
||||
|
|
|
@ -1,78 +1,78 @@
|
|||
// @ts-check
|
||||
const { defineConfig, devices } = require('@playwright/test');
|
||||
const { defineConfig, devices } = require( '@playwright/test' );
|
||||
|
||||
require('dotenv').config({ path: '.env' });
|
||||
require( 'dotenv' ).config( { path: '.env' } );
|
||||
|
||||
/**
|
||||
* @see https://playwright.dev/docs/test-configuration
|
||||
*/
|
||||
module.exports = defineConfig({
|
||||
timeout: 60000,
|
||||
testDir: './tests',
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: [
|
||||
[process.env.CI ? 'github' : 'list'],
|
||||
['html', {open: 'never'}],
|
||||
],
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: process.env.BASEURL,
|
||||
ignoreHTTPSErrors: true,
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
module.exports = defineConfig( {
|
||||
timeout: 30000,
|
||||
testDir: './tests',
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: false,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !! process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: [
|
||||
[ process.env.CI ? 'github' : 'list' ],
|
||||
[ 'html', { open: 'never' } ],
|
||||
],
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: process.env.BASEURL,
|
||||
ignoreHTTPSErrors: true,
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices[ 'Desktop Chrome' ] },
|
||||
},
|
||||
|
||||
// {
|
||||
// name: 'firefox',
|
||||
// use: { ...devices['Desktop Firefox'] },
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// name: 'webkit',
|
||||
// use: { ...devices['Desktop Safari'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'firefox',
|
||||
// use: { ...devices['Desktop Firefox'] },
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// name: 'webkit',
|
||||
// use: { ...devices['Desktop Safari'] },
|
||||
// },
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
// webServer: {
|
||||
// command: 'npm run start',
|
||||
// url: 'http://127.0.0.1:3000',
|
||||
// reuseExistingServer: !process.env.CI,
|
||||
// },
|
||||
});
|
||||
/* Run your local dev server before starting the tests */
|
||||
// webServer: {
|
||||
// command: 'npm run start',
|
||||
// url: 'http://127.0.0.1:3000',
|
||||
// reuseExistingServer: !process.env.CI,
|
||||
// },
|
||||
} );
|
||||
|
|
76
tests/Playwright/tests/apms-place-order.spec.js
Normal file
76
tests/Playwright/tests/apms-place-order.spec.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
const { test, expect } = require( '@playwright/test' );
|
||||
const {
|
||||
fillCheckoutForm,
|
||||
expectOrderReceivedPage,
|
||||
acceptTerms,
|
||||
} = require( './utils/checkout' );
|
||||
const {
|
||||
openPaypalPopup,
|
||||
completePaypalPayment,
|
||||
} = require( './utils/paypal-popup' );
|
||||
|
||||
const { PRODUCT_ID, CHECKOUT_URL, CART_URL, APM_ID } = process.env;
|
||||
|
||||
async function expectContinuation( page ) {
|
||||
await expect(
|
||||
page.locator( '#payment_method_ppcp-gateway' )
|
||||
).toBeChecked();
|
||||
|
||||
await expect( page.locator( '.component-frame' ) ).toHaveCount( 0 );
|
||||
}
|
||||
|
||||
async function completeContinuation( page ) {
|
||||
await expectContinuation( page );
|
||||
|
||||
await Promise.all( [
|
||||
page.waitForNavigation(),
|
||||
page.locator( '#place_order' ).click(),
|
||||
] );
|
||||
}
|
||||
|
||||
test( 'PayPal APM button place order', async ( { page } ) => {
|
||||
await page.goto( CART_URL + '?add-to-cart=' + PRODUCT_ID );
|
||||
|
||||
await page.goto( CHECKOUT_URL );
|
||||
|
||||
await fillCheckoutForm( page );
|
||||
|
||||
const popup = await openPaypalPopup( page, { fundingSource: APM_ID } );
|
||||
|
||||
await popup.getByText( 'Continue', { exact: true } ).click();
|
||||
await completePaypalPayment( popup, {
|
||||
selector: '[name="Successful"]',
|
||||
} );
|
||||
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
||||
|
||||
test( 'PayPal APM button place order when redirect fails', async ( {
|
||||
page,
|
||||
} ) => {
|
||||
await page.goto( CART_URL + '?add-to-cart=' + PRODUCT_ID );
|
||||
|
||||
await page.goto( CHECKOUT_URL );
|
||||
|
||||
await fillCheckoutForm( page );
|
||||
|
||||
await page.evaluate( 'PayPalCommerceGateway.ajax.approve_order = null' );
|
||||
|
||||
const popup = await openPaypalPopup( page, { fundingSource: APM_ID } );
|
||||
|
||||
await popup.getByText( 'Continue', { exact: true } ).click();
|
||||
await completePaypalPayment( popup, {
|
||||
selector: '[name="Successful"]',
|
||||
} );
|
||||
|
||||
await expect( page.locator( '.woocommerce-error' ) ).toBeVisible();
|
||||
|
||||
await page.reload();
|
||||
await expectContinuation( page );
|
||||
|
||||
await acceptTerms( page );
|
||||
|
||||
await completeContinuation( page );
|
||||
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
109
tests/Playwright/tests/blocks-place-order.spec.js
Normal file
109
tests/Playwright/tests/blocks-place-order.spec.js
Normal file
|
@ -0,0 +1,109 @@
|
|||
const { expect, test } = require( '@playwright/test' );
|
||||
const { serverExec } = require( './utils/server' );
|
||||
const {
|
||||
openPaypalPopup,
|
||||
loginIntoPaypal,
|
||||
completePaypalPayment,
|
||||
waitForPaypalShippingList,
|
||||
} = require( './utils/paypal-popup' );
|
||||
const { expectOrderReceivedPage } = require( './utils/checkout' );
|
||||
|
||||
const {
|
||||
PRODUCT_ID,
|
||||
BLOCK_CHECKOUT_URL,
|
||||
BLOCK_CHECKOUT_PAGE_ID,
|
||||
BLOCK_CART_URL,
|
||||
} = process.env;
|
||||
|
||||
async function completeBlockContinuation( page ) {
|
||||
await expect(
|
||||
page.locator( '#radio-control-wc-payment-method-options-ppcp-gateway' )
|
||||
).toBeChecked();
|
||||
|
||||
await expect( page.locator( '.component-frame' ) ).toHaveCount( 0 );
|
||||
|
||||
await Promise.all(
|
||||
page.waitForNavigation(),
|
||||
page
|
||||
.locator( '.wc-block-components-checkout-place-order-button' )
|
||||
.click()
|
||||
);
|
||||
}
|
||||
|
||||
test.beforeAll( async ( { browser } ) => {
|
||||
await serverExec(
|
||||
'wp option update woocommerce_checkout_page_id ' +
|
||||
BLOCK_CHECKOUT_PAGE_ID
|
||||
);
|
||||
await serverExec(
|
||||
'wp pcp settings update blocks_final_review_enabled true'
|
||||
);
|
||||
} );
|
||||
|
||||
test( 'PayPal express block checkout', async ( { page } ) => {
|
||||
await page.goto( '?add-to-cart=' + PRODUCT_ID );
|
||||
|
||||
await page.goto( BLOCK_CHECKOUT_URL );
|
||||
|
||||
const popup = await openPaypalPopup( page );
|
||||
|
||||
await loginIntoPaypal( popup );
|
||||
|
||||
await completePaypalPayment( popup );
|
||||
|
||||
await completeBlockContinuation( page );
|
||||
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
||||
|
||||
test( 'PayPal express block cart', async ( { page } ) => {
|
||||
await page.goto( BLOCK_CART_URL + '?add-to-cart=' + PRODUCT_ID );
|
||||
|
||||
const popup = await openPaypalPopup( page );
|
||||
|
||||
await loginIntoPaypal( popup );
|
||||
|
||||
await completePaypalPayment( popup );
|
||||
|
||||
await completeBlockContinuation( page );
|
||||
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
||||
|
||||
test.describe( 'Without review', () => {
|
||||
test.beforeAll( async ( { browser } ) => {
|
||||
await serverExec(
|
||||
'wp pcp settings update blocks_final_review_enabled false'
|
||||
);
|
||||
} );
|
||||
|
||||
test( 'PayPal express block checkout', async ( { page } ) => {
|
||||
await page.goto( '?add-to-cart=' + PRODUCT_ID );
|
||||
|
||||
await page.goto( BLOCK_CHECKOUT_URL );
|
||||
|
||||
const popup = await openPaypalPopup( page );
|
||||
|
||||
await loginIntoPaypal( popup );
|
||||
|
||||
await waitForPaypalShippingList( popup );
|
||||
|
||||
await completePaypalPayment( popup );
|
||||
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
||||
|
||||
test( 'PayPal express block cart', async ( { page } ) => {
|
||||
await page.goto( BLOCK_CART_URL + '?add-to-cart=' + PRODUCT_ID );
|
||||
|
||||
const popup = await openPaypalPopup( page );
|
||||
|
||||
await loginIntoPaypal( popup );
|
||||
|
||||
await waitForPaypalShippingList( popup );
|
||||
|
||||
await completePaypalPayment( popup );
|
||||
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
||||
} );
|
97
tests/Playwright/tests/classic-place-order.spec.js
Normal file
97
tests/Playwright/tests/classic-place-order.spec.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
const { test, expect } = require( '@playwright/test' );
|
||||
const { serverExec } = require( './utils/server' );
|
||||
const {
|
||||
fillCheckoutForm,
|
||||
expectOrderReceivedPage,
|
||||
} = require( './utils/checkout' );
|
||||
const {
|
||||
openPaypalPopup,
|
||||
loginIntoPaypal,
|
||||
completePaypalPayment,
|
||||
} = require( './utils/paypal-popup' );
|
||||
|
||||
const {
|
||||
CREDIT_CARD_NUMBER,
|
||||
CREDIT_CARD_CVV,
|
||||
PRODUCT_URL,
|
||||
CHECKOUT_URL,
|
||||
CHECKOUT_PAGE_ID,
|
||||
} = process.env;
|
||||
|
||||
async function expectContinuation( page ) {
|
||||
await expect(
|
||||
page.locator( '#payment_method_ppcp-gateway' )
|
||||
).toBeChecked();
|
||||
|
||||
await expect( page.locator( '.component-frame' ) ).toHaveCount( 0 );
|
||||
}
|
||||
|
||||
async function completeContinuation( page ) {
|
||||
await expectContinuation( page );
|
||||
|
||||
await Promise.all( [
|
||||
page.waitForNavigation(),
|
||||
page.locator( '#place_order' ).click(),
|
||||
] );
|
||||
}
|
||||
|
||||
test.beforeAll( async ( { browser } ) => {
|
||||
await serverExec(
|
||||
'wp option update woocommerce_checkout_page_id ' + CHECKOUT_PAGE_ID
|
||||
);
|
||||
} );
|
||||
|
||||
test( 'PayPal button place order from Product page', async ( { page } ) => {
|
||||
await serverExec(
|
||||
'wp pcp settings update blocks_final_review_enabled true'
|
||||
);
|
||||
|
||||
await page.goto( PRODUCT_URL );
|
||||
|
||||
const popup = await openPaypalPopup( page );
|
||||
|
||||
await loginIntoPaypal( popup );
|
||||
|
||||
await completePaypalPayment( popup );
|
||||
|
||||
await fillCheckoutForm( page );
|
||||
|
||||
await completeContinuation( page );
|
||||
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
||||
|
||||
test( 'Advanced Credit and Debit Card place order from Checkout page', async ( {
|
||||
page,
|
||||
} ) => {
|
||||
await page.goto( PRODUCT_URL );
|
||||
await page.locator( '.single_add_to_cart_button' ).click();
|
||||
|
||||
await page.goto( CHECKOUT_URL );
|
||||
await fillCheckoutForm( page );
|
||||
|
||||
await page.click( 'text=Credit Cards' );
|
||||
|
||||
const expirationDate = await page
|
||||
.frameLocator( 'iframe[title="paypal_card_expiry_field"]' )
|
||||
.locator( 'input.card-field-expiry' );
|
||||
await expirationDate.click();
|
||||
await page.keyboard.type( '01/42' );
|
||||
|
||||
const creditCardNumber = await page
|
||||
.frameLocator( '[title="paypal_card_number_field"]' )
|
||||
.locator( '.card-field-number' );
|
||||
await creditCardNumber.fill( CREDIT_CARD_NUMBER );
|
||||
|
||||
const cvv = await page
|
||||
.frameLocator( '[title="paypal_card_cvv_field"]' )
|
||||
.locator( '.card-field-cvv' );
|
||||
await cvv.fill( CREDIT_CARD_CVV );
|
||||
|
||||
await Promise.all( [
|
||||
page.waitForNavigation(),
|
||||
page.locator( '.ppcp-dcc-order-button' ).click(),
|
||||
] );
|
||||
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
97
tests/Playwright/tests/free-trial-subscriptions.spec.js
Normal file
97
tests/Playwright/tests/free-trial-subscriptions.spec.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
const { test, expect } = require( '@playwright/test' );
|
||||
const { loginAsCustomer } = require( './utils/user' );
|
||||
const { openPaypalPopup, loginIntoPaypal } = require( './utils/paypal-popup' );
|
||||
const { serverExec } = require( './utils/server' );
|
||||
const { expectOrderReceivedPage } = require( './utils/checkout' );
|
||||
|
||||
const { CREDIT_CARD_NUMBER, CREDIT_CARD_CVV } = process.env;
|
||||
|
||||
test( 'PayPal logged-in user free trial subscription without payment token with shipping callback enabled', async ( {
|
||||
page,
|
||||
} ) => {
|
||||
await serverExec(
|
||||
'wp pcp settings update blocks_final_review_enabled false'
|
||||
);
|
||||
|
||||
await loginAsCustomer( page );
|
||||
await page.goto( '/product/free-trial' );
|
||||
await page.click( 'text=Sign up now' );
|
||||
await page.goto( '/classic-checkout' );
|
||||
|
||||
const popup = await openPaypalPopup( page );
|
||||
await loginIntoPaypal( popup );
|
||||
popup.locator( '#consentButton' ).click();
|
||||
|
||||
await page.waitForURL( '**/order-received/**' );
|
||||
} );
|
||||
|
||||
test( 'ACDC logged-in user free trial subscription without payment token', async ( {
|
||||
page,
|
||||
} ) => {
|
||||
await loginAsCustomer( page );
|
||||
await page.goto( '/product/free-trial' );
|
||||
await page.click( 'text=Sign up now' );
|
||||
await page.goto( '/classic-checkout' );
|
||||
|
||||
await page.click( 'text=Credit Cards' );
|
||||
|
||||
const creditCardNumber = await page
|
||||
.frameLocator( '[title="paypal_card_number_field"]' )
|
||||
.locator( '.card-field-number' );
|
||||
await creditCardNumber.fill( CREDIT_CARD_NUMBER );
|
||||
|
||||
const expirationDate = await page
|
||||
.frameLocator( 'iframe[title="paypal_card_expiry_field"]' )
|
||||
.locator( 'input.card-field-expiry' );
|
||||
await expirationDate.click();
|
||||
await page.keyboard.type( '01/42' );
|
||||
|
||||
const cvv = await page
|
||||
.frameLocator( '[title="paypal_card_cvv_field"]' )
|
||||
.locator( '.card-field-cvv' );
|
||||
await cvv.fill( CREDIT_CARD_CVV );
|
||||
|
||||
await Promise.all( [
|
||||
page.waitForNavigation(),
|
||||
page.locator( '.ppcp-dcc-order-button' ).click(),
|
||||
] );
|
||||
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
||||
|
||||
test( 'ACDC purchase free trial in Block checkout page as logged-in without saved card payments', async ( {
|
||||
page,
|
||||
} ) => {
|
||||
await loginAsCustomer( page );
|
||||
await page.goto( '/product/free-trial' );
|
||||
await page.click( 'text=Sign up now' );
|
||||
await page.goto( '/checkout' );
|
||||
|
||||
await page
|
||||
.locator(
|
||||
'#radio-control-wc-payment-method-options-ppcp-credit-card-gateway'
|
||||
)
|
||||
.click();
|
||||
|
||||
const expirationDate = await page
|
||||
.frameLocator( 'iframe[title="paypal_card_expiry_field"]' )
|
||||
.locator( 'input.card-field-expiry' );
|
||||
await expirationDate.click();
|
||||
await page.keyboard.type( '01/42' );
|
||||
|
||||
const creditCardNumber = await page
|
||||
.frameLocator( '[title="paypal_card_number_field"]' )
|
||||
.locator( '.card-field-number' );
|
||||
await creditCardNumber.fill( CREDIT_CARD_NUMBER );
|
||||
|
||||
const cvv = await page
|
||||
.frameLocator( '[title="paypal_card_cvv_field"]' )
|
||||
.locator( '.card-field-cvv' );
|
||||
await cvv.fill( CREDIT_CARD_CVV );
|
||||
|
||||
await page
|
||||
.locator( '.wc-block-components-checkout-place-order-button' )
|
||||
.click();
|
||||
|
||||
await page.waitForURL( '**/order-received/**' );
|
||||
} );
|
|
@ -1,207 +0,0 @@
|
|||
const {test, expect} = require('@playwright/test');
|
||||
const {serverExec} = require("./utils/server");
|
||||
const {fillCheckoutForm, expectOrderReceivedPage, acceptTerms} = require("./utils/checkout");
|
||||
const {openPaypalPopup, loginIntoPaypal, waitForPaypalShippingList, completePaypalPayment} = require("./utils/paypal-popup");
|
||||
|
||||
const {
|
||||
CREDIT_CARD_NUMBER,
|
||||
CREDIT_CARD_EXPIRATION,
|
||||
CREDIT_CARD_CVV,
|
||||
PRODUCT_URL,
|
||||
PRODUCT_ID,
|
||||
CHECKOUT_URL,
|
||||
CHECKOUT_PAGE_ID,
|
||||
CART_URL,
|
||||
BLOCK_CHECKOUT_URL,
|
||||
BLOCK_CHECKOUT_PAGE_ID,
|
||||
BLOCK_CART_URL,
|
||||
APM_ID,
|
||||
} = process.env;
|
||||
|
||||
async function completeBlockContinuation(page) {
|
||||
await expect(page.locator('#radio-control-wc-payment-method-options-ppcp-gateway')).toBeChecked();
|
||||
|
||||
await expect(page.locator('.component-frame')).toHaveCount(0);
|
||||
|
||||
await Promise.all(
|
||||
page.waitForNavigation(),
|
||||
page.locator('.wc-block-components-checkout-place-order-button').click(),
|
||||
);
|
||||
}
|
||||
|
||||
async function expectContinuation(page) {
|
||||
await expect(page.locator('#payment_method_ppcp-gateway')).toBeChecked();
|
||||
|
||||
await expect(page.locator('.component-frame')).toHaveCount(0);
|
||||
}
|
||||
|
||||
async function completeContinuation(page) {
|
||||
await expectContinuation(page);
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator('#place_order').click(),
|
||||
]);
|
||||
}
|
||||
|
||||
test.describe('Classic checkout', () => {
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
await serverExec('wp option update woocommerce_checkout_page_id ' + CHECKOUT_PAGE_ID);
|
||||
});
|
||||
|
||||
test('PayPal button place order from Product page', async ({page}) => {
|
||||
await page.goto(PRODUCT_URL);
|
||||
|
||||
const popup = await openPaypalPopup(page);
|
||||
|
||||
await loginIntoPaypal(popup);
|
||||
|
||||
await completePaypalPayment(popup);
|
||||
|
||||
await fillCheckoutForm(page);
|
||||
|
||||
await completeContinuation(page);
|
||||
|
||||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
|
||||
test('Advanced Credit and Debit Card place order from Checkout page', async ({page}) => {
|
||||
await page.goto(PRODUCT_URL);
|
||||
await page.locator('.single_add_to_cart_button').click();
|
||||
|
||||
await page.goto(CHECKOUT_URL);
|
||||
await fillCheckoutForm(page);
|
||||
|
||||
await page.click("text=Credit Cards");
|
||||
|
||||
const creditCardNumber = page.frameLocator('#braintree-hosted-field-number').locator('#credit-card-number');
|
||||
await creditCardNumber.fill(CREDIT_CARD_NUMBER);
|
||||
|
||||
const expirationDate = page.frameLocator('#braintree-hosted-field-expirationDate').locator('#expiration');
|
||||
await expirationDate.fill(CREDIT_CARD_EXPIRATION);
|
||||
|
||||
const cvv = page.frameLocator('#braintree-hosted-field-cvv').locator('#cvv');
|
||||
await cvv.fill(CREDIT_CARD_CVV);
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator('.ppcp-dcc-order-button').click(),
|
||||
]);
|
||||
|
||||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
|
||||
test('PayPal APM button place order', async ({page}) => {
|
||||
await page.goto(CART_URL + '?add-to-cart=' + PRODUCT_ID);
|
||||
|
||||
await page.goto(CHECKOUT_URL);
|
||||
|
||||
await fillCheckoutForm(page);
|
||||
|
||||
const popup = await openPaypalPopup(page, {fundingSource: APM_ID});
|
||||
|
||||
await popup.getByText('Continue', { exact: true }).click();
|
||||
await completePaypalPayment(popup, {selector: '[name="Successful"]'});
|
||||
|
||||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
|
||||
test('PayPal APM button place order when redirect fails', async ({page}) => {
|
||||
await page.goto(CART_URL + '?add-to-cart=' + PRODUCT_ID);
|
||||
|
||||
await page.goto(CHECKOUT_URL);
|
||||
|
||||
await fillCheckoutForm(page);
|
||||
|
||||
await page.evaluate('PayPalCommerceGateway.ajax.approve_order = null');
|
||||
|
||||
const popup = await openPaypalPopup(page, {fundingSource: APM_ID});
|
||||
|
||||
await popup.getByText('Continue', { exact: true }).click();
|
||||
await completePaypalPayment(popup, {selector: '[name="Successful"]'});
|
||||
|
||||
await expect(page.locator('.woocommerce-error')).toBeVisible();
|
||||
|
||||
await page.reload();
|
||||
await expectContinuation(page);
|
||||
|
||||
await acceptTerms(page);
|
||||
|
||||
await completeContinuation(page);
|
||||
|
||||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Block checkout', () => {
|
||||
test.beforeAll(async ({browser}) => {
|
||||
await serverExec('wp option update woocommerce_checkout_page_id ' + BLOCK_CHECKOUT_PAGE_ID);
|
||||
await serverExec('wp pcp settings update blocks_final_review_enabled true');
|
||||
});
|
||||
|
||||
test('PayPal express block checkout', async ({page}) => {
|
||||
await page.goto('?add-to-cart=' + PRODUCT_ID);
|
||||
|
||||
await page.goto(BLOCK_CHECKOUT_URL)
|
||||
|
||||
const popup = await openPaypalPopup(page);
|
||||
|
||||
await loginIntoPaypal(popup);
|
||||
|
||||
await completePaypalPayment(popup);
|
||||
|
||||
await completeBlockContinuation(page);
|
||||
|
||||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
|
||||
test('PayPal express block cart', async ({page}) => {
|
||||
await page.goto(BLOCK_CART_URL + '?add-to-cart=' + PRODUCT_ID)
|
||||
|
||||
const popup = await openPaypalPopup(page);
|
||||
|
||||
await loginIntoPaypal(popup);
|
||||
|
||||
await completePaypalPayment(popup);
|
||||
|
||||
await completeBlockContinuation(page);
|
||||
|
||||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
|
||||
test.describe('Without review', () => {
|
||||
test.beforeAll(async ({browser}) => {
|
||||
await serverExec('wp pcp settings update blocks_final_review_enabled false');
|
||||
});
|
||||
|
||||
test('PayPal express block checkout', async ({page}) => {
|
||||
await page.goto('?add-to-cart=' + PRODUCT_ID);
|
||||
|
||||
await page.goto(BLOCK_CHECKOUT_URL)
|
||||
|
||||
const popup = await openPaypalPopup(page);
|
||||
|
||||
await loginIntoPaypal(popup);
|
||||
|
||||
await waitForPaypalShippingList(popup);
|
||||
|
||||
await completePaypalPayment(popup);
|
||||
|
||||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
|
||||
test('PayPal express block cart', async ({page}) => {
|
||||
await page.goto(BLOCK_CART_URL + '?add-to-cart=' + PRODUCT_ID)
|
||||
|
||||
const popup = await openPaypalPopup(page);
|
||||
|
||||
await loginIntoPaypal(popup);
|
||||
|
||||
await waitForPaypalShippingList(popup);
|
||||
|
||||
await completePaypalPayment(popup);
|
||||
|
||||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,89 +1,84 @@
|
|||
const {test, expect} = require('@playwright/test');
|
||||
const {loginAsCustomer} = require("./utils/user");
|
||||
const {openPaypalPopup, loginIntoPaypal, completePaypalPayment} = require("./utils/paypal-popup");
|
||||
const {fillCheckoutForm, expectOrderReceivedPage} = require("./utils/checkout");
|
||||
|
||||
const { test, expect } = require( '@playwright/test' );
|
||||
const { loginAsCustomer } = require( './utils/user' );
|
||||
const {
|
||||
PRODUCT_URL,
|
||||
} = process.env;
|
||||
openPaypalPopup,
|
||||
loginIntoPaypal,
|
||||
completePaypalPayment,
|
||||
} = require( './utils/paypal-popup' );
|
||||
const {
|
||||
fillCheckoutForm,
|
||||
expectOrderReceivedPage,
|
||||
} = require( './utils/checkout' );
|
||||
|
||||
async function expectContinuation(page) {
|
||||
await expect(page.locator('#payment_method_ppcp-gateway')).toBeChecked();
|
||||
const { PRODUCT_URL } = process.env;
|
||||
|
||||
await expect(page.locator('.component-frame')).toHaveCount(0);
|
||||
async function expectContinuation( page ) {
|
||||
await expect(
|
||||
page.locator( '#payment_method_ppcp-gateway' )
|
||||
).toBeChecked();
|
||||
|
||||
await expect( page.locator( '.component-frame' ) ).toHaveCount( 0 );
|
||||
}
|
||||
|
||||
async function completeContinuation(page) {
|
||||
await expectContinuation(page);
|
||||
async function completeContinuation( page ) {
|
||||
await expectContinuation( page );
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator('#place_order').click(),
|
||||
]);
|
||||
await Promise.all( [
|
||||
page.waitForNavigation(),
|
||||
page.locator( '#place_order' ).click(),
|
||||
] );
|
||||
}
|
||||
|
||||
test('Save during purchase', async ({page}) => {
|
||||
await loginAsCustomer(page)
|
||||
// preconditions: shipping callback disabled and no saved payments
|
||||
test( 'Save during purchase', async ( { page } ) => {
|
||||
await loginAsCustomer( page );
|
||||
|
||||
await page.goto(PRODUCT_URL);
|
||||
const popup = await openPaypalPopup(page);
|
||||
await page.goto( PRODUCT_URL );
|
||||
const popup = await openPaypalPopup( page );
|
||||
|
||||
await loginIntoPaypal(popup);
|
||||
await completePaypalPayment(popup);
|
||||
await fillCheckoutForm(page);
|
||||
await loginIntoPaypal( popup );
|
||||
await completePaypalPayment( popup );
|
||||
await fillCheckoutForm( page );
|
||||
|
||||
await completeContinuation(page);
|
||||
await completeContinuation( page );
|
||||
|
||||
await expectOrderReceivedPage(page);
|
||||
});
|
||||
await expectOrderReceivedPage( page );
|
||||
} );
|
||||
|
||||
test('PayPal add payment method', async ({page}) => {
|
||||
await loginAsCustomer(page);
|
||||
await page.goto('/my-account/add-payment-method');
|
||||
test( 'PayPal add payment method', async ( { page } ) => {
|
||||
await loginAsCustomer( page );
|
||||
await page.goto( '/my-account/add-payment-method' );
|
||||
|
||||
const popup = await openPaypalPopup(page);
|
||||
await loginIntoPaypal(popup);
|
||||
popup.locator('#consentButton').click();
|
||||
const popup = await openPaypalPopup( page );
|
||||
await loginIntoPaypal( popup );
|
||||
popup.locator( '#consentButton' ).click();
|
||||
|
||||
await page.waitForURL('/my-account/payment-methods');
|
||||
});
|
||||
await page.waitForURL( '/my-account/payment-methods' );
|
||||
} );
|
||||
|
||||
test('ACDC add payment method', async ({page}) => {
|
||||
await loginAsCustomer(page);
|
||||
await page.goto('/my-account/add-payment-method');
|
||||
test( 'ACDC add payment method', async ( { page } ) => {
|
||||
await loginAsCustomer( page );
|
||||
await page.goto( '/my-account/add-payment-method' );
|
||||
|
||||
await page.click("text=Debit & Credit Cards");
|
||||
|
||||
const creditCardNumber = await page.frameLocator('[title="paypal_card_number_field"]').locator('.card-field-number');
|
||||
await creditCardNumber.fill('4005519200000004');
|
||||
|
||||
const expirationDate = await page.frameLocator('[title="paypal_card_expiry_field"]').locator('.card-field-expiry');
|
||||
await expirationDate.fill('01/25');
|
||||
|
||||
const cvv = await page.frameLocator('[title="paypal_card_cvv_field"]').locator('.card-field-cvv');
|
||||
await cvv.fill('123');
|
||||
|
||||
await page.waitForURL('/my-account/payment-methods');
|
||||
});
|
||||
|
||||
test('PayPal logged-in user free trial subscription without payment token', async ({page}) => {
|
||||
await loginAsCustomer(page);
|
||||
|
||||
await page.goto('/shop');
|
||||
await page.click("text=Sign up now");
|
||||
await page.goto('/classic-checkout');
|
||||
|
||||
const popup = await openPaypalPopup(page);
|
||||
await loginIntoPaypal(popup);
|
||||
popup.locator('#consentButton').click();
|
||||
|
||||
await page.click("text=Proceed to PayPal");
|
||||
|
||||
const title = await page.locator('.entry-title');
|
||||
await expect(title).toHaveText('Order received');
|
||||
})
|
||||
await page.click( 'text=Debit & Credit Cards' );
|
||||
|
||||
const creditCardNumber = await page
|
||||
.frameLocator( '[title="paypal_card_number_field"]' )
|
||||
.locator( '.card-field-number' );
|
||||
await creditCardNumber.fill( '4005519200000004' );
|
||||
|
||||
const expirationDate = await page
|
||||
.frameLocator( 'iframe[title="paypal_card_expiry_field"]' )
|
||||
.locator( 'input.card-field-expiry' );
|
||||
await expirationDate.click();
|
||||
await page.keyboard.type( '12/25' );
|
||||
|
||||
const cvv = await page
|
||||
.frameLocator( '[title="paypal_card_cvv_field"]' )
|
||||
.locator( '.card-field-cvv' );
|
||||
await cvv.fill( '123' );
|
||||
|
||||
await page.getByRole( 'button', { name: 'Add payment method' } ).click();
|
||||
|
||||
await page.waitForURL( '/my-account/payment-methods' );
|
||||
} );
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue