mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Merge pull request #3456 from woocommerce/PCP-4803-modify-create-order-payload-to-display-email-and-phone-in-pay-pal-popup
Modify Create Order payload to display email and phone in PayPal popup (4803)
This commit is contained in:
commit
8fe7615eec
12 changed files with 276 additions and 30 deletions
|
@ -32,7 +32,6 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\RefundPayerFactory;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\SellerPayableBreakdownFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingOptionFactory;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Settings\Service\BrandedExperience\ActivationDetector;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer;
|
||||
|
@ -82,6 +81,8 @@ use WooCommerce\PayPalCommerce\ApiClient\Authentication\ConnectBearer;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Helper\EnvironmentConfig;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Settings\Enum\InstallationPathEnum;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ContactPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Settings\Data\SettingsModel;
|
||||
|
||||
return array(
|
||||
'api.host' => static function( ContainerInterface $container ) : string {
|
||||
|
@ -330,6 +331,22 @@ return array(
|
|||
$container->get( 'api.endpoint.order' )
|
||||
);
|
||||
},
|
||||
'api.factory.contact-preference' => static function ( ContainerInterface $container ): ContactPreferenceFactory {
|
||||
if ( $container->has( 'settings.data.settings' ) ) {
|
||||
$settings = $container->get( 'settings.data.settings' );
|
||||
assert( $settings instanceof SettingsModel );
|
||||
|
||||
$contact_module_active = $settings->get_enable_contact_module();
|
||||
} else {
|
||||
// #legacy-ui: Auto-enable the feature; can be disabled via eligibility hook.
|
||||
$contact_module_active = true;
|
||||
}
|
||||
|
||||
return new ContactPreferenceFactory(
|
||||
$contact_module_active,
|
||||
$container->get( 'settings.merchant-details' )
|
||||
);
|
||||
},
|
||||
'api.factory.payment-token' => static function ( ContainerInterface $container ) : PaymentTokenFactory {
|
||||
return new PaymentTokenFactory();
|
||||
},
|
||||
|
|
|
@ -30,6 +30,9 @@ class ExperienceContext {
|
|||
public const PAYMENT_METHOD_UNRESTRICTED = 'UNRESTRICTED';
|
||||
public const PAYMENT_METHOD_IMMEDIATE_PAYMENT_REQUIRED = 'IMMEDIATE_PAYMENT_REQUIRED';
|
||||
|
||||
public const CONTACT_PREFERENCE_NO_CONTACT_INFO = 'NO_CONTACT_INFO';
|
||||
public const CONTACT_PREFERENCE_UPDATE_CONTACT_INFO = 'UPDATE_CONTACT_INFO';
|
||||
|
||||
/**
|
||||
* The return url.
|
||||
*/
|
||||
|
@ -70,6 +73,12 @@ class ExperienceContext {
|
|||
*/
|
||||
private ?string $payment_method_preference = null;
|
||||
|
||||
/**
|
||||
* Controls the contact module, and when defined, the API response will
|
||||
* include additional details in the `purchase_units[].shipping` object.
|
||||
*/
|
||||
private ?string $contact_preference = null;
|
||||
|
||||
/**
|
||||
* The callback config.
|
||||
*/
|
||||
|
@ -229,6 +238,28 @@ class ExperienceContext {
|
|||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact preference.
|
||||
*/
|
||||
public function contact_preference(): ?string {
|
||||
return $this->contact_preference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the contact preference.
|
||||
*
|
||||
* This preference is only available for the payment source 'paypal' and 'venmo'.
|
||||
* https://developer.paypal.com/docs/api/orders/v2/#definition-paypal_wallet_experience_context
|
||||
*
|
||||
* @param string|null $new_value The value to set.
|
||||
*/
|
||||
public function with_contact_preference( ?string $new_value ): ExperienceContext {
|
||||
$obj = clone $this;
|
||||
|
||||
$obj->contact_preference = $new_value;
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the callback config.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* Returns contact_preference for the given state.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||
*/
|
||||
|
||||
declare( strict_types = 1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ExperienceContext;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\MerchantDetails;
|
||||
|
||||
/**
|
||||
* Class ContactPreferenceFactory
|
||||
*/
|
||||
class ContactPreferenceFactory {
|
||||
/**
|
||||
* Whether the contact module toggle is enabled in the plugin settings.
|
||||
* Allows eligible merchants to opt out of the feature.
|
||||
*/
|
||||
private bool $is_contact_module_active;
|
||||
|
||||
/**
|
||||
* Used to determine if a merchant is eligible to use the contact preference.
|
||||
*/
|
||||
private MerchantDetails $merchant_details;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param bool $is_contact_module_active Whether custom contact details are enabled
|
||||
* in the plugin settings.
|
||||
* @param MerchantDetails $merchant_details Service 'settings.merchant-details'.
|
||||
*/
|
||||
public function __construct(
|
||||
bool $is_contact_module_active,
|
||||
MerchantDetails $merchant_details
|
||||
) {
|
||||
$this->is_contact_module_active = $is_contact_module_active;
|
||||
$this->merchant_details = $merchant_details;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns contact_preference for the given state.
|
||||
*
|
||||
* @param string $payment_source_key Name of the payment_source.
|
||||
* @return string|null
|
||||
*/
|
||||
public function from_state( string $payment_source_key ) : ?string {
|
||||
$payment_sources_with_contact = array( 'paypal', 'venmo' );
|
||||
|
||||
/**
|
||||
* In case the payment-source does not support the contact-info preference
|
||||
* we return null to remove the property from the context.
|
||||
*/
|
||||
if ( ! in_array( $payment_source_key, $payment_sources_with_contact, true ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! $this->is_contact_module_active ) {
|
||||
return ExperienceContext::CONTACT_PREFERENCE_NO_CONTACT_INFO;
|
||||
}
|
||||
|
||||
if ( ! $this->merchant_details->is_eligible_for( MerchantDetails::FEATURE_CONTACT_MODULE ) ) {
|
||||
return ExperienceContext::CONTACT_PREFERENCE_NO_CONTACT_INFO;
|
||||
}
|
||||
|
||||
return ExperienceContext::CONTACT_PREFERENCE_UPDATE_CONTACT_INFO;
|
||||
}
|
||||
}
|
|
@ -181,6 +181,20 @@ class ExperienceContextBuilder {
|
|||
return $builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a custom contact preference to the experience context.
|
||||
*
|
||||
* @param string|null $preference The new preference to apply.
|
||||
*/
|
||||
public function with_contact_preference( ?string $preference = null ) : ExperienceContextBuilder {
|
||||
$builder = clone $this;
|
||||
|
||||
$builder->experience_context = $builder->experience_context
|
||||
->with_contact_preference( $preference );
|
||||
|
||||
return $builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ExperienceContext.
|
||||
*/
|
||||
|
|
|
@ -228,6 +228,7 @@ return array(
|
|||
$request_data,
|
||||
$purchase_unit_factory,
|
||||
$container->get( 'api.factory.shipping-preference' ),
|
||||
$container->get( 'api.factory.contact-preference' ),
|
||||
$container->get( 'wcgateway.builder.experience-context' ),
|
||||
$order_endpoint,
|
||||
$payer_factory,
|
||||
|
|
|
@ -37,6 +37,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ContactPreferenceFactory;
|
||||
|
||||
/**
|
||||
* Class CreateOrderEndpoint
|
||||
|
@ -68,6 +69,11 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
*/
|
||||
private $shipping_preference_factory;
|
||||
|
||||
/**
|
||||
* The contact_preference factors.
|
||||
*/
|
||||
private ContactPreferenceFactory $contact_preference_factory;
|
||||
|
||||
/**
|
||||
* The ExperienceContextBuilder.
|
||||
*/
|
||||
|
@ -189,6 +195,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
* @param RequestData $request_data The RequestData object.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The PurchaseUnit factory.
|
||||
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
|
||||
* @param ContactPreferenceFactory $contact_preference_factory The contact_preference factory.
|
||||
* @param ExperienceContextBuilder $experience_context_builder The ExperienceContextBuilder.
|
||||
* @param OrderEndpoint $order_endpoint The OrderEndpoint object.
|
||||
* @param PayerFactory $payer_factory The PayerFactory object.
|
||||
|
@ -208,6 +215,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
RequestData $request_data,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
ShippingPreferenceFactory $shipping_preference_factory,
|
||||
ContactPreferenceFactory $contact_preference_factory,
|
||||
ExperienceContextBuilder $experience_context_builder,
|
||||
OrderEndpoint $order_endpoint,
|
||||
PayerFactory $payer_factory,
|
||||
|
@ -224,23 +232,24 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
$this->request_data = $request_data;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->experience_context_builder = $experience_context_builder;
|
||||
$this->api_endpoint = $order_endpoint;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->settings = $settings;
|
||||
$this->early_order_handler = $early_order_handler;
|
||||
$this->registration_needed = $registration_needed;
|
||||
$this->card_billing_data_mode = $card_billing_data_mode;
|
||||
$this->early_validation_enabled = $early_validation_enabled;
|
||||
$this->pay_now_contexts = $pay_now_contexts;
|
||||
$this->handle_shipping_in_paypal = $handle_shipping_in_paypal;
|
||||
$this->request_data = $request_data;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->contact_preference_factory = $contact_preference_factory;
|
||||
$this->experience_context_builder = $experience_context_builder;
|
||||
$this->api_endpoint = $order_endpoint;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->settings = $settings;
|
||||
$this->early_order_handler = $early_order_handler;
|
||||
$this->registration_needed = $registration_needed;
|
||||
$this->card_billing_data_mode = $card_billing_data_mode;
|
||||
$this->early_validation_enabled = $early_validation_enabled;
|
||||
$this->pay_now_contexts = $pay_now_contexts;
|
||||
$this->handle_shipping_in_paypal = $handle_shipping_in_paypal;
|
||||
$this->server_side_shipping_callback_enabled = $server_side_shipping_callback_enabled;
|
||||
$this->funding_sources_without_redirect = $funding_sources_without_redirect;
|
||||
$this->logger = $logger;
|
||||
$this->funding_sources_without_redirect = $funding_sources_without_redirect;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -449,12 +458,20 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
}
|
||||
}
|
||||
|
||||
$payment_source_key = 'paypal';
|
||||
if ( in_array( $funding_source, array( 'venmo' ), true ) ) {
|
||||
$payment_source_key = $funding_source;
|
||||
if ( 'venmo' === $funding_source ) {
|
||||
$payment_source_key = 'venmo';
|
||||
} else {
|
||||
$payment_source_key = 'paypal';
|
||||
}
|
||||
|
||||
$experience_context = $this->experience_context_builder->with_default_paypal_config( $shipping_preference, $action );
|
||||
$contact_preference = $this->contact_preference_factory->from_state(
|
||||
$payment_source_key
|
||||
);
|
||||
|
||||
$experience_context = $this->experience_context_builder
|
||||
->with_default_paypal_config( $shipping_preference, $action )
|
||||
->with_contact_preference( $contact_preference );
|
||||
|
||||
if ( $this->server_side_shipping_callback_enabled
|
||||
&& $shipping_preference === ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE ) {
|
||||
$experience_context = $experience_context->with_shipping_callback();
|
||||
|
|
|
@ -104,9 +104,10 @@ return array(
|
|||
return $state->get_environment();
|
||||
},
|
||||
'settings.merchant-details' => static function ( ContainerInterface $container ) : MerchantDetails {
|
||||
$woo_country = $container->get( 'api.shop.country' );
|
||||
$woo_country = $container->get( 'api.shop.country' );
|
||||
$eligibility_checks = $container->get( 'wcgateway.feature-eligibility.list' );
|
||||
|
||||
return new MerchantDetails( $woo_country, $woo_country );
|
||||
return new MerchantDetails( $woo_country, $woo_country, $eligibility_checks );
|
||||
},
|
||||
'onboarding.assets' => function( ContainerInterface $container ) : OnboardingAssets {
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
|
|
|
@ -672,6 +672,8 @@ return array(
|
|||
$merchant_country = $data->get_merchant_country();
|
||||
$woo_data = $data->get_woo_settings();
|
||||
|
||||
return new MerchantDetails( $merchant_country, $woo_data['country'] );
|
||||
$eligibility_checks = $container->get( 'wcgateway.feature-eligibility.list' );
|
||||
|
||||
return new MerchantDetails( $merchant_country, $woo_data['country'], $eligibility_checks );
|
||||
},
|
||||
);
|
||||
|
|
|
@ -16,6 +16,8 @@ use WooCommerce\PayPalCommerce\Settings\Service\DataSanitizer;
|
|||
* Class SettingsModel
|
||||
*
|
||||
* Handles the storage and retrieval of PayPal Commerce settings in WordPress options table.
|
||||
*
|
||||
* DI Service: 'settings.data.settings'
|
||||
*/
|
||||
class SettingsModel extends AbstractDataModel {
|
||||
|
||||
|
@ -97,7 +99,7 @@ class SettingsModel extends AbstractDataModel {
|
|||
'authorize_only' => false,
|
||||
'capture_virtual_orders' => false,
|
||||
'save_paypal_and_venmo' => false,
|
||||
'enable_contact_module' => false,
|
||||
'enable_contact_module' => true,
|
||||
'save_card_details' => false,
|
||||
'enable_pay_now' => false,
|
||||
'enable_logging' => false,
|
||||
|
|
|
@ -2172,6 +2172,23 @@ return array(
|
|||
);
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a centralized list of feature eligibility checks.
|
||||
*
|
||||
* This is a helper service which is used by the `MerchantDetails` class and
|
||||
* should not be directly accessed.
|
||||
*/
|
||||
'wcgateway.feature-eligibility.list' => static function( ContainerInterface $container ): array {
|
||||
return array(
|
||||
MerchantDetails::FEATURE_SAVE_PAYPAL_VENMO => $container->get( 'save-payment-methods.eligibility.check' ),
|
||||
MerchantDetails::FEATURE_ADVANCED_CARD_PROCESSING => $container->get( 'card-fields.eligibility.check' ),
|
||||
MerchantDetails::FEATURE_GOOGLE_PAY => $container->get( 'googlepay.eligibility.check' ),
|
||||
MerchantDetails::FEATURE_APPLE_PAY => $container->get( 'applepay.eligibility.check' ),
|
||||
MerchantDetails::FEATURE_CONTACT_MODULE => $container->get( 'wcgateway.contact-module.eligibility.check' ),
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a prefix for the site, ensuring the same site always gets the same prefix (unless the URL changes).
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,34 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
|||
* Main information source about merchant details.
|
||||
*/
|
||||
class MerchantDetails {
|
||||
|
||||
/**
|
||||
* Save tokenized PayPal and Venmo payment details, required for subscriptions and saving
|
||||
* payment methods in user account.
|
||||
*/
|
||||
public const FEATURE_SAVE_PAYPAL_VENMO = 'save_paypal_venmo';
|
||||
|
||||
/**
|
||||
* Advanced card processing eligibility. Required for credit- and debit-card processing.
|
||||
*/
|
||||
public const FEATURE_ADVANCED_CARD_PROCESSING = 'acdc';
|
||||
|
||||
/**
|
||||
* Merchant eligibility to use Google Pay.
|
||||
*/
|
||||
public const FEATURE_GOOGLE_PAY = 'googlepay';
|
||||
|
||||
/**
|
||||
* Whether Apple Pay can be used by the merchant. Apple Pay requires an Apple device (like
|
||||
* iPhone) to be used by customers.
|
||||
*/
|
||||
public const FEATURE_APPLE_PAY = 'applepay';
|
||||
|
||||
/**
|
||||
* Contact module allows the merchant to unlock the "Custom Shipping Contact" toggle.
|
||||
*/
|
||||
public const FEATURE_CONTACT_MODULE = 'contact_module';
|
||||
|
||||
/**
|
||||
* The merchant's country according to PayPal, which might be different from
|
||||
* the WooCommerce country.
|
||||
|
@ -30,15 +58,27 @@ class MerchantDetails {
|
|||
*/
|
||||
private string $store_country;
|
||||
|
||||
/**
|
||||
* A collection of feature eligibility checks. The value can be either a
|
||||
* boolean (static eligibility) or a callback that returns a boolean (lazy check).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $eligibility_checks;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $merchant_country Initial merchant country.
|
||||
* @param string $store_country Initial store country.
|
||||
* @param string $merchant_country Merchant country provided by PayPal's API. Not editable.
|
||||
* @param string $store_country WooCommerce store country, can be changed by the site
|
||||
* admin via the WooCommerce settings.
|
||||
* @param array $eligibility_checks Array of eligibility checks. Default service:
|
||||
* 'wcgateway.feature-eligibility.list'.
|
||||
*/
|
||||
public function __construct( string $merchant_country, string $store_country ) {
|
||||
$this->merchant_country = $merchant_country;
|
||||
$this->store_country = $store_country;
|
||||
public function __construct( string $merchant_country, string $store_country, array $eligibility_checks ) {
|
||||
$this->merchant_country = $merchant_country;
|
||||
$this->store_country = $store_country;
|
||||
$this->eligibility_checks = $eligibility_checks;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,4 +103,33 @@ class MerchantDetails {
|
|||
public function get_shop_country() : string {
|
||||
return $this->store_country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests, if the merchant is eligible to use a certain feature.
|
||||
* Feature checks are reliable _after_ the "plugins_loaded" action finished.
|
||||
*
|
||||
* Note:
|
||||
* To register features for detection by this method, the features must be
|
||||
* present in the service `wcgateway.contact-module.eligibility.check`, and
|
||||
* also define a public FEATURE_* const in the class header.
|
||||
* Adding all features is an ongoing task.
|
||||
*
|
||||
* @param string $feature One of the public self::FEATURE_* values.
|
||||
* @return bool Whether the merchant can use the relevant feature.
|
||||
*/
|
||||
public function is_eligible_for( string $feature ) : bool {
|
||||
if ( ! array_key_exists( $feature, $this->eligibility_checks ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$check = $this->eligibility_checks[ $feature ];
|
||||
if ( is_bool( $check ) ) {
|
||||
return $check;
|
||||
}
|
||||
if ( is_callable( $check ) ) {
|
||||
return (bool) $check();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\ExperienceContextBuilder;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ContactPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
|
@ -148,6 +149,7 @@ class CreateOrderEndpointTest extends TestCase
|
|||
{
|
||||
$request_data = Mockery::mock(RequestData::class);
|
||||
$shippingPreferenceFactory = Mockery::mock(ShippingPreferenceFactory::class);
|
||||
$contactPreferenceFactory = Mockery::mock(ContactPreferenceFactory::class);
|
||||
$experienceContextBuilder = Mockery::mock(ExperienceContextBuilder::class);
|
||||
$purchase_unit_factory = Mockery::mock(PurchaseUnitFactory::class);
|
||||
$order_endpoint = Mockery::mock(OrderEndpoint::class);
|
||||
|
@ -161,6 +163,7 @@ class CreateOrderEndpointTest extends TestCase
|
|||
$request_data,
|
||||
$purchase_unit_factory,
|
||||
$shippingPreferenceFactory,
|
||||
$contactPreferenceFactory,
|
||||
$experienceContextBuilder,
|
||||
$order_endpoint,
|
||||
$payer_factory,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue