mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
Merge branch 'trunk' into PCP-688-add-functionality-to-choose-subscription-failure-behavior
This commit is contained in:
commit
e43313f114
101 changed files with 4250 additions and 1303 deletions
|
@ -14,3 +14,6 @@ trim_trailing_whitespace = false
|
|||
|
||||
[*.{js,json,yml}]
|
||||
indent_style = space
|
||||
|
||||
[*.yml]
|
||||
indent_size = 2
|
||||
|
|
57
.github/workflows/package.yml
vendored
Normal file
57
.github/workflows/package.yml
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
name: Build package
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
packageVersion:
|
||||
description: 'Package version'
|
||||
required: false
|
||||
type: string
|
||||
filePrefix:
|
||||
description: 'File prefix'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
package:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
PACKAGE_VERSION: ${{ github.event.inputs.packageVersion }}
|
||||
FILENAME: woocommerce-paypal-payments
|
||||
|
||||
name: Build package
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 7.1
|
||||
tools: composer:v1
|
||||
|
||||
- name: Fix plugin version input # Add the version number if only suffix entered
|
||||
run: echo "PACKAGE_VERSION=$(sed -nE '/Version:/s/.* ([0-9.]+).*/\1/p' woocommerce-paypal-payments.php)-$PACKAGE_VERSION" >> $GITHUB_ENV
|
||||
if: env.PACKAGE_VERSION && !contains(env.PACKAGE_VERSION, '.')
|
||||
|
||||
- name: Set plugin version header
|
||||
run: 'sed -Ei "s/Version: .*/Version: ${PACKAGE_VERSION}/g" woocommerce-paypal-payments.php'
|
||||
if: env.PACKAGE_VERSION
|
||||
|
||||
- name: Build
|
||||
run: yarn build
|
||||
|
||||
- name: Unzip # GH currently always zips, so if we upload a zip we get a zip inside a zip
|
||||
run: unzip woocommerce-paypal-payments.zip -d dist
|
||||
|
||||
- name: Set file name
|
||||
env:
|
||||
FILE_PREFIX: ${{ github.event.inputs.filePrefix }}
|
||||
run: echo "FILENAME=$FILE_PREFIX-$FILENAME" >> $GITHUB_ENV
|
||||
if: github.event.inputs.filePrefix
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.FILENAME }}
|
||||
path: dist/
|
|
@ -1,5 +1,30 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 1.9.2 - 2022-08-09 =
|
||||
* Fix - Do not allow birth date older than 100 years for PUI. #743
|
||||
* Fix - Store the customer id for vaulted payment method in usermeta to not lose vaulted methods after the invoice prefix change. #698
|
||||
* Fix - Capture Virtual-Only Orders setting did not auto-capture subscription renewal payments. #626
|
||||
* Fix - Voiding authorization at PayPal did not update the status/order notes. #712
|
||||
* Fix - PayPal scripts were loading on pages without smart buttons or Pay Later messaging. #750
|
||||
* Fix - Do not show links for unavailable gateways settings pages. #753
|
||||
* Fix - The smart buttons were not loaded on single product page if a subscription product exists in the cart. #703
|
||||
* Fix - DCC was causing other gateways to disappear after checkout validation error. #757
|
||||
* Fix - Buttons not loading on single product page with default settings when product is in cart. #777
|
||||
* Enhancement - Improve Checkout Field Validation Message. #739
|
||||
* Enhancement - Handle PAYER_ACTION_REQUIRED error. #759
|
||||
|
||||
= 1.9.1 - 2022-07-25 =
|
||||
* Fix - ITEM_TOTAL_MISMATCH error when checking out with multiple products #721
|
||||
* Fix - Unable to purchase a product with Credit card button in pay for order page #718
|
||||
* Fix - Pay Later messaging only displayed when smart button is active on the same page #283
|
||||
* Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
|
||||
* Fix - Placeholders and card type detection not working for PayPal Card Processing (260) #685
|
||||
* Fix - PUI gateway is displayed with unsupported store currency #711
|
||||
* Fix - Wrong PUI locale sent causing error PAYMENT_SOURCE_CANNOT_BE_USED #741
|
||||
* Enhancement - Missing PayPal fee in WC order details for PUI purchase #714
|
||||
* Enhancement - Skip loading of PUI js file on all pages where PUI gateway is not displayed #723
|
||||
* Enhancement - PUI feature capitalization not consistent #724
|
||||
|
||||
= 1.9.0 - 2022-07-04 =
|
||||
* Add - New Feature - Pay Upon Invoice (Germany only) #608
|
||||
* Fix - Order not approved: payment via vaulted PayPal account fails #677
|
||||
|
|
|
@ -43,13 +43,13 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\SellerReceivableBreakdownFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\SellerStatusFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PartnerReferralsData;
|
||||
|
@ -221,10 +221,6 @@ return array(
|
|||
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
|
||||
return new PartnerReferralsData( $dcc_applies );
|
||||
},
|
||||
'api.repository.cart' => static function ( ContainerInterface $container ): CartRepository {
|
||||
$factory = $container->get( 'api.factory.purchase-unit' );
|
||||
return new CartRepository( $factory );
|
||||
},
|
||||
'api.repository.payee' => static function ( ContainerInterface $container ): PayeeRepository {
|
||||
$merchant_email = $container->get( 'api.merchant_email' );
|
||||
$merchant_id = $container->get( 'api.merchant_id' );
|
||||
|
@ -298,6 +294,9 @@ return array(
|
|||
$address_factory = $container->get( 'api.factory.address' );
|
||||
return new ShippingFactory( $address_factory );
|
||||
},
|
||||
'api.factory.shipping-preference' => static function ( ContainerInterface $container ): ShippingPreferenceFactory {
|
||||
return new ShippingPreferenceFactory();
|
||||
},
|
||||
'api.factory.amount' => static function ( ContainerInterface $container ): AmountFactory {
|
||||
$item_factory = $container->get( 'api.factory.item' );
|
||||
return new AmountFactory(
|
||||
|
@ -401,6 +400,60 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
|
||||
'api.shop.is-latin-america' => static function ( ContainerInterface $container ): bool {
|
||||
return in_array(
|
||||
$container->get( 'api.shop.country' ),
|
||||
array(
|
||||
'AI',
|
||||
'AG',
|
||||
'AR',
|
||||
'AW',
|
||||
'BS',
|
||||
'BB',
|
||||
'BZ',
|
||||
'BM',
|
||||
'BO',
|
||||
'BR',
|
||||
'VG',
|
||||
'KY',
|
||||
'CL',
|
||||
'CO',
|
||||
'CR',
|
||||
'DM',
|
||||
'DO',
|
||||
'EC',
|
||||
'SV',
|
||||
'FK',
|
||||
'GF',
|
||||
'GD',
|
||||
'GP',
|
||||
'GT',
|
||||
'GY',
|
||||
'HN',
|
||||
'JM',
|
||||
'MQ',
|
||||
'MX',
|
||||
'MS',
|
||||
'AN',
|
||||
'NI',
|
||||
'PA',
|
||||
'PY',
|
||||
'PE',
|
||||
'KN',
|
||||
'LC',
|
||||
'PM',
|
||||
'VC',
|
||||
'SR',
|
||||
'TT',
|
||||
'TC',
|
||||
'UY',
|
||||
'VE',
|
||||
),
|
||||
true
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Currencies supported by PayPal.
|
||||
*
|
||||
|
|
|
@ -106,7 +106,7 @@ class IdentityToken {
|
|||
&& defined( 'PPCP_FLAG_SUBSCRIPTION' ) && PPCP_FLAG_SUBSCRIPTION
|
||||
) {
|
||||
$customer_id = $this->customer_repository->customer_id_for_user( ( $user_id ) );
|
||||
|
||||
update_user_meta( $user_id, 'ppcp_customer_id', $customer_id );
|
||||
$args['body'] = wp_json_encode(
|
||||
array(
|
||||
'customer_id' => $customer_id,
|
||||
|
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||
|
||||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
|
||||
|
@ -28,6 +29,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class OrderEndpoint
|
||||
|
@ -163,57 +165,23 @@ class OrderEndpoint {
|
|||
* Creates an order.
|
||||
*
|
||||
* @param PurchaseUnit[] $items The purchase unit items for the order.
|
||||
* @param string $shipping_preference One of ApplicationContext::SHIPPING_PREFERENCE_ values.
|
||||
* @param Payer|null $payer The payer off the order.
|
||||
* @param PaymentToken|null $payment_token The payment token.
|
||||
* @param PaymentMethod|null $payment_method The payment method.
|
||||
* @param string $paypal_request_id The paypal request id.
|
||||
* @param bool $shipping_address_is_fixed Whether the shipping address is changeable or not.
|
||||
*
|
||||
* @return Order
|
||||
* @throws RuntimeException If the request fails.
|
||||
*/
|
||||
public function create(
|
||||
array $items,
|
||||
string $shipping_preference,
|
||||
Payer $payer = null,
|
||||
PaymentToken $payment_token = null,
|
||||
PaymentMethod $payment_method = null,
|
||||
string $paypal_request_id = '',
|
||||
bool $shipping_address_is_fixed = false
|
||||
string $paypal_request_id = ''
|
||||
): Order {
|
||||
|
||||
$contains_physical_goods = false;
|
||||
$items = array_filter(
|
||||
$items,
|
||||
static function ( $item ) use ( &$contains_physical_goods ): bool {
|
||||
$is_purchase_unit = is_a( $item, PurchaseUnit::class );
|
||||
/**
|
||||
* A purchase unit.
|
||||
*
|
||||
* @var PurchaseUnit $item
|
||||
*/
|
||||
if ( $is_purchase_unit && $item->contains_physical_goods() ) {
|
||||
$contains_physical_goods = true;
|
||||
}
|
||||
|
||||
return $is_purchase_unit;
|
||||
}
|
||||
);
|
||||
|
||||
$shipping_preference = ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
|
||||
if ( $contains_physical_goods ) {
|
||||
if ( $shipping_address_is_fixed ) {
|
||||
// Checkout + no address given? Probably something weird happened, like no form validation?
|
||||
// Also note that $items currently always seems to be an array with one item.
|
||||
if ( $this->has_items_without_shipping( $items ) ) {
|
||||
$shipping_preference = ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
|
||||
} else {
|
||||
$shipping_preference = ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS;
|
||||
}
|
||||
} else {
|
||||
$shipping_preference = ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$data = array(
|
||||
'intent' => ( $this->subscription_helper->cart_contains_subscription() || $this->subscription_helper->current_product_is_subscription() ) ? 'AUTHORIZE' : $this->intent,
|
||||
|
@ -226,7 +194,7 @@ class OrderEndpoint {
|
|||
'application_context' => $this->application_context_repository
|
||||
->current_context( $shipping_preference )->to_array(),
|
||||
);
|
||||
if ( $payer && ! empty( $payer->email_address() ) && ! empty( $payer->name() ) ) {
|
||||
if ( $payer && ! empty( $payer->email_address() ) ) {
|
||||
$data['payer'] = $payer->to_array();
|
||||
}
|
||||
if ( $payment_token ) {
|
||||
|
@ -600,18 +568,47 @@ class OrderEndpoint {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks if there is at least one item without shipping.
|
||||
* Confirms payment source.
|
||||
*
|
||||
* @param PurchaseUnit[] $items The items.
|
||||
* @return bool Whether items contains shipping or not.
|
||||
* @param string $id The PayPal order ID.
|
||||
* @param array $payment_source The payment source.
|
||||
* @return stdClass
|
||||
* @throws PayPalApiException If the request fails.
|
||||
* @throws RuntimeException If something unexpected happens.
|
||||
*/
|
||||
private function has_items_without_shipping( array $items ): bool {
|
||||
foreach ( $items as $item ) {
|
||||
if ( ! $item->shipping() ) {
|
||||
return true;
|
||||
}
|
||||
public function confirm_payment_source( string $id, array $payment_source ): stdClass {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id . '/confirm-payment-source';
|
||||
|
||||
$data = array(
|
||||
'payment_source' => $payment_source,
|
||||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
'application_context' => array(
|
||||
'locale' => 'es-MX',
|
||||
),
|
||||
);
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( $response instanceof WP_Error ) {
|
||||
throw new RuntimeException( $response->get_error_message() );
|
||||
}
|
||||
|
||||
return false;
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $status_code ) {
|
||||
throw new PayPalApiException( $json, $status_code );
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\RequestTrait;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
|
@ -162,14 +163,14 @@ class PayUponInvoiceOrderEndpoint {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get Ratepay payment instructions from PayPal order.
|
||||
* Get PayPal order as object.
|
||||
*
|
||||
* @param string $id The PayPal order ID.
|
||||
* @return array
|
||||
* @return stdClass
|
||||
* @throws RuntimeException When there is a problem getting the order.
|
||||
* @throws PayPalApiException When there is a problem getting the order.
|
||||
*/
|
||||
public function order_payment_instructions( string $id ): array {
|
||||
public function order( string $id ): stdClass {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id;
|
||||
$args = array(
|
||||
|
@ -191,10 +192,7 @@ class PayUponInvoiceOrderEndpoint {
|
|||
throw new PayPalApiException( $json, $status_code );
|
||||
}
|
||||
|
||||
return array(
|
||||
$json->payment_source->pay_upon_invoice->payment_reference,
|
||||
$json->payment_source->pay_upon_invoice->deposit_bank_details,
|
||||
);
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -64,6 +64,15 @@ class Amount {
|
|||
return $this->money->value();
|
||||
}
|
||||
|
||||
/**
|
||||
* The value formatted as string for API requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function value_str(): string {
|
||||
return $this->money->value_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the breakdown.
|
||||
*
|
||||
|
@ -79,12 +88,7 @@ class Amount {
|
|||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
$amount = array(
|
||||
'currency_code' => $this->currency_code(),
|
||||
'value' => in_array( $this->currency_code(), $this->currencies_without_decimals, true )
|
||||
? round( $this->value(), 0 )
|
||||
: number_format( $this->value(), 2, '.', '' ),
|
||||
);
|
||||
$amount = $this->money->to_array();
|
||||
if ( $this->breakdown() && count( $this->breakdown()->to_array() ) ) {
|
||||
$amount['breakdown'] = $this->breakdown()->to_array();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\MoneyFormatter;
|
||||
|
||||
/**
|
||||
* Class Money
|
||||
*/
|
||||
|
@ -29,11 +31,11 @@ class Money {
|
|||
private $value;
|
||||
|
||||
/**
|
||||
* Currencies that does not support decimals.
|
||||
* The MoneyFormatter.
|
||||
*
|
||||
* @var array
|
||||
* @var MoneyFormatter
|
||||
*/
|
||||
private $currencies_without_decimals = array( 'HUF', 'JPY', 'TWD' );
|
||||
private $money_formatter;
|
||||
|
||||
/**
|
||||
* Money constructor.
|
||||
|
@ -44,6 +46,8 @@ class Money {
|
|||
public function __construct( float $value, string $currency_code ) {
|
||||
$this->value = $value;
|
||||
$this->currency_code = $currency_code;
|
||||
|
||||
$this->money_formatter = new MoneyFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,6 +59,15 @@ class Money {
|
|||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value formatted as string for API requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function value_str(): string {
|
||||
return $this->money_formatter->format( $this->value, $this->currency_code );
|
||||
}
|
||||
|
||||
/**
|
||||
* The currency code.
|
||||
*
|
||||
|
@ -72,9 +85,7 @@ class Money {
|
|||
public function to_array(): array {
|
||||
return array(
|
||||
'currency_code' => $this->currency_code(),
|
||||
'value' => in_array( $this->currency_code(), $this->currencies_without_decimals, true )
|
||||
? round( $this->value(), 0 )
|
||||
: number_format( $this->value(), 2, '.', '' ),
|
||||
'value' => $this->value_str(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class Payer {
|
|||
/**
|
||||
* The name.
|
||||
*
|
||||
* @var PayerName
|
||||
* @var PayerName|null
|
||||
*/
|
||||
private $name;
|
||||
|
||||
|
@ -46,7 +46,7 @@ class Payer {
|
|||
/**
|
||||
* The address.
|
||||
*
|
||||
* @var Address
|
||||
* @var Address|null
|
||||
*/
|
||||
private $address;
|
||||
|
||||
|
@ -67,7 +67,7 @@ class Payer {
|
|||
/**
|
||||
* Payer constructor.
|
||||
*
|
||||
* @param PayerName $name The name.
|
||||
* @param PayerName|null $name The name.
|
||||
* @param string $email_address The email.
|
||||
* @param string $payer_id The payer id.
|
||||
* @param Address|null $address The address.
|
||||
|
@ -76,7 +76,7 @@ class Payer {
|
|||
* @param PayerTaxInfo|null $tax_info The tax info.
|
||||
*/
|
||||
public function __construct(
|
||||
PayerName $name,
|
||||
?PayerName $name,
|
||||
string $email_address,
|
||||
string $payer_id,
|
||||
Address $address = null,
|
||||
|
@ -97,12 +97,21 @@ class Payer {
|
|||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
* @return PayerName
|
||||
* @return PayerName|null
|
||||
*/
|
||||
public function name(): PayerName {
|
||||
public function name(): ?PayerName {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name.
|
||||
*
|
||||
* @param PayerName|null $name The value.
|
||||
*/
|
||||
public function set_name( ?PayerName $name ): void {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the email address.
|
||||
*
|
||||
|
@ -139,6 +148,15 @@ class Payer {
|
|||
return $this->address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the address.
|
||||
*
|
||||
* @param Address|null $address The value.
|
||||
*/
|
||||
public function set_address( ?Address $address ): void {
|
||||
$this->address = $address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phone.
|
||||
*
|
||||
|
@ -164,27 +182,26 @@ class Payer {
|
|||
*/
|
||||
public function to_array() {
|
||||
$payer = array(
|
||||
'name' => $this->name()->to_array(),
|
||||
'email_address' => $this->email_address(),
|
||||
);
|
||||
if ( $this->address() ) {
|
||||
$payer['address'] = $this->address->to_array();
|
||||
if ( 2 !== strlen( $this->address()->country_code() ) ) {
|
||||
unset( $payer['address'] );
|
||||
}
|
||||
if ( $this->name ) {
|
||||
$payer['name'] = $this->name->to_array();
|
||||
}
|
||||
if ( $this->payer_id() ) {
|
||||
$payer['payer_id'] = $this->payer_id();
|
||||
if ( $this->address && 2 === strlen( $this->address->country_code() ) ) {
|
||||
$payer['address'] = $this->address->to_array();
|
||||
}
|
||||
if ( $this->payer_id ) {
|
||||
$payer['payer_id'] = $this->payer_id;
|
||||
}
|
||||
|
||||
if ( $this->phone() ) {
|
||||
$payer['phone'] = $this->phone()->to_array();
|
||||
if ( $this->phone ) {
|
||||
$payer['phone'] = $this->phone->to_array();
|
||||
}
|
||||
if ( $this->tax_info() ) {
|
||||
$payer['tax_info'] = $this->tax_info()->to_array();
|
||||
if ( $this->tax_info ) {
|
||||
$payer['tax_info'] = $this->tax_info->to_array();
|
||||
}
|
||||
if ( $this->birthdate() ) {
|
||||
$payer['birth_date'] = $this->birthdate()->format( 'Y-m-d' );
|
||||
if ( $this->birthdate ) {
|
||||
$payer['birth_date'] = $this->birthdate->format( 'Y-m-d' );
|
||||
}
|
||||
return $payer;
|
||||
}
|
||||
|
|
|
@ -331,9 +331,9 @@ class PurchaseUnit {
|
|||
$remaining_item_total = array_reduce(
|
||||
$items,
|
||||
function ( float $total, Item $item ): float {
|
||||
return $total - $item->unit_amount()->value() * (float) $item->quantity();
|
||||
return $total - (float) $item->unit_amount()->value_str() * (float) $item->quantity();
|
||||
},
|
||||
$item_total->value()
|
||||
(float) $item_total->value_str()
|
||||
);
|
||||
|
||||
$remaining_item_total = round( $remaining_item_total, 2 );
|
||||
|
@ -356,11 +356,11 @@ class PurchaseUnit {
|
|||
function ( float $total, Item $item ): float {
|
||||
$tax = $item->tax();
|
||||
if ( $tax ) {
|
||||
$total -= $tax->value() * (float) $item->quantity();
|
||||
$total -= (float) $tax->value_str() * (float) $item->quantity();
|
||||
}
|
||||
return $total;
|
||||
},
|
||||
$tax_total->value()
|
||||
(float) $tax_total->value_str()
|
||||
);
|
||||
|
||||
$remaining_tax_total = round( $remaining_tax_total, 2 );
|
||||
|
@ -378,29 +378,29 @@ class PurchaseUnit {
|
|||
|
||||
$amount_total = 0.0;
|
||||
if ( $shipping ) {
|
||||
$amount_total += $shipping->value();
|
||||
$amount_total += (float) $shipping->value_str();
|
||||
}
|
||||
if ( $item_total ) {
|
||||
$amount_total += $item_total->value();
|
||||
$amount_total += (float) $item_total->value_str();
|
||||
}
|
||||
if ( $discount ) {
|
||||
$amount_total -= $discount->value();
|
||||
$amount_total -= (float) $discount->value_str();
|
||||
}
|
||||
if ( $tax_total ) {
|
||||
$amount_total += $tax_total->value();
|
||||
$amount_total += (float) $tax_total->value_str();
|
||||
}
|
||||
if ( $shipping_discount ) {
|
||||
$amount_total -= $shipping_discount->value();
|
||||
$amount_total -= (float) $shipping_discount->value_str();
|
||||
}
|
||||
if ( $handling ) {
|
||||
$amount_total += $handling->value();
|
||||
$amount_total += (float) $handling->value_str();
|
||||
}
|
||||
if ( $insurance ) {
|
||||
$amount_total += $insurance->value();
|
||||
$amount_total += (float) $insurance->value_str();
|
||||
}
|
||||
|
||||
$amount_str = (string) $amount->to_array()['value'];
|
||||
$amount_total_str = (string) ( new Money( $amount_total, $amount->currency_code() ) )->to_array()['value'];
|
||||
$amount_str = $amount->value_str();
|
||||
$amount_total_str = ( new Money( $amount_total, $amount->currency_code() ) )->value_str();
|
||||
$needs_to_ditch = $amount_str !== $amount_total_str;
|
||||
return $needs_to_ditch;
|
||||
}
|
||||
|
|
|
@ -111,15 +111,6 @@ class PayPalApiException extends RuntimeException {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns response issues.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function issues(): array {
|
||||
return $this->response->issues ?? array();
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP status code.
|
||||
*
|
||||
|
|
|
@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
||||
|
@ -132,7 +133,7 @@ class AmountFactory {
|
|||
|
||||
$total_value = (float) $order->get_total();
|
||||
if ( (
|
||||
CreditCardGateway::ID === $order->get_payment_method()
|
||||
in_array( $order->get_payment_method(), array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
||||
|| ( PayPalGateway::ID === $order->get_payment_method() && 'card' === $order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) )
|
||||
)
|
||||
&& $this->is_free_trial_order( $order )
|
||||
|
|
|
@ -152,11 +152,15 @@ class PurchaseUnitFactory {
|
|||
/**
|
||||
* Creates a PurchaseUnit based off a WooCommerce cart.
|
||||
*
|
||||
* @param \WC_Cart $cart The cart.
|
||||
* @param \WC_Cart|null $cart The cart.
|
||||
*
|
||||
* @return PurchaseUnit
|
||||
*/
|
||||
public function from_wc_cart( \WC_Cart $cart ): PurchaseUnit {
|
||||
public function from_wc_cart( ?\WC_Cart $cart = null ): PurchaseUnit {
|
||||
if ( ! $cart ) {
|
||||
$cart = WC()->cart ?? new \WC_Cart();
|
||||
}
|
||||
|
||||
$amount = $this->amount_factory->from_wc_cart( $cart );
|
||||
$items = array_filter(
|
||||
$this->item_factory->from_wc_cart( $cart ),
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
/**
|
||||
* Returns shipping_preference for the given state.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use WC_Cart;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
|
||||
/**
|
||||
* Class ShippingPreferenceFactory
|
||||
*/
|
||||
class ShippingPreferenceFactory {
|
||||
|
||||
/**
|
||||
* Returns shipping_preference for the given state.
|
||||
*
|
||||
* @param PurchaseUnit $purchase_unit Thw PurchaseUnit.
|
||||
* @param string $context The operation context like 'checkout', 'cart'.
|
||||
* @param WC_Cart|null $cart The current cart if relevant.
|
||||
* @param string $funding_source The funding source (PayPal button) like 'paypal', 'venmo', 'card'.
|
||||
* @return string
|
||||
*/
|
||||
public function from_state(
|
||||
PurchaseUnit $purchase_unit,
|
||||
string $context,
|
||||
?WC_Cart $cart = null,
|
||||
string $funding_source = ''
|
||||
): string {
|
||||
$contains_physical_goods = $purchase_unit->contains_physical_goods();
|
||||
if ( ! $contains_physical_goods ) {
|
||||
return ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
|
||||
}
|
||||
|
||||
$has_shipping = null !== $purchase_unit->shipping();
|
||||
$needs_shipping = $cart && $cart->needs_shipping();
|
||||
$shipping_address_is_fixed = $needs_shipping && 'checkout' === $context;
|
||||
|
||||
if ( $shipping_address_is_fixed ) {
|
||||
// Checkout + no address given? Probably something weird happened, like no form validation?
|
||||
if ( ! $has_shipping ) {
|
||||
return ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
|
||||
}
|
||||
|
||||
return ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS;
|
||||
}
|
||||
|
||||
if ( 'card' === $funding_source ) {
|
||||
if ( ! $has_shipping ) {
|
||||
return ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
|
||||
}
|
||||
// Looks like GET_FROM_FILE does not work for the vaulted card button.
|
||||
return ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS;
|
||||
}
|
||||
|
||||
return ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE;
|
||||
}
|
||||
}
|
36
modules/ppcp-api-client/src/Helper/MoneyFormatter.php
Normal file
36
modules/ppcp-api-client/src/Helper/MoneyFormatter.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/**
|
||||
* Class MoneyFormatter.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
||||
|
||||
/**
|
||||
* Class MoneyFormatter
|
||||
*/
|
||||
class MoneyFormatter {
|
||||
/**
|
||||
* Currencies that does not support decimals.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $currencies_without_decimals = array( 'HUF', 'JPY', 'TWD' );
|
||||
|
||||
/**
|
||||
* Returns the value formatted as string for API requests.
|
||||
*
|
||||
* @param float $value The value.
|
||||
* @param string $currency The 3-letter currency code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function format( float $value, string $currency ): string {
|
||||
return in_array( $currency, $this->currencies_without_decimals, true )
|
||||
? (string) round( $value, 0 )
|
||||
: number_format( $value, 2, '.', '' );
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* The cart repository returns the purchase units from the current \WC_Cart.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Repository
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Repository;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
|
||||
/**
|
||||
* Class CartRepository
|
||||
*/
|
||||
class CartRepository implements PurchaseUnitRepositoryInterface {
|
||||
|
||||
/**
|
||||
* The purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $factory;
|
||||
|
||||
/**
|
||||
* CartRepository constructor.
|
||||
*
|
||||
* @param PurchaseUnitFactory $factory The purchase unit factory.
|
||||
*/
|
||||
public function __construct( PurchaseUnitFactory $factory ) {
|
||||
$this->factory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Pur of the WooCommerce cart.
|
||||
*
|
||||
* @return PurchaseUnit[]
|
||||
*/
|
||||
public function all(): array {
|
||||
$cart = WC()->cart ?? new \WC_Cart();
|
||||
return array( $this->factory->from_wc_cart( $cart ) );
|
||||
}
|
||||
}
|
|
@ -57,6 +57,6 @@ class CustomerRepository {
|
|||
return $guest_customer_id;
|
||||
}
|
||||
|
||||
return $this->prefix . (string) $user_id;
|
||||
return get_user_meta( $user_id, 'ppcp_customer_id', true ) ?: $this->prefix . (string) $user_id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* The Purchase Unit Repository interface.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Repository
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Repository;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
|
||||
/**
|
||||
* Interface PurchaseUnitRepositoryInterface
|
||||
*/
|
||||
interface PurchaseUnitRepositoryInterface {
|
||||
|
||||
|
||||
/**
|
||||
* Returns all purchase units.
|
||||
*
|
||||
* @return PurchaseUnit[]
|
||||
*/
|
||||
public function all(): array;
|
||||
}
|
|
@ -3,6 +3,9 @@
|
|||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"main": "resources/js/button.js",
|
||||
"dependencies": {
|
||||
"deepmerge": "^4.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
|
|
|
@ -18,7 +18,9 @@ import {hide, setVisible} from "./modules/Helper/Hiding";
|
|||
import {isChangePaymentPage} from "./modules/Helper/Subscriptions";
|
||||
import FreeTrialHandler from "./modules/ActionHandler/FreeTrialHandler";
|
||||
|
||||
const buttonsSpinner = new Spinner('.ppc-button-wrapper');
|
||||
// TODO: could be a good idea to have a separate spinner for each gateway,
|
||||
// but I think we care mainly about the script loading, so one spinner should be enough.
|
||||
const buttonsSpinner = new Spinner(document.querySelector('.ppc-button-wrapper'));
|
||||
const cardsSpinner = new Spinner('#ppcp-hosted-fields');
|
||||
|
||||
const bootstrap = () => {
|
||||
|
@ -38,9 +40,36 @@ const bootstrap = () => {
|
|||
requiredFields.each((i, input) => {
|
||||
jQuery(input).trigger('validate');
|
||||
});
|
||||
if (jQuery('form.woocommerce-checkout .validate-required.woocommerce-invalid:visible').length) {
|
||||
const invalidFields = Array.from(jQuery('form.woocommerce-checkout .validate-required.woocommerce-invalid:visible'));
|
||||
if (invalidFields.length) {
|
||||
const billingFieldsContainer = document.querySelector('.woocommerce-billing-fields');
|
||||
const shippingFieldsContainer = document.querySelector('.woocommerce-shipping-fields');
|
||||
|
||||
const nameMessageMap = PayPalCommerceGateway.labels.error.required.elements;
|
||||
const messages = invalidFields.map(el => {
|
||||
const name = el.querySelector('[name]')?.getAttribute('name');
|
||||
if (name && name in nameMessageMap) {
|
||||
return nameMessageMap[name];
|
||||
}
|
||||
let label = el.querySelector('label').textContent
|
||||
.replaceAll('*', '')
|
||||
.trim();
|
||||
if (billingFieldsContainer?.contains(el)) {
|
||||
label = PayPalCommerceGateway.labels.billing_field.replace('%s', label);
|
||||
}
|
||||
if (shippingFieldsContainer?.contains(el)) {
|
||||
label = PayPalCommerceGateway.labels.shipping_field.replace('%s', label);
|
||||
}
|
||||
return PayPalCommerceGateway.labels.error.required.field
|
||||
.replace('%s', `<strong>${label}</strong>`)
|
||||
}).filter(s => s.length > 2);
|
||||
|
||||
errorHandler.clear();
|
||||
errorHandler.message(PayPalCommerceGateway.labels.error.js_validation);
|
||||
if (messages.length) {
|
||||
messages.forEach(s => errorHandler.message(s));
|
||||
} else {
|
||||
errorHandler.message(PayPalCommerceGateway.labels.error.required.generic);
|
||||
}
|
||||
|
||||
return actions.reject();
|
||||
}
|
||||
|
@ -138,6 +167,11 @@ document.addEventListener(
|
|||
return;
|
||||
}
|
||||
|
||||
const paypalButtonGatewayIds = [
|
||||
PaymentMethods.PAYPAL,
|
||||
...Object.entries(PayPalCommerceGateway.separate_buttons).map(([k, data]) => data.id),
|
||||
]
|
||||
|
||||
// Sometimes PayPal script takes long time to load,
|
||||
// so we additionally hide the standard order button here to avoid failed orders.
|
||||
// Normally it is hidden later after the script load.
|
||||
|
@ -153,12 +187,12 @@ document.addEventListener(
|
|||
}
|
||||
|
||||
const currentPaymentMethod = getCurrentPaymentMethod();
|
||||
const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;
|
||||
const isPaypalButton = paypalButtonGatewayIds.includes(currentPaymentMethod);
|
||||
const isCards = currentPaymentMethod === PaymentMethods.CARDS;
|
||||
|
||||
setVisible(ORDER_BUTTON_SELECTOR, !isPaypal && !isCards, true);
|
||||
setVisible(ORDER_BUTTON_SELECTOR, !isPaypalButton && !isCards, true);
|
||||
|
||||
if (isPaypal) {
|
||||
if (isPaypalButton) {
|
||||
// stopped after the first rendering of the buttons, in onInit
|
||||
buttonsSpinner.block();
|
||||
} else {
|
||||
|
|
|
@ -26,6 +26,9 @@ class CheckoutActionHandler {
|
|||
|
||||
const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
|
||||
|
||||
const paymentMethod = getCurrentPaymentMethod();
|
||||
const fundingSource = window.ppcpFundingSource;
|
||||
|
||||
return fetch(this.config.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
|
@ -34,8 +37,8 @@ class CheckoutActionHandler {
|
|||
bn_code:bnCode,
|
||||
context:this.config.context,
|
||||
order_id:this.config.order_id,
|
||||
payment_method: getCurrentPaymentMethod(),
|
||||
funding_source: window.ppcpFundingSource,
|
||||
payment_method: paymentMethod,
|
||||
funding_source: fundingSource,
|
||||
form: formJsonObj,
|
||||
createaccount: createaccount
|
||||
})
|
||||
|
|
|
@ -32,9 +32,7 @@ class CartBootstrap {
|
|||
);
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.wrapper,
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
actionHandler.configuration(),
|
||||
actionHandler.configuration()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,9 +69,7 @@ class CheckoutBootstap {
|
|||
);
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.wrapper,
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
actionHandler.configuration(),
|
||||
actionHandler.configuration()
|
||||
);
|
||||
|
||||
this.buttonChangeObserver.observe(
|
||||
|
@ -84,16 +82,27 @@ class CheckoutBootstap {
|
|||
const currentPaymentMethod = getCurrentPaymentMethod();
|
||||
const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;
|
||||
const isCard = currentPaymentMethod === PaymentMethods.CARDS;
|
||||
const isSeparateButtonGateway = [PaymentMethods.CARD_BUTTON].includes(currentPaymentMethod);
|
||||
const isSavedCard = isCard && isSavedCardSelected();
|
||||
const isNotOurGateway = !isPaypal && !isCard;
|
||||
const isNotOurGateway = !isPaypal && !isCard && !isSeparateButtonGateway;
|
||||
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
|
||||
const hasVaultedPaypal = PayPalCommerceGateway.vaulted_paypal_email !== '';
|
||||
|
||||
const paypalButtonWrappers = {
|
||||
...Object.entries(PayPalCommerceGateway.separate_buttons)
|
||||
.reduce((result, [k, data]) => {
|
||||
return {...result, [data.id]: data.wrapper}
|
||||
}, {}),
|
||||
};
|
||||
|
||||
setVisible(this.standardOrderButtonSelector, (isPaypal && isFreeTrial && hasVaultedPaypal) || isNotOurGateway || isSavedCard, true);
|
||||
setVisible('.ppcp-vaulted-paypal-details', isPaypal);
|
||||
setVisible(this.gateway.button.wrapper, isPaypal && !(isFreeTrial && hasVaultedPaypal));
|
||||
setVisible(this.gateway.messages.wrapper, isPaypal && !isFreeTrial);
|
||||
setVisible(this.gateway.hosted_fields.wrapper, isCard && !isSavedCard);
|
||||
for (const [gatewayId, wrapper] of Object.entries(paypalButtonWrappers)) {
|
||||
setVisible(wrapper, gatewayId === currentPaymentMethod);
|
||||
}
|
||||
|
||||
if (isPaypal && !isFreeTrial) {
|
||||
this.messages.render();
|
||||
|
|
|
@ -32,9 +32,13 @@ class MiniCartBootstap {
|
|||
}
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.mini_cart_wrapper,
|
||||
this.gateway.hosted_fields.mini_cart_wrapper,
|
||||
this.actionHandler.configuration()
|
||||
this.actionHandler.configuration(),
|
||||
{
|
||||
button: {
|
||||
wrapper: this.gateway.button.mini_cart_wrapper,
|
||||
style: this.gateway.button.mini_cart_style,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ class SingleProductBootstap {
|
|||
|
||||
}
|
||||
|
||||
priceAmountIsZero() {
|
||||
priceAmount() {
|
||||
|
||||
let priceText = "0";
|
||||
if (document.querySelector('form.cart ins .woocommerce-Price-amount')) {
|
||||
|
@ -55,9 +55,12 @@ class SingleProductBootstap {
|
|||
}
|
||||
|
||||
priceText = priceText.replace(/,/g, '.');
|
||||
const amount = parseFloat(priceText.replace(/([^\d,\.\s]*)/g, ''));
|
||||
return amount === 0;
|
||||
|
||||
return parseFloat(priceText.replace(/([^\d,\.\s]*)/g, ''));
|
||||
}
|
||||
|
||||
priceAmountIsZero() {
|
||||
return this.priceAmount() === 0;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -70,28 +73,19 @@ class SingleProductBootstap {
|
|||
() => {
|
||||
this.renderer.showButtons(this.gateway.button.wrapper);
|
||||
this.renderer.showButtons(this.gateway.hosted_fields.wrapper);
|
||||
let priceText = "0";
|
||||
if (document.querySelector('form.cart ins .woocommerce-Price-amount')) {
|
||||
priceText = document.querySelector('form.cart ins .woocommerce-Price-amount').innerText;
|
||||
}
|
||||
else if (document.querySelector('form.cart .woocommerce-Price-amount')) {
|
||||
priceText = document.querySelector('form.cart .woocommerce-Price-amount').innerText;
|
||||
}
|
||||
const amount = parseInt(priceText.replace(/([^\d,\.\s]*)/g, ''));
|
||||
this.messages.renderWithAmount(amount)
|
||||
this.messages.renderWithAmount(this.priceAmount())
|
||||
},
|
||||
() => {
|
||||
this.renderer.hideButtons(this.gateway.button.wrapper);
|
||||
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
|
||||
this.messages.hideMessages();
|
||||
},
|
||||
document.querySelector('form.cart'),
|
||||
new ErrorHandler(this.gateway.labels.error.generic),
|
||||
);
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.wrapper,
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
actionHandler.configuration(),
|
||||
actionHandler.configuration()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
export const PaymentMethods = {
|
||||
PAYPAL: 'ppcp-gateway',
|
||||
CARDS: 'ppcp-credit-card-gateway',
|
||||
OXXO: 'ppcp-oxxo-gateway',
|
||||
CARD_BUTTON: 'ppcp-card-button-gateway',
|
||||
};
|
||||
|
||||
export const ORDER_BUTTON_SELECTOR = '#place_order';
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
const dccInputFactory = (original) => {
|
||||
const styles = window.getComputedStyle(original);
|
||||
const newElement = document.createElement('span');
|
||||
|
||||
newElement.setAttribute('id', original.id);
|
||||
newElement.setAttribute('class', original.className);
|
||||
|
||||
Object.values(styles).forEach( (prop) => {
|
||||
if (! styles[prop] || ! isNaN(prop) ) {
|
||||
if (! styles[prop] || ! isNaN(prop) || prop === 'background-image' ) {
|
||||
return;
|
||||
}
|
||||
newElement.style.setProperty(prop,'' + styles[prop]);
|
||||
|
@ -11,4 +14,4 @@ const dccInputFactory = (original) => {
|
|||
return newElement;
|
||||
}
|
||||
|
||||
export default dccInputFactory;
|
||||
export default dccInputFactory;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import dccInputFactory from "../Helper/DccInputFactory";
|
||||
import {show} from "../Helper/Hiding";
|
||||
import Product from "../Entity/Product";
|
||||
|
||||
class CreditCardRenderer {
|
||||
|
||||
|
@ -117,11 +118,23 @@ class CreditCardRenderer {
|
|||
}
|
||||
const validCards = this.defaultConfig.hosted_fields.valid_cards;
|
||||
this.cardValid = validCards.indexOf(event.cards[0].type) !== -1;
|
||||
|
||||
const className = this._cardNumberFiledCLassNameByCardType(event.cards[0].type);
|
||||
this._recreateElementClassAttribute(cardNumber, cardNumberField.className);
|
||||
if (event.fields.number.isValid) {
|
||||
cardNumber.classList.add(className);
|
||||
}
|
||||
})
|
||||
hostedFields.on('validityChange', (event) => {
|
||||
const formValid = Object.keys(event.fields).every(function (key) {
|
||||
return event.fields[key].isValid;
|
||||
});
|
||||
|
||||
const className = this._cardNumberFiledCLassNameByCardType(event.cards[0].type);
|
||||
event.fields.number.isValid
|
||||
? cardNumber.classList.add(className)
|
||||
: this._recreateElementClassAttribute(cardNumber, cardNumberField.className);
|
||||
|
||||
this.formValid = formValid;
|
||||
|
||||
});
|
||||
|
@ -230,5 +243,14 @@ class CreditCardRenderer {
|
|||
this.errorHandler.message(message);
|
||||
}
|
||||
}
|
||||
|
||||
_cardNumberFiledCLassNameByCardType(cardType) {
|
||||
return cardType === 'american-express' ? 'amex' : cardType.replace('-', '');
|
||||
}
|
||||
|
||||
_recreateElementClassAttribute(element, newClassName) {
|
||||
element.removeAttribute('class')
|
||||
element.setAttribute('class', newClassName);
|
||||
}
|
||||
}
|
||||
export default CreditCardRenderer;
|
||||
|
|
|
@ -1,33 +1,96 @@
|
|||
import merge from "deepmerge";
|
||||
|
||||
class Renderer {
|
||||
constructor(creditCardRenderer, defaultConfig, onSmartButtonClick, onSmartButtonsInit) {
|
||||
this.defaultConfig = defaultConfig;
|
||||
constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit) {
|
||||
this.defaultSettings = defaultSettings;
|
||||
this.creditCardRenderer = creditCardRenderer;
|
||||
this.onSmartButtonClick = onSmartButtonClick;
|
||||
this.onSmartButtonsInit = onSmartButtonsInit;
|
||||
|
||||
this.renderedSources = new Set();
|
||||
}
|
||||
|
||||
render(wrapper, hostedFieldsWrapper, contextConfig) {
|
||||
render(contextConfig, settingsOverride = {}) {
|
||||
const settings = merge(this.defaultSettings, settingsOverride);
|
||||
|
||||
this.renderButtons(wrapper, contextConfig);
|
||||
this.creditCardRenderer.render(hostedFieldsWrapper, contextConfig);
|
||||
const enabledSeparateGateways = Object.fromEntries(Object.entries(
|
||||
settings.separate_buttons).filter(([s, data]) => document.querySelector(data.wrapper)
|
||||
));
|
||||
const hasEnabledSeparateGateways = Object.keys(enabledSeparateGateways).length !== 0;
|
||||
|
||||
if (!hasEnabledSeparateGateways) {
|
||||
this.renderButtons(
|
||||
settings.button.wrapper,
|
||||
settings.button.style,
|
||||
contextConfig,
|
||||
hasEnabledSeparateGateways
|
||||
);
|
||||
} else {
|
||||
// render each button separately
|
||||
for (const fundingSource of paypal.getFundingSources().filter(s => !(s in enabledSeparateGateways))) {
|
||||
let style = settings.button.style;
|
||||
if (fundingSource !== 'paypal') {
|
||||
style = {
|
||||
shape: style.shape,
|
||||
};
|
||||
}
|
||||
|
||||
this.renderButtons(
|
||||
settings.button.wrapper,
|
||||
style,
|
||||
contextConfig,
|
||||
hasEnabledSeparateGateways,
|
||||
fundingSource
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.creditCardRenderer.render(settings.hosted_fields.wrapper, contextConfig);
|
||||
|
||||
for (const [fundingSource, data] of Object.entries(enabledSeparateGateways)) {
|
||||
this.renderButtons(
|
||||
data.wrapper,
|
||||
data.style,
|
||||
contextConfig,
|
||||
hasEnabledSeparateGateways,
|
||||
fundingSource
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderButtons(wrapper, contextConfig) {
|
||||
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper) || 'undefined' === typeof paypal.Buttons ) {
|
||||
renderButtons(wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource = null) {
|
||||
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) || 'undefined' === typeof paypal.Buttons ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const style = wrapper === this.defaultConfig.button.wrapper ? this.defaultConfig.button.style : this.defaultConfig.button.mini_cart_style;
|
||||
paypal.Buttons({
|
||||
if (fundingSource) {
|
||||
contextConfig.fundingSource = fundingSource;
|
||||
}
|
||||
|
||||
const btn = paypal.Buttons({
|
||||
style,
|
||||
...contextConfig,
|
||||
onClick: this.onSmartButtonClick,
|
||||
onInit: this.onSmartButtonsInit,
|
||||
}).render(wrapper);
|
||||
});
|
||||
if (!btn.isEligible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
btn.render(wrapper);
|
||||
|
||||
this.renderedSources.add(wrapper + fundingSource ?? '');
|
||||
}
|
||||
|
||||
isAlreadyRendered(wrapper) {
|
||||
return document.querySelector(wrapper).hasChildNodes();
|
||||
isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) {
|
||||
// Simply check that has child nodes when we do not need to render buttons separately,
|
||||
// this will reduce the risk of breaking with different themes/plugins
|
||||
// and on the cart page (where we also do not need to render separately), which may fully reload this part of the page.
|
||||
// Ideally we should also find a way to detect such full reloads and remove the corresponding keys from the set.
|
||||
if (!hasEnabledSeparateGateways) {
|
||||
return document.querySelector(wrapper).hasChildNodes();
|
||||
}
|
||||
return this.renderedSources.has(wrapper + fundingSource ?? '');
|
||||
}
|
||||
|
||||
hideButtons(element) {
|
||||
|
|
|
@ -108,14 +108,13 @@ return array(
|
|||
$cart = WC()->cart;
|
||||
$shipping = WC()->shipping();
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
$repository = $container->get( 'api.repository.cart' );
|
||||
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
||||
$data_store = \WC_Data_Store::load( 'product' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store, $logger );
|
||||
return new ChangeCartEndpoint( $cart, $shipping, $request_data, $purchase_unit_factory, $data_store, $logger );
|
||||
},
|
||||
'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint {
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
$cart_repository = $container->get( 'api.repository.cart' );
|
||||
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$payer_factory = $container->get( 'api.factory.payer' );
|
||||
|
@ -126,14 +125,15 @@ return array(
|
|||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
return new CreateOrderEndpoint(
|
||||
$request_data,
|
||||
$cart_repository,
|
||||
$purchase_unit_factory,
|
||||
$container->get( 'api.factory.shipping-preference' ),
|
||||
$order_endpoint,
|
||||
$payer_factory,
|
||||
$session_handler,
|
||||
$settings,
|
||||
$early_order_handler,
|
||||
$registration_needed,
|
||||
$container->get( 'wcgateway.settings.card_billing_data_mode' ),
|
||||
$logger
|
||||
);
|
||||
},
|
||||
|
|
|
@ -28,7 +28,9 @@ use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
|||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
|
@ -421,16 +423,23 @@ class SmartButton implements SmartButtonInterface {
|
|||
) {
|
||||
add_action(
|
||||
$this->single_product_renderer_hook(),
|
||||
array(
|
||||
$this,
|
||||
'button_renderer',
|
||||
),
|
||||
function () {
|
||||
$product = wc_get_product();
|
||||
|
||||
if (
|
||||
is_a( $product, WC_Product::class )
|
||||
&& ! $this->product_supports_payment( $product )
|
||||
) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->button_renderer( PayPalGateway::ID );
|
||||
},
|
||||
31
|
||||
);
|
||||
}
|
||||
|
||||
add_action( $this->pay_order_renderer_hook(), array( $this, 'button_renderer' ), 10 );
|
||||
|
||||
$not_enabled_on_minicart = $this->settings->has( 'button_mini_cart_enabled' ) &&
|
||||
! $this->settings->get( 'button_mini_cart_enabled' );
|
||||
if (
|
||||
|
@ -457,21 +466,38 @@ class SmartButton implements SmartButtonInterface {
|
|||
);
|
||||
}
|
||||
|
||||
add_action( $this->checkout_button_renderer_hook(), array( $this, 'button_renderer' ), 10 );
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
|
||||
$not_enabled_on_cart = $this->settings->has( 'button_cart_enabled' ) &&
|
||||
! $this->settings->get( 'button_cart_enabled' );
|
||||
add_action(
|
||||
$this->proceed_to_checkout_button_renderer_hook(),
|
||||
function() use ( $not_enabled_on_cart ) {
|
||||
if ( ! is_cart() || $not_enabled_on_cart || $this->is_free_trial_cart() || $this->is_cart_price_total_zero() ) {
|
||||
return;
|
||||
if ( isset( $available_gateways['ppcp-gateway'] ) ) {
|
||||
add_action(
|
||||
$this->pay_order_renderer_hook(),
|
||||
function (): void {
|
||||
$this->button_renderer( PayPalGateway::ID );
|
||||
$this->button_renderer( CardButtonGateway::ID );
|
||||
}
|
||||
);
|
||||
add_action(
|
||||
$this->checkout_button_renderer_hook(),
|
||||
function (): void {
|
||||
$this->button_renderer( PayPalGateway::ID );
|
||||
$this->button_renderer( CardButtonGateway::ID );
|
||||
}
|
||||
);
|
||||
|
||||
$this->button_renderer();
|
||||
},
|
||||
20
|
||||
);
|
||||
$not_enabled_on_cart = $this->settings->has( 'button_cart_enabled' ) &&
|
||||
! $this->settings->get( 'button_cart_enabled' );
|
||||
add_action(
|
||||
$this->proceed_to_checkout_button_renderer_hook(),
|
||||
function() use ( $not_enabled_on_cart ) {
|
||||
if ( ! is_cart() || $not_enabled_on_cart || $this->is_free_trial_cart() || $this->is_cart_price_total_zero() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->button_renderer( PayPalGateway::ID );
|
||||
},
|
||||
20
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -524,32 +550,24 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
/**
|
||||
* Renders the HTML for the buttons.
|
||||
*
|
||||
* @param string $gateway_id The gateway ID, like 'ppcp-gateway'.
|
||||
*/
|
||||
public function button_renderer() {
|
||||
public function button_renderer( string $gateway_id ) {
|
||||
|
||||
if ( ! $this->can_save_vault_token() && $this->has_subscriptions() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$product = wc_get_product();
|
||||
|
||||
if (
|
||||
! is_checkout() && is_a( $product, WC_Product::class )
|
||||
&& ! $this->product_supports_payment( $product )
|
||||
) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
|
||||
if ( ! isset( $available_gateways['ppcp-gateway'] ) ) {
|
||||
if ( ! isset( $available_gateways[ $gateway_id ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The wrapper is needed for the loading spinner,
|
||||
// otherwise jQuery block() prevents buttons rendering.
|
||||
echo '<div class="ppc-button-wrapper"><div id="ppc-button"></div></div>';
|
||||
echo '<div class="ppc-button-wrapper"><div id="ppc-button-' . esc_attr( $gateway_id ) . '"></div></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -810,7 +828,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
'bn_codes' => $this->bn_codes(),
|
||||
'payer' => $this->payerData(),
|
||||
'button' => array(
|
||||
'wrapper' => '#ppc-button',
|
||||
'wrapper' => '#ppc-button-' . PayPalGateway::ID,
|
||||
'mini_cart_wrapper' => '#ppc-button-minicart',
|
||||
'cancel_wrapper' => '#ppcp-cancel',
|
||||
'url' => $this->url(),
|
||||
|
@ -830,10 +848,19 @@ class SmartButton implements SmartButtonInterface {
|
|||
'tagline' => $this->style_for_context( 'tagline', $this->context() ),
|
||||
),
|
||||
),
|
||||
'separate_buttons' => array(
|
||||
'card' => array(
|
||||
'id' => CardButtonGateway::ID,
|
||||
'wrapper' => '#ppc-button-' . CardButtonGateway::ID,
|
||||
'style' => array(
|
||||
'shape' => $this->style_for_context( 'shape', $this->context() ),
|
||||
// TODO: color black, white from the gateway settings.
|
||||
),
|
||||
),
|
||||
),
|
||||
'hosted_fields' => array(
|
||||
'wrapper' => '#ppcp-hosted-fields',
|
||||
'mini_cart_wrapper' => '#ppcp-hosted-fields-mini-cart',
|
||||
'labels' => array(
|
||||
'wrapper' => '#ppcp-hosted-fields',
|
||||
'labels' => array(
|
||||
'credit_card_number' => '',
|
||||
'cvv' => '',
|
||||
'mm_yy' => __( 'MM/YY', 'woocommerce-paypal-payments' ),
|
||||
|
@ -847,21 +874,36 @@ class SmartButton implements SmartButtonInterface {
|
|||
),
|
||||
'cardholder_name_required' => __( 'Cardholder\'s first and last name are required, please fill the checkout form required fields.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'valid_cards' => $this->dcc_applies->valid_cards(),
|
||||
'contingency' => $this->get_3ds_contingency(),
|
||||
'valid_cards' => $this->dcc_applies->valid_cards(),
|
||||
'contingency' => $this->get_3ds_contingency(),
|
||||
),
|
||||
'messages' => $this->message_values(),
|
||||
'labels' => array(
|
||||
'error' => array(
|
||||
'generic' => __(
|
||||
'error' => array(
|
||||
'generic' => __(
|
||||
'Something went wrong. Please try again or choose another payment source.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'js_validation' => __(
|
||||
'Required form fields are not filled or invalid.',
|
||||
'woocommerce-paypal-payments'
|
||||
'required' => array(
|
||||
'generic' => __(
|
||||
'Required form fields are not filled.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
// phpcs:ignore WordPress.WP.I18n
|
||||
'field' => __( '%s is a required field.', 'woocommerce' ),
|
||||
'elements' => array( // Map <form element name> => text for error messages.
|
||||
'terms' => __(
|
||||
'Please read and accept the terms and conditions to proceed with your order.',
|
||||
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
||||
'woocommerce'
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// phpcs:ignore WordPress.WP.I18n
|
||||
'billing_field' => _x( 'Billing %s', 'checkout-validation', 'woocommerce' ),
|
||||
// phpcs:ignore WordPress.WP.I18n
|
||||
'shipping_field' => _x( 'Shipping %s', 'checkout-validation', 'woocommerce' ),
|
||||
),
|
||||
'order_id' => 'pay-now' === $this->context() ? absint( $wp->query_vars['order-pay'] ) : 0,
|
||||
'single_product_buttons_enabled' => $this->settings->has( 'button_product_enabled' ) && $this->settings->get( 'button_product_enabled' ),
|
||||
|
@ -870,10 +912,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
);
|
||||
|
||||
if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) {
|
||||
unset( $localize['button']['mini_cart_style']['tagline'] );
|
||||
$localize['button']['mini_cart_style']['tagline'] = false;
|
||||
}
|
||||
if ( $this->style_for_context( 'layout', $this->context() ) !== 'horizontal' ) {
|
||||
unset( $localize['button']['style']['tagline'] );
|
||||
$localize['button']['style']['tagline'] = false;
|
||||
}
|
||||
|
||||
$this->request_data->dequeue_nonce_fix();
|
||||
|
@ -901,7 +943,9 @@ class SmartButton implements SmartButtonInterface {
|
|||
* @throws \WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting was not found.
|
||||
*/
|
||||
private function url(): string {
|
||||
$intent = ( $this->settings->has( 'intent' ) ) ? $this->settings->get( 'intent' ) : 'capture';
|
||||
$intent = ( $this->settings->has( 'intent' ) ) ? $this->settings->get( 'intent' ) : 'capture';
|
||||
$product_intent = $this->subscription_helper->current_product_is_subscription() ? 'authorize' : $intent;
|
||||
$other_context_intent = $this->subscription_helper->cart_contains_subscription() ? 'authorize' : $intent;
|
||||
|
||||
$params = array(
|
||||
'client-id' => $this->client_id,
|
||||
|
@ -910,9 +954,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
'components' => implode( ',', $this->components() ),
|
||||
'vault' => $this->can_save_vault_token() ? 'true' : 'false',
|
||||
'commit' => is_checkout() ? 'true' : 'false',
|
||||
'intent' => ( $this->subscription_helper->cart_contains_subscription() || $this->subscription_helper->current_product_is_subscription() )
|
||||
? 'authorize'
|
||||
: $intent,
|
||||
'intent' => $this->context() === 'product' ? $product_intent : $other_context_intent,
|
||||
);
|
||||
if (
|
||||
$this->environment->current_environment_is( Environment::SANDBOX )
|
||||
|
@ -933,7 +975,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
$is_dcc_enabled = $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' );
|
||||
|
||||
if ( is_checkout() && $is_dcc_enabled ) {
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
$is_separate_card_enabled = isset( $available_gateways[ CardButtonGateway::ID ] );
|
||||
|
||||
if ( is_checkout() && ( $is_dcc_enabled || $is_separate_card_enabled ) ) {
|
||||
$key = array_search( 'card', $disable_funding, true );
|
||||
if ( false !== $key ) {
|
||||
unset( $disable_funding[ $key ] );
|
||||
|
@ -942,7 +987,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
if ( $this->is_free_trial_cart() ) {
|
||||
$all_sources = array_keys( $this->all_funding_sources );
|
||||
if ( $is_dcc_enabled ) {
|
||||
if ( $is_dcc_enabled || $is_separate_card_enabled ) {
|
||||
$all_sources = array_diff( $all_sources, array( 'card' ) );
|
||||
}
|
||||
$disable_funding = $all_sources;
|
||||
|
@ -1018,6 +1063,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
if ( $this->load_button_component() ) {
|
||||
$components[] = 'buttons';
|
||||
$components[] = 'funding-eligibility';
|
||||
}
|
||||
if (
|
||||
$this->messages_apply->for_country()
|
||||
|
@ -1049,8 +1095,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
}
|
||||
if (
|
||||
$this->context() === 'product'
|
||||
&& $this->settings->has( 'button_product_enabled' )
|
||||
&& $this->settings->get( 'button_product_enabled' )
|
||||
&& (
|
||||
( $this->settings->has( 'button_product_enabled' ) && $this->settings->get( 'button_product_enabled' ) ) ||
|
||||
( $this->settings->has( 'message_product_enabled' ) && $this->settings->get( 'message_product_enabled' ) )
|
||||
)
|
||||
) {
|
||||
$load_buttons = true;
|
||||
}
|
||||
|
@ -1060,13 +1108,17 @@ class SmartButton implements SmartButtonInterface {
|
|||
) {
|
||||
$load_buttons = true;
|
||||
}
|
||||
|
||||
if (
|
||||
$this->context() === 'cart'
|
||||
&& $this->settings->has( 'button_cart_enabled' )
|
||||
&& $this->settings->get( 'button_cart_enabled' )
|
||||
&& (
|
||||
( $this->settings->has( 'button_cart_enabled' ) && $this->settings->get( 'button_cart_enabled' ) ) ||
|
||||
( $this->settings->has( 'message_cart_enabled' ) && $this->settings->get( 'message_cart_enabled' ) )
|
||||
)
|
||||
) {
|
||||
$load_buttons = true;
|
||||
}
|
||||
|
||||
if ( $this->context() === 'pay-now' ) {
|
||||
$load_buttons = true;
|
||||
}
|
||||
|
@ -1110,6 +1162,9 @@ class SmartButton implements SmartButtonInterface {
|
|||
if ( $source && $source->card() ) {
|
||||
return false; // Ignore for DCC.
|
||||
}
|
||||
if ( 'card' === $this->session_handler->funding_source() ) {
|
||||
return false; // Ignore for card buttons.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ use Exception;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
|
@ -46,11 +46,11 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
private $request_data;
|
||||
|
||||
/**
|
||||
* Contains purchase units based off the current WC cart.
|
||||
* The PurchaseUnit factory.
|
||||
*
|
||||
* @var CartRepository
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $repository;
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The product data store.
|
||||
|
@ -69,28 +69,28 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
/**
|
||||
* ChangeCartEndpoint constructor.
|
||||
*
|
||||
* @param \WC_Cart $cart The current WC cart object.
|
||||
* @param \WC_Shipping $shipping The current WC shipping object.
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param CartRepository $repository The repository for the current purchase items.
|
||||
* @param \WC_Data_Store $product_data_store The data store for products.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param \WC_Cart $cart The current WC cart object.
|
||||
* @param \WC_Shipping $shipping The current WC shipping object.
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The PurchaseUnit factory.
|
||||
* @param \WC_Data_Store $product_data_store The data store for products.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
\WC_Cart $cart,
|
||||
\WC_Shipping $shipping,
|
||||
RequestData $request_data,
|
||||
CartRepository $repository,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
\WC_Data_Store $product_data_store,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
$this->cart = $cart;
|
||||
$this->shipping = $shipping;
|
||||
$this->request_data = $request_data;
|
||||
$this->repository = $repository;
|
||||
$this->product_data_store = $product_data_store;
|
||||
$this->logger = $logger;
|
||||
$this->cart = $cart;
|
||||
$this->shipping = $shipping;
|
||||
$this->request_data = $request_data;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->product_data_store = $product_data_store;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -292,11 +292,7 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
* @return array
|
||||
*/
|
||||
private function generate_purchase_units(): array {
|
||||
return array_map(
|
||||
static function ( PurchaseUnit $line_item ): array {
|
||||
return $line_item->to_array();
|
||||
},
|
||||
$this->repository->all()
|
||||
);
|
||||
$pu = $this->purchase_unit_factory->from_wc_cart();
|
||||
return array( $pu->to_array() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface;
|
|||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Amount;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||
|
@ -23,11 +24,13 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\CardBillingMode;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
@ -48,13 +51,6 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The cart repository.
|
||||
*
|
||||
* @var CartRepository
|
||||
*/
|
||||
private $cart_repository;
|
||||
|
||||
/**
|
||||
* The PurchaseUnit factory.
|
||||
*
|
||||
|
@ -62,6 +58,13 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The shipping_preference factory.
|
||||
*
|
||||
* @var ShippingPreferenceFactory
|
||||
*/
|
||||
private $shipping_preference_factory;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
|
@ -105,11 +108,11 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
private $parsed_request_data;
|
||||
|
||||
/**
|
||||
* The array of purchase units for order.
|
||||
* The purchase unit for order.
|
||||
*
|
||||
* @var PurchaseUnit[]
|
||||
* @var PurchaseUnit|null
|
||||
*/
|
||||
private $purchase_units;
|
||||
private $purchase_unit;
|
||||
|
||||
/**
|
||||
* Whether a new user must be registered during checkout.
|
||||
|
@ -118,6 +121,13 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
*/
|
||||
private $registration_needed;
|
||||
|
||||
/**
|
||||
* The value of card_billing_data_mode from the settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $card_billing_data_mode;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -128,40 +138,43 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
/**
|
||||
* CreateOrderEndpoint constructor.
|
||||
*
|
||||
* @param RequestData $request_data The RequestData object.
|
||||
* @param CartRepository $cart_repository The CartRepository object.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The Purchaseunit factory.
|
||||
* @param OrderEndpoint $order_endpoint The OrderEndpoint object.
|
||||
* @param PayerFactory $payer_factory The PayerFactory object.
|
||||
* @param SessionHandler $session_handler The SessionHandler object.
|
||||
* @param Settings $settings The Settings object.
|
||||
* @param EarlyOrderHandler $early_order_handler The EarlyOrderHandler object.
|
||||
* @param bool $registration_needed Whether a new user must be registered during checkout.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @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 OrderEndpoint $order_endpoint The OrderEndpoint object.
|
||||
* @param PayerFactory $payer_factory The PayerFactory object.
|
||||
* @param SessionHandler $session_handler The SessionHandler object.
|
||||
* @param Settings $settings The Settings object.
|
||||
* @param EarlyOrderHandler $early_order_handler The EarlyOrderHandler object.
|
||||
* @param bool $registration_needed Whether a new user must be registered during checkout.
|
||||
* @param string $card_billing_data_mode The value of card_billing_data_mode from the settings.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
CartRepository $cart_repository,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
ShippingPreferenceFactory $shipping_preference_factory,
|
||||
OrderEndpoint $order_endpoint,
|
||||
PayerFactory $payer_factory,
|
||||
SessionHandler $session_handler,
|
||||
Settings $settings,
|
||||
EarlyOrderHandler $early_order_handler,
|
||||
bool $registration_needed,
|
||||
string $card_billing_data_mode,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
$this->request_data = $request_data;
|
||||
$this->cart_repository = $cart_repository;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$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->logger = $logger;
|
||||
$this->request_data = $request_data;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$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->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,21 +211,21 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
)
|
||||
);
|
||||
}
|
||||
$this->purchase_units = array( $this->purchase_unit_factory->from_wc_order( $wc_order ) );
|
||||
$this->purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
} else {
|
||||
$this->purchase_units = $this->cart_repository->all();
|
||||
$this->purchase_unit = $this->purchase_unit_factory->from_wc_cart();
|
||||
|
||||
// The cart does not have any info about payment method, so we must handle free trial here.
|
||||
if ( (
|
||||
CreditCardGateway::ID === $payment_method
|
||||
in_array( $payment_method, array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
||||
|| ( PayPalGateway::ID === $payment_method && 'card' === $funding_source )
|
||||
)
|
||||
&& $this->is_free_trial_cart()
|
||||
) {
|
||||
$this->purchase_units[0]->set_amount(
|
||||
$this->purchase_unit->set_amount(
|
||||
new Amount(
|
||||
new Money( 1.0, $this->purchase_units[0]->amount()->currency_code() ),
|
||||
$this->purchase_units[0]->amount()->breakdown()
|
||||
new Money( 1.0, $this->purchase_unit->amount()->currency_code() ),
|
||||
$this->purchase_unit->amount()->breakdown()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -329,17 +342,44 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
* phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
||||
*/
|
||||
private function create_paypal_order( \WC_Order $wc_order = null ): Order {
|
||||
$needs_shipping = WC()->cart instanceof \WC_Cart && WC()->cart->needs_shipping();
|
||||
$shipping_address_is_fix = $needs_shipping && 'checkout' === $this->parsed_request_data['context'];
|
||||
assert( $this->purchase_unit instanceof PurchaseUnit );
|
||||
|
||||
$funding_source = $this->parsed_request_data['funding_source'] ?? '';
|
||||
$payer = $this->payer( $this->parsed_request_data, $wc_order );
|
||||
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$this->purchase_unit,
|
||||
$this->parsed_request_data['context'],
|
||||
WC()->cart,
|
||||
$funding_source
|
||||
);
|
||||
|
||||
if ( 'card' === $funding_source ) {
|
||||
if ( CardBillingMode::MINIMAL_INPUT === $this->card_billing_data_mode ) {
|
||||
if ( ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS === $shipping_preference ) {
|
||||
if ( $payer ) {
|
||||
$payer->set_address( null );
|
||||
}
|
||||
}
|
||||
if ( ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING === $shipping_preference ) {
|
||||
if ( $payer ) {
|
||||
$payer->set_name( null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( CardBillingMode::NO_WC === $this->card_billing_data_mode ) {
|
||||
$payer = null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->api_endpoint->create(
|
||||
$this->purchase_units,
|
||||
$this->payer( $this->parsed_request_data, $wc_order ),
|
||||
array( $this->purchase_unit ),
|
||||
$shipping_preference,
|
||||
$payer,
|
||||
null,
|
||||
$this->payment_method(),
|
||||
'',
|
||||
$shipping_address_is_fix
|
||||
$this->payment_method()
|
||||
);
|
||||
} catch ( PayPalApiException $exception ) {
|
||||
// Looks like currently there is no proper way to validate the shipping address for PayPal,
|
||||
|
@ -354,17 +394,14 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
) ) {
|
||||
$this->logger->info( 'Invalid shipping address for order creation, retrying without it.' );
|
||||
|
||||
foreach ( $this->purchase_units as $purchase_unit ) {
|
||||
$purchase_unit->set_shipping( null );
|
||||
}
|
||||
$this->purchase_unit->set_shipping( null );
|
||||
|
||||
return $this->api_endpoint->create(
|
||||
$this->purchase_units,
|
||||
$this->payer( $this->parsed_request_data, $wc_order ),
|
||||
array( $this->purchase_unit ),
|
||||
$shipping_preference,
|
||||
$payer,
|
||||
null,
|
||||
$this->payment_method(),
|
||||
'',
|
||||
$shipping_address_is_fix
|
||||
$this->payment_method()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -873,6 +873,46 @@
|
|||
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3"
|
||||
integrity sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.0":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
|
||||
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
|
||||
dependencies:
|
||||
"@jridgewell/set-array" "^1.0.1"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.0.3":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
||||
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
||||
|
||||
"@jridgewell/set-array@^1.0.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
|
||||
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||
|
||||
"@jridgewell/source-map@^0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
|
||||
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10":
|
||||
version "1.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.9":
|
||||
version "0.3.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
|
||||
integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@types/eslint-scope@^3.7.0":
|
||||
version "3.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e"
|
||||
|
@ -1057,10 +1097,10 @@ acorn-import-assertions@^1.7.6:
|
|||
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz#580e3ffcae6770eebeec76c3b9723201e9d01f78"
|
||||
integrity sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==
|
||||
|
||||
acorn@^8.4.1:
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
|
||||
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
|
||||
acorn@^8.4.1, acorn@^8.5.0:
|
||||
version "8.7.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
|
||||
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
|
||||
|
||||
ajv-keywords@^3.5.2:
|
||||
version "3.5.2"
|
||||
|
@ -1313,6 +1353,11 @@ debug@^4.1.0, debug@^4.1.1:
|
|||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
deepmerge@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
|
||||
define-properties@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
||||
|
@ -2017,9 +2062,9 @@ signal-exit@^3.0.3:
|
|||
integrity sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==
|
||||
|
||||
source-map-support@~0.5.20:
|
||||
version "0.5.20"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9"
|
||||
integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==
|
||||
version "0.5.21"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
||||
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
|
||||
dependencies:
|
||||
buffer-from "^1.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
@ -2034,11 +2079,6 @@ source-map@^0.6.0, source-map@^0.6.1:
|
|||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@~0.7.2:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
|
||||
|
||||
strip-final-newline@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||
|
@ -2076,12 +2116,13 @@ terser-webpack-plugin@^5.1.3:
|
|||
terser "^5.7.2"
|
||||
|
||||
terser@^5.7.2:
|
||||
version "5.9.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351"
|
||||
integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==
|
||||
version "5.14.2"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
|
||||
integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
|
||||
dependencies:
|
||||
"@jridgewell/source-map" "^0.3.2"
|
||||
acorn "^8.5.0"
|
||||
commander "^2.20.0"
|
||||
source-map "~0.7.2"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles the onboard with Pay Upon Invoice setting.
|
||||
* Handles the onboard with Pay upon Invoice setting.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Onboarding\Endpoint
|
||||
*/
|
||||
|
|
|
@ -86,7 +86,7 @@ class OnboardingOptionsRenderer {
|
|||
$checked = '';
|
||||
}
|
||||
return '<li><label><input type="checkbox" id="ppcp-onboarding-pui" ' . $checked . '> ' .
|
||||
__( 'Onboard with Pay Upon Invoice', 'woocommerce-paypal-payments' ) . '
|
||||
__( 'Onboard with Pay upon Invoice', 'woocommerce-paypal-payments' ) . '
|
||||
</label></li>';
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,10 @@ class CancelController {
|
|||
return; // Ignore for DCC.
|
||||
}
|
||||
|
||||
if ( 'card' === $this->session_handler->funding_source() ) {
|
||||
return; // Ignore for card buttons.
|
||||
}
|
||||
|
||||
$url = add_query_arg( array( $param_name => wp_create_nonce( $nonce ) ), wc_get_checkout_url() );
|
||||
add_action(
|
||||
'woocommerce_review_order_after_submit',
|
||||
|
|
|
@ -24,13 +24,18 @@ return array(
|
|||
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
||||
$payer_factory = $container->get( 'api.factory.payer' );
|
||||
$environment = $container->get( 'onboarding.environment' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$authorized_payments_processor = $container->get( 'wcgateway.processor.authorized-payments' );
|
||||
return new RenewalHandler(
|
||||
$logger,
|
||||
$repository,
|
||||
$endpoint,
|
||||
$purchase_unit_factory,
|
||||
$container->get( 'api.factory.shipping-preference' ),
|
||||
$payer_factory,
|
||||
$environment
|
||||
$environment,
|
||||
$settings,
|
||||
$authorized_payments_processor
|
||||
);
|
||||
},
|
||||
'subscription.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository {
|
||||
|
|
|
@ -10,16 +10,20 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\Subscription;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class RenewalHandler
|
||||
|
@ -58,6 +62,13 @@ class RenewalHandler {
|
|||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The shipping_preference factory.
|
||||
*
|
||||
* @var ShippingPreferenceFactory
|
||||
*/
|
||||
private $shipping_preference_factory;
|
||||
|
||||
/**
|
||||
* The payer factory.
|
||||
*
|
||||
|
@ -72,31 +83,54 @@ class RenewalHandler {
|
|||
*/
|
||||
protected $environment;
|
||||
|
||||
/**
|
||||
* The settings
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* The processor for authorized payments.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor
|
||||
*/
|
||||
protected $authorized_payments_processor;
|
||||
|
||||
/**
|
||||
* RenewalHandler constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentTokenRepository $repository The payment token repository.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param PayerFactory $payer_factory The payer factory.
|
||||
* @param Environment $environment The environment.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentTokenRepository $repository The payment token repository.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
|
||||
* @param PayerFactory $payer_factory The payer factory.
|
||||
* @param Environment $environment The environment.
|
||||
* @param Settings $settings The Settings.
|
||||
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor.
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
PaymentTokenRepository $repository,
|
||||
OrderEndpoint $order_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
ShippingPreferenceFactory $shipping_preference_factory,
|
||||
PayerFactory $payer_factory,
|
||||
Environment $environment
|
||||
Environment $environment,
|
||||
Settings $settings,
|
||||
AuthorizedPaymentsProcessor $authorized_payments_processor
|
||||
) {
|
||||
|
||||
$this->logger = $logger;
|
||||
$this->repository = $repository;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->environment = $environment;
|
||||
$this->logger = $logger;
|
||||
$this->repository = $repository;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->environment = $environment;
|
||||
$this->settings = $settings;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,7 +167,7 @@ class RenewalHandler {
|
|||
*
|
||||
* @throws \Exception If customer cannot be read/found.
|
||||
*/
|
||||
private function process_order( \WC_Order $wc_order ) {
|
||||
private function process_order( \WC_Order $wc_order ): void {
|
||||
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$customer = new \WC_Customer( $user_id );
|
||||
|
@ -141,11 +175,16 @@ class RenewalHandler {
|
|||
if ( ! $token ) {
|
||||
return;
|
||||
}
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payer = $this->payer_factory->from_customer( $customer );
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payer = $this->payer_factory->from_customer( $customer );
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$purchase_unit,
|
||||
'renewal'
|
||||
);
|
||||
|
||||
$order = $this->order_endpoint->create(
|
||||
array( $purchase_unit ),
|
||||
$shipping_preference,
|
||||
$payer,
|
||||
$token
|
||||
);
|
||||
|
@ -163,6 +202,14 @@ class RenewalHandler {
|
|||
}
|
||||
|
||||
$this->handle_new_order_status( $order, $wc_order );
|
||||
|
||||
if ( $this->capture_authorized_downloads( $order ) && AuthorizedPaymentsProcessor::SUCCESSFUL === $this->authorized_payments_processor->process( $wc_order ) ) {
|
||||
$wc_order->add_order_note(
|
||||
__( 'Payment successfully captured.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'true' );
|
||||
$wc_order->update_status( 'completed' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,4 +260,39 @@ class RenewalHandler {
|
|||
|
||||
return current( $tokens );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if an order should be captured immediately.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
*
|
||||
* @return bool
|
||||
* @throws NotFoundException When a setting was not found.
|
||||
*/
|
||||
protected function capture_authorized_downloads( Order $order ): bool {
|
||||
if (
|
||||
! $this->settings->has( 'capture_for_virtual_only' )
|
||||
|| ! $this->settings->get( 'capture_for_virtual_only' )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'CAPTURE' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* We fetch the order again as the authorize endpoint (from which the Order derives)
|
||||
* drops the item's category, making it impossible to check, if purchase units contain
|
||||
* physical goods.
|
||||
*/
|
||||
$order = $this->order_endpoint->order( $order->id() );
|
||||
|
||||
foreach ( $order->purchase_units() as $unit ) {
|
||||
if ( $unit->contains_physical_goods() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,4 +57,17 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'vaulting.credit-card-handler' => function( ContainerInterface $container ): VaultedCreditCardHandler {
|
||||
return new VaultedCreditCardHandler(
|
||||
$container->get( 'subscription.helper' ),
|
||||
$container->get( 'vaulting.repository.payment-token' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'api.factory.payer' ),
|
||||
$container->get( 'api.factory.shipping-preference' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'onboarding.environment' ),
|
||||
$container->get( 'wcgateway.processor.authorized-payments' ),
|
||||
$container->get( 'wcgateway.settings' )
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -16,6 +16,7 @@ use WC_Order;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
|
@ -124,7 +125,7 @@ class PaymentTokenChecker {
|
|||
if ( $tokens || $subscription_behavior_when_vault_fails === 'capture_auth' ) {
|
||||
try {
|
||||
if ( $this->is_free_trial_order( $wc_order ) ) {
|
||||
if ( CreditCardGateway::ID === $wc_order->get_payment_method()
|
||||
if ( in_array( $wc_order->get_payment_method(), array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
||||
|| ( PayPalGateway::ID === $wc_order->get_payment_method() && 'card' === $wc_order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) )
|
||||
) {
|
||||
$order = $this->order_repository->for_wc_order( $wc_order );
|
||||
|
|
223
modules/ppcp-vaulting/src/VaultedCreditCardHandler.php
Normal file
223
modules/ppcp-vaulting/src/VaultedCreditCardHandler.php
Normal file
|
@ -0,0 +1,223 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles payment through saved credit card.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Vaulting
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use WC_Customer;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
|
||||
/**
|
||||
* Class VaultedCreditCardHandler
|
||||
*/
|
||||
class VaultedCreditCardHandler {
|
||||
|
||||
use OrderMetaTrait, TransactionIdHandlingTrait, PaymentsStatusHandlingTrait, FreeTrialHandlerTrait;
|
||||
|
||||
/**
|
||||
* The subscription helper.
|
||||
*
|
||||
* @var SubscriptionHelper
|
||||
*/
|
||||
protected $subscription_helper;
|
||||
|
||||
/**
|
||||
* The payment token repository.
|
||||
*
|
||||
* @var PaymentTokenRepository
|
||||
*/
|
||||
private $payment_token_repository;
|
||||
|
||||
/**
|
||||
* The purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The payer factory.
|
||||
*
|
||||
* @var PayerFactory
|
||||
*/
|
||||
private $payer_factory;
|
||||
|
||||
/**
|
||||
* The shipping_preference factory.
|
||||
*
|
||||
* @var ShippingPreferenceFactory
|
||||
*/
|
||||
private $shipping_preference_factory;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
private $order_endpoint;
|
||||
|
||||
/**
|
||||
* The environment.
|
||||
*
|
||||
* @var Environment
|
||||
*/
|
||||
protected $environment;
|
||||
|
||||
/**
|
||||
* The processor for authorized payments.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor
|
||||
*/
|
||||
protected $authorized_payments_processor;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* VaultedCreditCardHandler constructor
|
||||
*
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param PayerFactory $payer_factory The payer factory.
|
||||
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param Environment $environment The environment.
|
||||
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The processor for authorized payments.
|
||||
* @param ContainerInterface $config The settings.
|
||||
*/
|
||||
public function __construct(
|
||||
SubscriptionHelper $subscription_helper,
|
||||
PaymentTokenRepository $payment_token_repository,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
PayerFactory $payer_factory,
|
||||
ShippingPreferenceFactory $shipping_preference_factory,
|
||||
OrderEndpoint $order_endpoint,
|
||||
Environment $environment,
|
||||
AuthorizedPaymentsProcessor $authorized_payments_processor,
|
||||
ContainerInterface $config
|
||||
) {
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->environment = $environment;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the saved credit card payment.
|
||||
*
|
||||
* @param string $saved_credit_card The saved credit card.
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @return WC_Order
|
||||
* @throws RuntimeException When something went wrong with the payment process.
|
||||
*/
|
||||
public function handle_payment(
|
||||
string $saved_credit_card,
|
||||
WC_Order $wc_order
|
||||
): WC_Order {
|
||||
|
||||
$change_payment = filter_input( INPUT_POST, 'woocommerce_change_payment', FILTER_SANITIZE_STRING );
|
||||
if (
|
||||
$change_payment
|
||||
&& $this->subscription_helper->has_subscription( $wc_order->get_id() )
|
||||
&& $this->subscription_helper->is_subscription_change_payment()
|
||||
&& $saved_credit_card
|
||||
) {
|
||||
update_post_meta( $wc_order->get_id(), 'payment_token_id', $saved_credit_card );
|
||||
return $wc_order;
|
||||
}
|
||||
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( $wc_order->get_customer_id() );
|
||||
$selected_token = null;
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->id() === $saved_credit_card ) {
|
||||
$selected_token = $token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! $selected_token ) {
|
||||
throw new RuntimeException( 'Saved card token not found.' );
|
||||
}
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payer = $this->payer_factory->from_wc_order( $wc_order );
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$purchase_unit,
|
||||
''
|
||||
);
|
||||
|
||||
try {
|
||||
$order = $this->order_endpoint->create(
|
||||
array( $purchase_unit ),
|
||||
$shipping_preference,
|
||||
$payer,
|
||||
$selected_token
|
||||
);
|
||||
|
||||
$this->add_paypal_meta( $wc_order, $order, $this->environment );
|
||||
|
||||
if ( ! $order->status()->is( OrderStatus::COMPLETED ) ) {
|
||||
throw new RuntimeException( "Unexpected status for order {$order->id()} using a saved card: {$order->status()->name()}." );
|
||||
}
|
||||
|
||||
if ( ! in_array(
|
||||
$order->intent(),
|
||||
array( 'CAPTURE', 'AUTHORIZE' ),
|
||||
true
|
||||
) ) {
|
||||
throw new RuntimeException( "Could neither capture nor authorize order {$order->id()} using a saved card. Status: {$order->status()->name()}. Intent: {$order->intent()}." );
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'AUTHORIZE' ) {
|
||||
$order = $this->order_endpoint->authorize( $order );
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' );
|
||||
}
|
||||
|
||||
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
||||
if ( $transaction_id ) {
|
||||
$this->update_transaction_id( $transaction_id, $wc_order );
|
||||
}
|
||||
|
||||
$this->handle_new_order_status( $order, $wc_order );
|
||||
|
||||
if ( $this->is_free_trial_order( $wc_order ) ) {
|
||||
$this->authorized_payments_processor->void_authorizations( $order );
|
||||
$wc_order->payment_complete();
|
||||
} elseif ( $this->config->has( 'intent' ) && strtoupper( (string) $this->config->get( 'intent' ) ) === 'CAPTURE' ) {
|
||||
$this->authorized_payments_processor->capture_authorized_payment( $wc_order );
|
||||
}
|
||||
|
||||
return $wc_order;
|
||||
} catch ( RuntimeException $error ) {
|
||||
throw new RuntimeException( $error->getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -873,6 +873,46 @@
|
|||
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3"
|
||||
integrity sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.0":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
|
||||
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
|
||||
dependencies:
|
||||
"@jridgewell/set-array" "^1.0.1"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.0.3":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
||||
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
||||
|
||||
"@jridgewell/set-array@^1.0.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
|
||||
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||
|
||||
"@jridgewell/source-map@^0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
|
||||
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10":
|
||||
version "1.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.9":
|
||||
version "0.3.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
|
||||
integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@types/eslint-scope@^3.7.0":
|
||||
version "3.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e"
|
||||
|
@ -1057,10 +1097,10 @@ acorn-import-assertions@^1.7.6:
|
|||
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz#580e3ffcae6770eebeec76c3b9723201e9d01f78"
|
||||
integrity sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==
|
||||
|
||||
acorn@^8.4.1:
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
|
||||
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
|
||||
acorn@^8.4.1, acorn@^8.5.0:
|
||||
version "8.7.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
|
||||
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
|
||||
|
||||
ajv-keywords@^3.5.2:
|
||||
version "3.5.2"
|
||||
|
@ -2017,9 +2057,9 @@ signal-exit@^3.0.3:
|
|||
integrity sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==
|
||||
|
||||
source-map-support@~0.5.20:
|
||||
version "0.5.20"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9"
|
||||
integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==
|
||||
version "0.5.21"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
||||
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
|
||||
dependencies:
|
||||
buffer-from "^1.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
@ -2034,11 +2074,6 @@ source-map@^0.6.0, source-map@^0.6.1:
|
|||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@~0.7.2:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
|
||||
|
||||
strip-final-newline@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||
|
@ -2076,12 +2111,13 @@ terser-webpack-plugin@^5.1.3:
|
|||
terser "^5.7.2"
|
||||
|
||||
terser@^5.7.2:
|
||||
version "5.9.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351"
|
||||
integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==
|
||||
version "5.14.2"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
|
||||
integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
|
||||
dependencies:
|
||||
"@jridgewell/source-map" "^0.3.2"
|
||||
acorn "^8.5.0"
|
||||
commander "^2.20.0"
|
||||
source-map "~0.7.2"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
|
|
18
modules/ppcp-wc-gateway/assets/images/oxxo.svg
Normal file
18
modules/ppcp-wc-gateway/assets/images/oxxo.svg
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="42px" height="20px" viewBox="0 0 42 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>logo OXXO</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs/>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="SPB_&_AltPay_NewAssets" transform="translate(-100.000000, -159.000000)">
|
||||
<g id="logo-OXXO" transform="translate(100.000000, 159.000000)">
|
||||
<path d="M0.142456528,1.48437917 C0.142456528,0.77043992 0.728159303,0.186243119 1.44446761,0.186243119 L40.6503931,0.186243119 C41.3667014,0.186243119 41.9524042,0.77043992 41.9524042,1.48437917 L41.9524042,18.1011373 C41.9524042,18.8150765 41.3667014,19.3990362 40.6503931,19.3990362 L1.44446761,19.3990362 C0.728159303,19.3990362 0.142456528,18.8150765 0.142456528,18.1011373 L0.142456528,1.48437917 Z" id="Fill-2" fill="#EDA42D"/>
|
||||
<polygon id="Fill-4" fill="#FEFEFE" points="0.142480318 17.5124813 41.952428 17.5124813 41.952428 2.07265562 0.142480318 2.07265562"/>
|
||||
<path d="M35.5752619,6.08262231 C33.662331,6.08262231 32.1029152,7.63763417 32.1029152,9.54463469 C32.1029152,11.4511608 33.662331,13.0064099 35.5752619,13.0064099 C37.4877171,13.0064099 39.0471329,11.4511608 39.0471329,9.54463469 C39.0471329,7.63763417 37.4877171,6.08262231 35.5752619,6.08262231" id="Fill-6" fill="#EC1D24"/>
|
||||
<path d="M6.95585459,6.08262231 C5.04268574,6.08262231 3.48326994,7.63763417 3.48326994,9.54463469 C3.48326994,11.4511608 5.04268574,13.0064099 6.95585459,13.0064099 C8.86807185,13.0064099 10.4277255,11.4511608 10.4277255,9.54463469 C10.4277255,7.63763417 8.86807185,6.08262231 6.95585459,6.08262231" id="Fill-7" fill="#EC1D24"/>
|
||||
<path d="M35.5752619,15.0141446 C32.5537303,15.0141446 30.0893537,12.5573397 30.0893537,9.54480072 C30.0893537,6.53155015 32.5537303,4.07521964 35.5752619,4.07521964 C38.5970315,4.07521964 41.0609322,6.53155015 41.0609322,9.54480072 C41.0609322,12.5573397 38.5970315,15.0141446 35.5752619,15.0141446 Z M12.4411918,9.54480072 C12.4411918,12.5573397 9.97729109,15.0141446 6.95575943,15.0141446 C3.93351408,15.0141446 1.46985124,12.5573397 1.46985124,9.54480072 C1.46985124,6.53155015 3.93351408,4.07521964 6.95575943,4.07521964 C9.97729109,4.07521964 12.4411918,6.53155015 12.4411918,9.54480072 Z M35.3028697,3.03585692 C32.0884035,2.9620911 30.5772808,5.01709763 28.384107,7.55170056 L26.3151155,9.94232969 L29.591435,13.8526295 C30.3719756,15.0542296 28.8822636,16.2465793 27.9580332,15.1472077 L24.9288888,11.5447794 L21.9772989,14.9562705 C21.0373673,16.0421223 19.5645461,14.8288999 20.3617394,13.6386849 L23.5659761,9.92382894 L21.4667717,7.42693908 L22.8173138,5.75949957 L24.9522028,8.31639828 L26.7923372,6.18217058 C27.6953948,5.13569219 28.6162946,3.74884741 29.8098246,3.03585692 L0.142385159,3.03585692 L0.142385159,16.549707 L7.07875226,16.549707 C10.2934564,16.549707 11.7529554,14.6332189 13.8866549,12.0492806 L15.8999784,9.61097649 L12.5334959,5.77752594 C11.726073,4.59418943 13.1874752,3.36815887 14.1371606,4.44594623 L17.2483795,7.9779294 L20.1209875,4.49931378 C21.0354641,3.39164059 22.5356435,4.57118208 21.7662842,5.77942346 L18.6486421,9.56757088 L20.8051797,12.0153626 L19.4463112,13.6197098 L17.2997653,11.2058361 L15.5095892,13.3813347 C14.6310351,14.4484486 13.7415376,15.8094397 12.5646605,16.549707 L41.9523328,16.549707 L41.9523328,3.03585692 L35.3028697,3.03585692 Z" id="Fill-8" fill="#EC1D24"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
18
modules/ppcp-wc-gateway/resources/js/oxxo.js
Normal file
18
modules/ppcp-wc-gateway/resources/js/oxxo.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
function() {
|
||||
jQuery('form.checkout').on('checkout_place_order_success', function(type, data) {
|
||||
if(data.payer_action && data.payer_action !== '') {
|
||||
const width = screen.width / 2;
|
||||
const height = screen.height / 2;
|
||||
const left = width - (width / 2);
|
||||
const top = height - (height / 2);
|
||||
window.open(
|
||||
data.payer_action,
|
||||
'_blank',
|
||||
'popup, width=' + width + ', height=' + height + ', top=' + top + ', left=' + left
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
|
@ -29,7 +29,11 @@ use WooCommerce\PayPalCommerce\WcGateway\Checkout\CheckoutPayPalAddressPreset;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Checkout\DisableGateways;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXO;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSessionId;
|
||||
|
@ -38,13 +42,14 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSourceFac
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\GatewayWithoutPayPalAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
@ -55,11 +60,10 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
|||
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||
|
||||
return array(
|
||||
'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
|
||||
'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
|
||||
$order_processor = $container->get( 'wcgateway.order-processor' );
|
||||
$settings_renderer = $container->get( 'wcgateway.settings.render' );
|
||||
$funding_source_renderer = $container->get( 'wcgateway.funding-source.renderer' );
|
||||
$authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
|
||||
|
@ -68,8 +72,6 @@ return array(
|
|||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
|
||||
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$environment = $container->get( 'onboarding.environment' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$api_shop_country = $container->get( 'api.shop.country' );
|
||||
|
@ -77,7 +79,6 @@ return array(
|
|||
$settings_renderer,
|
||||
$funding_source_renderer,
|
||||
$order_processor,
|
||||
$authorized_payments,
|
||||
$settings,
|
||||
$session_handler,
|
||||
$refund_processor,
|
||||
|
@ -88,70 +89,74 @@ return array(
|
|||
$environment,
|
||||
$payment_token_repository,
|
||||
$logger,
|
||||
$payments_endpoint,
|
||||
$order_endpoint,
|
||||
$api_shop_country
|
||||
);
|
||||
},
|
||||
'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
|
||||
'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
|
||||
$order_processor = $container->get( 'wcgateway.order-processor' );
|
||||
$settings_renderer = $container->get( 'wcgateway.settings.render' );
|
||||
$authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$module_url = $container->get( 'wcgateway.url' );
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
$transaction_url_provider = $container->get( 'wcgateway.transaction-url-provider' );
|
||||
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
||||
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
||||
$payer_factory = $container->get( 'api.factory.payer' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$environment = $container->get( 'onboarding.environment' );
|
||||
$vaulted_credit_card_handler = $container->get( 'vaulting.credit-card-handler' );
|
||||
return new CreditCardGateway(
|
||||
$settings_renderer,
|
||||
$order_processor,
|
||||
$authorized_payments,
|
||||
$settings,
|
||||
$module_url,
|
||||
$session_handler,
|
||||
$refund_processor,
|
||||
$state,
|
||||
$transaction_url_provider,
|
||||
$payment_token_repository,
|
||||
$purchase_unit_factory,
|
||||
$payer_factory,
|
||||
$order_endpoint,
|
||||
$subscription_helper,
|
||||
$logger,
|
||||
$environment,
|
||||
$payments_endpoint
|
||||
$payments_endpoint,
|
||||
$vaulted_credit_card_handler
|
||||
);
|
||||
},
|
||||
'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways {
|
||||
'wcgateway.card-button-gateway' => static function ( ContainerInterface $container ): CardButtonGateway {
|
||||
return new CardButtonGateway(
|
||||
$container->get( 'wcgateway.settings.render' ),
|
||||
$container->get( 'wcgateway.order-processor' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'onboarding.state' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' ),
|
||||
$container->get( 'subscription.helper' ),
|
||||
$container->get( 'wcgateway.settings.allow_card_button_gateway.default' ),
|
||||
$container->get( 'onboarding.environment' ),
|
||||
$container->get( 'vaulting.repository.payment-token' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways {
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new DisableGateways( $session_handler, $settings );
|
||||
},
|
||||
'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool {
|
||||
'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool {
|
||||
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
|
||||
$tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
|
||||
return 'wc-settings' === $page && 'checkout' === $tab;
|
||||
},
|
||||
|
||||
'wcgateway.is-ppcp-settings-page' => static function ( ContainerInterface $container ): bool {
|
||||
'wcgateway.is-ppcp-settings-page' => static function ( ContainerInterface $container ): bool {
|
||||
if ( ! $container->get( 'wcgateway.is-wc-payments-page' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
|
||||
return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID, PayUponInvoiceGateway::ID ), true );
|
||||
return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID, PayUponInvoiceGateway::ID, CardButtonGateway::ID, OXXOGateway::ID ), true );
|
||||
},
|
||||
|
||||
'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string {
|
||||
'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string {
|
||||
if ( ! $container->get( 'wcgateway.is-ppcp-settings-page' ) ) {
|
||||
return '';
|
||||
}
|
||||
|
@ -162,36 +167,70 @@ return array(
|
|||
return $ppcp_tab ? $ppcp_tab : $section;
|
||||
},
|
||||
|
||||
'wcgateway.settings' => static function ( ContainerInterface $container ): Settings {
|
||||
'wcgateway.settings' => static function ( ContainerInterface $container ): Settings {
|
||||
return new Settings();
|
||||
},
|
||||
'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice {
|
||||
'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice {
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new ConnectAdminNotice( $state, $settings );
|
||||
},
|
||||
'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $container ): DccWithoutPayPalAdminNotice {
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$is_payments_page = $container->get( 'wcgateway.is-wc-payments-page' );
|
||||
$is_ppcp_settings_page = $container->get( 'wcgateway.is-ppcp-settings-page' );
|
||||
return new DccWithoutPayPalAdminNotice( $state, $settings, $is_payments_page, $is_ppcp_settings_page );
|
||||
'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $container ): GatewayWithoutPayPalAdminNotice {
|
||||
return new GatewayWithoutPayPalAdminNotice(
|
||||
CreditCardGateway::ID,
|
||||
$container->get( 'onboarding.state' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'wcgateway.is-wc-payments-page' ),
|
||||
$container->get( 'wcgateway.is-ppcp-settings-page' )
|
||||
);
|
||||
},
|
||||
'wcgateway.notice.authorize-order-action' =>
|
||||
'wcgateway.notice.card-button-without-paypal' => static function ( ContainerInterface $container ): GatewayWithoutPayPalAdminNotice {
|
||||
return new GatewayWithoutPayPalAdminNotice(
|
||||
CardButtonGateway::ID,
|
||||
$container->get( 'onboarding.state' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'wcgateway.is-wc-payments-page' ),
|
||||
$container->get( 'wcgateway.is-ppcp-settings-page' )
|
||||
);
|
||||
},
|
||||
'wcgateway.notice.authorize-order-action' =>
|
||||
static function ( ContainerInterface $container ): AuthorizeOrderActionNotice {
|
||||
return new AuthorizeOrderActionNotice();
|
||||
},
|
||||
'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
|
||||
'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
|
||||
return new SectionsRenderer(
|
||||
$container->get( 'wcgateway.current-ppcp-settings-page-id' ),
|
||||
$container->get( 'api.shop.country' )
|
||||
$container->get( 'wcgateway.settings.sections' )
|
||||
);
|
||||
},
|
||||
'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus {
|
||||
'wcgateway.settings.sections' => static function ( ContainerInterface $container ): array {
|
||||
$sections = array(
|
||||
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
|
||||
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
|
||||
CardButtonGateway::ID => __( 'PayPal Card Button', 'woocommerce-paypal-payments' ),
|
||||
OXXOGateway::ID => __( 'OXXO', 'woocommerce-paypal-payments' ),
|
||||
PayUponInvoiceGateway::ID => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ),
|
||||
WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
|
||||
// Remove for all not registered in WC gateways that cannot render anything in this case.
|
||||
$gateways = WC()->payment_gateways->payment_gateways();
|
||||
foreach ( array_diff(
|
||||
array_keys( $sections ),
|
||||
array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID )
|
||||
) as $id ) {
|
||||
if ( ! isset( $gateways[ $id ] ) ) {
|
||||
unset( $sections[ $id ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $sections;
|
||||
},
|
||||
'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new SettingsStatus( $settings );
|
||||
},
|
||||
'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer {
|
||||
'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
$fields = $container->get( 'wcgateway.settings.fields' );
|
||||
|
@ -211,7 +250,7 @@ return array(
|
|||
$page_id
|
||||
);
|
||||
},
|
||||
'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener {
|
||||
'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$fields = $container->get( 'wcgateway.settings.fields' );
|
||||
$webhook_registrar = $container->get( 'webhook.registrar' );
|
||||
|
@ -233,7 +272,7 @@ return array(
|
|||
$signup_link_ids
|
||||
);
|
||||
},
|
||||
'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor {
|
||||
'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor {
|
||||
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
|
@ -258,13 +297,13 @@ return array(
|
|||
$order_helper
|
||||
);
|
||||
},
|
||||
'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor {
|
||||
'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor {
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
return new RefundProcessor( $order_endpoint, $payments_endpoint, $logger );
|
||||
},
|
||||
'wcgateway.processor.authorized-payments' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor {
|
||||
'wcgateway.processor.authorized-payments' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor {
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
|
@ -280,23 +319,23 @@ return array(
|
|||
$subscription_helper
|
||||
);
|
||||
},
|
||||
'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
|
||||
'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
|
||||
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
||||
return new RenderAuthorizeAction( $column );
|
||||
},
|
||||
'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
|
||||
'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
|
||||
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
||||
return new PaymentStatusOrderDetail( $column );
|
||||
},
|
||||
'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn {
|
||||
'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new OrderTablePaymentStatusColumn( $settings );
|
||||
},
|
||||
'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer {
|
||||
'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer {
|
||||
return new FeesRenderer();
|
||||
},
|
||||
|
||||
'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
|
||||
'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
|
||||
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
assert( $state instanceof State );
|
||||
|
@ -878,6 +917,40 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'card_billing_data_mode' => array(
|
||||
'title' => __( 'Card billing data handling', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Using the WC form data increases convenience for the customers, but can cause issues if card details do not match the billing data in the checkout form.', 'woocommerce-paypal-payments' ),
|
||||
'default' => $container->get( 'wcgateway.settings.card_billing_data_mode.default' ),
|
||||
'options' => array(
|
||||
CardBillingMode::USE_WC => __( 'Use WC checkout form data (do not show any address fields)', 'woocommerce-paypal-payments' ),
|
||||
CardBillingMode::MINIMAL_INPUT => __( 'Request only name and postal code', 'woocommerce-paypal-payments' ),
|
||||
CardBillingMode::NO_WC => __( 'Do not use WC checkout form data (request all address fields)', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => array( 'paypal', CardButtonGateway::ID ),
|
||||
),
|
||||
'allow_card_button_gateway' => array(
|
||||
'title' => __( 'Separate Card Button from PayPal gateway', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'desc_tip' => true,
|
||||
'label' => __( 'Enable a separate payment gateway for the branded PayPal Debit or Credit Card button.', 'woocommerce-paypal-payments' ),
|
||||
'description' => __( 'By default, the Debit or Credit Card button is displayed in the PayPal Checkout payment gateway. This setting creates a second gateway for the Card button.', 'woocommerce-paypal-payments' ),
|
||||
'default' => $container->get( 'wcgateway.settings.allow_card_button_gateway.default' ),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
|
||||
// General button styles.
|
||||
'button_style_heading' => array(
|
||||
|
@ -2088,10 +2161,14 @@ return array(
|
|||
$fields['disable_cards']['options'] = $card_options;
|
||||
$fields['card_icons']['options'] = array_merge( $dark_versions, $card_options );
|
||||
|
||||
if ( defined( 'PPCP_FLAG_SEPARATE_APM_BUTTONS' ) && PPCP_FLAG_SEPARATE_APM_BUTTONS === false ) {
|
||||
unset( $fields['allow_card_button_gateway'] );
|
||||
}
|
||||
|
||||
return $fields;
|
||||
},
|
||||
|
||||
'wcgateway.all-funding-sources' => static function( ContainerInterface $container ): array {
|
||||
'wcgateway.all-funding-sources' => static function( ContainerInterface $container ): array {
|
||||
return array(
|
||||
'card' => _x( 'Credit or debit cards', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'credit' => _x( 'Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
|
@ -2109,28 +2186,28 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
'wcgateway.checkout.address-preset' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset {
|
||||
'wcgateway.checkout.address-preset' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset {
|
||||
|
||||
return new CheckoutPayPalAddressPreset(
|
||||
$container->get( 'session.handler' )
|
||||
);
|
||||
},
|
||||
'wcgateway.url' => static function ( ContainerInterface $container ): string {
|
||||
'wcgateway.url' => static function ( ContainerInterface $container ): string {
|
||||
return plugins_url(
|
||||
$container->get( 'wcgateway.relative-path' ),
|
||||
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
},
|
||||
'wcgateway.relative-path' => static function( ContainerInterface $container ): string {
|
||||
'wcgateway.relative-path' => static function( ContainerInterface $container ): string {
|
||||
return 'modules/ppcp-wc-gateway/';
|
||||
},
|
||||
'wcgateway.absolute-path' => static function( ContainerInterface $container ): string {
|
||||
'wcgateway.absolute-path' => static function( ContainerInterface $container ): string {
|
||||
return plugin_dir_path(
|
||||
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
||||
) .
|
||||
$container->get( 'wcgateway.relative-path' );
|
||||
},
|
||||
'wcgateway.endpoint.return-url' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint {
|
||||
'wcgateway.endpoint.return-url' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint {
|
||||
$gateway = $container->get( 'wcgateway.paypal-gateway' );
|
||||
$endpoint = $container->get( 'api.endpoint.order' );
|
||||
$prefix = $container->get( 'api.prefix' );
|
||||
|
@ -2141,40 +2218,43 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
'wcgateway.transaction-url-sandbox' => static function ( ContainerInterface $container ): string {
|
||||
'wcgateway.transaction-url-sandbox' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
||||
},
|
||||
|
||||
'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string {
|
||||
'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
||||
},
|
||||
|
||||
'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
|
||||
'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
|
||||
$sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' );
|
||||
$live_url_base = $container->get( 'wcgateway.transaction-url-live' );
|
||||
|
||||
return new TransactionUrlProvider( $sandbox_url_base, $live_url_base );
|
||||
},
|
||||
|
||||
'wcgateway.helper.dcc-product-status' => static function ( ContainerInterface $container ) : DCCProductStatus {
|
||||
'wcgateway.helper.dcc-product-status' => static function ( ContainerInterface $container ) : DCCProductStatus {
|
||||
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$partner_endpoint = $container->get( 'api.endpoint.partners' );
|
||||
return new DCCProductStatus( $settings, $partner_endpoint );
|
||||
},
|
||||
|
||||
'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers {
|
||||
'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers {
|
||||
return new MessagesDisclaimers(
|
||||
$container->get( 'api.shop.country' )
|
||||
);
|
||||
},
|
||||
|
||||
'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer {
|
||||
'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer {
|
||||
return new FundingSourceRenderer(
|
||||
$container->get( 'wcgateway.settings' )
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-order-endpoint' => static function ( ContainerInterface $container ): PayUponInvoiceOrderEndpoint {
|
||||
'wcgateway.checkout-helper' => static function ( ContainerInterface $container ): CheckoutHelper {
|
||||
return new CheckoutHelper();
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-order-endpoint' => static function ( ContainerInterface $container ): PayUponInvoiceOrderEndpoint {
|
||||
return new PayUponInvoiceOrderEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
|
@ -2183,10 +2263,10 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-payment-source-factory' => static function ( ContainerInterface $container ): PaymentSourceFactory {
|
||||
'wcgateway.pay-upon-invoice-payment-source-factory' => static function ( ContainerInterface $container ): PaymentSourceFactory {
|
||||
return new PaymentSourceFactory();
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-gateway' => static function ( ContainerInterface $container ): PayUponInvoiceGateway {
|
||||
'wcgateway.pay-upon-invoice-gateway' => static function ( ContainerInterface $container ): PayUponInvoiceGateway {
|
||||
return new PayUponInvoiceGateway(
|
||||
$container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
|
@ -2194,16 +2274,17 @@ return array(
|
|||
$container->get( 'onboarding.environment' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' ),
|
||||
$container->get( 'wcgateway.pay-upon-invoice-helper' )
|
||||
$container->get( 'wcgateway.pay-upon-invoice-helper' ),
|
||||
$container->get( 'wcgateway.checkout-helper' )
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId {
|
||||
'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId {
|
||||
return new FraudNetSessionId();
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-fraudnet-source-website-id' => static function ( ContainerInterface $container ): FraudNetSourceWebsiteId {
|
||||
return new FraudNetSourceWebsiteId( $container->get( 'api.merchant_id' ) );
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-fraudnet' => static function ( ContainerInterface $container ): FraudNet {
|
||||
'wcgateway.pay-upon-invoice-fraudnet' => static function ( ContainerInterface $container ): FraudNet {
|
||||
$session_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-session-id' );
|
||||
$source_website_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-source-website-id' );
|
||||
return new FraudNet(
|
||||
|
@ -2211,16 +2292,18 @@ return array(
|
|||
(string) $source_website_id()
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-helper' => static function( ContainerInterface $container ): PayUponInvoiceHelper {
|
||||
return new PayUponInvoiceHelper();
|
||||
'wcgateway.pay-upon-invoice-helper' => static function( ContainerInterface $container ): PayUponInvoiceHelper {
|
||||
return new PayUponInvoiceHelper(
|
||||
$container->get( 'wcgateway.checkout-helper' )
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-product-status' => static function( ContainerInterface $container ): PayUponInvoiceProductStatus {
|
||||
'wcgateway.pay-upon-invoice-product-status' => static function( ContainerInterface $container ): PayUponInvoiceProductStatus {
|
||||
return new PayUponInvoiceProductStatus(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' )
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
|
||||
'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
|
||||
return new PayUponInvoice(
|
||||
$container->get( 'wcgateway.url' ),
|
||||
$container->get( 'wcgateway.pay-upon-invoice-fraudnet' ),
|
||||
|
@ -2233,10 +2316,37 @@ return array(
|
|||
$container->get( 'wcgateway.is-ppcp-settings-page' ),
|
||||
$container->get( 'wcgateway.current-ppcp-settings-page-id' ),
|
||||
$container->get( 'wcgateway.pay-upon-invoice-product-status' ),
|
||||
$container->get( 'wcgateway.pay-upon-invoice-helper' )
|
||||
$container->get( 'wcgateway.pay-upon-invoice-helper' ),
|
||||
$container->get( 'wcgateway.checkout-helper' ),
|
||||
$container->get( 'api.factory.capture' )
|
||||
);
|
||||
},
|
||||
'wcgateway.logging.is-enabled' => function ( ContainerInterface $container ) : bool {
|
||||
'wcgateway.oxxo' => static function( ContainerInterface $container ): OXXO {
|
||||
return new OXXO(
|
||||
$container->get( 'wcgateway.checkout-helper' ),
|
||||
$container->get( 'wcgateway.url' ),
|
||||
$container->get( 'ppcp.asset-version' )
|
||||
);
|
||||
},
|
||||
'wcgateway.oxxo-gateway' => static function( ContainerInterface $container ): OXXOGateway {
|
||||
return new OXXOGateway(
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'api.factory.shipping-preference' ),
|
||||
$container->get( 'wcgateway.url' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'wcgateway.endpoint.oxxo' => static function ( ContainerInterface $container ): OXXOEndpoint {
|
||||
return new OXXOEndpoint(
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'api.factory.shipping-preference' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'wcgateway.logging.is-enabled' => function ( ContainerInterface $container ) : bool {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
|
||||
/**
|
||||
|
@ -2248,7 +2358,7 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool {
|
||||
'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool {
|
||||
try {
|
||||
$token = $container->get( 'api.bearer' )->bearer();
|
||||
return $token->vaulting_available();
|
||||
|
@ -2257,7 +2367,7 @@ return array(
|
|||
}
|
||||
},
|
||||
|
||||
'button.helper.vaulting-label' => static function ( ContainerInterface $container ): string {
|
||||
'button.helper.vaulting-label' => static function ( ContainerInterface $container ): string {
|
||||
$vaulting_label = __( 'Enable saved cards and subscription features on your store.', 'woocommerce-paypal-payments' );
|
||||
|
||||
if ( ! $container->get( 'wcgateway.helper.vaulting-scope' ) ) {
|
||||
|
@ -2279,7 +2389,7 @@ return array(
|
|||
return $vaulting_label;
|
||||
},
|
||||
|
||||
'wcgateway.settings.fields.pay-later-label' => static function ( ContainerInterface $container ): string {
|
||||
'wcgateway.settings.fields.pay-later-label' => static function ( ContainerInterface $container ): string {
|
||||
$pay_later_label = '<span class="ppcp-pay-later-enabled-label">%s</span>';
|
||||
$pay_later_label .= '<span class="ppcp-pay-later-disabled-label">';
|
||||
$pay_later_label .= __( "You have PayPal vaulting enabled, that's why Pay Later Messaging options are unavailable now. You cannot use both features at the same time.", 'woocommerce-paypal-payments' );
|
||||
|
@ -2287,4 +2397,32 @@ return array(
|
|||
|
||||
return $pay_later_label;
|
||||
},
|
||||
|
||||
'wcgateway.settings.card_billing_data_mode.default' => static function ( ContainerInterface $container ): string {
|
||||
return $container->get( 'api.shop.is-latin-america' ) ? CardBillingMode::MINIMAL_INPUT : CardBillingMode::USE_WC;
|
||||
},
|
||||
'wcgateway.settings.card_billing_data_mode' => static function ( ContainerInterface $container ): string {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof ContainerInterface );
|
||||
|
||||
return $settings->has( 'card_billing_data_mode' ) ?
|
||||
(string) $settings->get( 'card_billing_data_mode' ) :
|
||||
$container->get( 'wcgateway.settings.card_billing_data_mode.default' );
|
||||
},
|
||||
|
||||
'wcgateway.settings.allow_card_button_gateway.default' => static function ( ContainerInterface $container ): bool {
|
||||
return $container->get( 'api.shop.is-latin-america' );
|
||||
},
|
||||
'wcgateway.settings.allow_card_button_gateway' => static function ( ContainerInterface $container ): bool {
|
||||
if ( defined( 'PPCP_FLAG_SEPARATE_APM_BUTTONS' ) && PPCP_FLAG_SEPARATE_APM_BUTTONS === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof ContainerInterface );
|
||||
|
||||
return $settings->has( 'allow_card_button_gateway' ) ?
|
||||
(bool) $settings->get( 'allow_card_button_gateway' ) :
|
||||
$container->get( 'wcgateway.settings.allow_card_button_gateway.default' );
|
||||
},
|
||||
);
|
||||
|
|
19
modules/ppcp-wc-gateway/src/CardBillingMode.php
Normal file
19
modules/ppcp-wc-gateway/src/CardBillingMode.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* Possible values of card_billing_data_mode.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway;
|
||||
|
||||
/**
|
||||
* Class CardBillingMode
|
||||
*/
|
||||
interface CardBillingMode {
|
||||
public const USE_WC = 'use_wc';
|
||||
public const MINIMAL_INPUT = 'minimal_input';
|
||||
public const NO_WC = 'no_wc';
|
||||
}
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Checkout;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
@ -59,9 +60,10 @@ class DisableGateways {
|
|||
if ( ! isset( $methods[ PayPalGateway::ID ] ) && ! isset( $methods[ CreditCardGateway::ID ] ) ) {
|
||||
return $methods;
|
||||
}
|
||||
if ( $this->disable_both_gateways() ) {
|
||||
if ( $this->disable_all_gateways() ) {
|
||||
unset( $methods[ PayPalGateway::ID ] );
|
||||
unset( $methods[ CreditCardGateway::ID ] );
|
||||
unset( $methods[ CardButtonGateway::ID ] );
|
||||
return $methods;
|
||||
}
|
||||
|
||||
|
@ -77,21 +79,15 @@ class DisableGateways {
|
|||
return $methods;
|
||||
}
|
||||
|
||||
if ( $this->is_credit_card() ) {
|
||||
return array(
|
||||
CreditCardGateway::ID => $methods[ CreditCardGateway::ID ],
|
||||
PayPalGateway::ID => $methods[ PayPalGateway::ID ],
|
||||
);
|
||||
}
|
||||
return array( PayPalGateway::ID => $methods[ PayPalGateway::ID ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether both gateways should be disabled or not.
|
||||
* Whether all gateways should be disabled or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function disable_both_gateways() : bool {
|
||||
private function disable_all_gateways() : bool {
|
||||
if ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
@ -110,22 +106,20 @@ class DisableGateways {
|
|||
* @return bool
|
||||
*/
|
||||
private function needs_to_disable_gateways(): bool {
|
||||
return $this->session_handler->order() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current PayPal session is done via DCC payment.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_credit_card(): bool {
|
||||
$order = $this->session_handler->order();
|
||||
if ( ! $order ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! $order->payment_source() || ! $order->payment_source()->card() ) {
|
||||
return false;
|
||||
|
||||
$source = $order->payment_source();
|
||||
if ( $source && $source->card() ) {
|
||||
return false; // DCC.
|
||||
}
|
||||
|
||||
if ( 'card' === $this->session_handler->funding_source() ) {
|
||||
return false; // Card buttons.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Endpoint;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PrefixTrait;
|
||||
|
||||
|
@ -51,7 +52,7 @@ class ReturnUrlEndpoint {
|
|||
/**
|
||||
* Handles the incoming request.
|
||||
*/
|
||||
public function handle_request() {
|
||||
public function handle_request(): void {
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! isset( $_GET['token'] ) ) {
|
||||
|
@ -68,7 +69,12 @@ class ReturnUrlEndpoint {
|
|||
}
|
||||
|
||||
$wc_order = wc_get_order( $wc_order_id );
|
||||
if ( ! $wc_order ) {
|
||||
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
||||
exit();
|
||||
}
|
||||
|
||||
if ( $wc_order->get_payment_method() === OXXOGateway::ID ) {
|
||||
wp_safe_redirect( wc_get_checkout_url() );
|
||||
exit();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Wrapper for more detailed gateway error.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Exception
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Exception;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\Messages;
|
||||
|
||||
/**
|
||||
* Class GatewayGenericException
|
||||
*/
|
||||
class GatewayGenericException extends Exception {
|
||||
/**
|
||||
* GatewayGenericException constructor.
|
||||
*
|
||||
* @param Throwable|null $inner The exception.
|
||||
*/
|
||||
public function __construct( ?Throwable $inner = null ) {
|
||||
parent::__construct(
|
||||
Messages::generic_payment_error_message(),
|
||||
$inner ? (int) $inner->getCode() : 0,
|
||||
$inner
|
||||
);
|
||||
}
|
||||
}
|
364
modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php
Normal file
364
modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php
Normal file
|
@ -0,0 +1,364 @@
|
|||
<?php
|
||||
/**
|
||||
* The PayPal Card Button Gateway
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
|
||||
/**
|
||||
* Class CardButtonGateway
|
||||
*/
|
||||
class CardButtonGateway extends \WC_Payment_Gateway {
|
||||
|
||||
use ProcessPaymentTrait, FreeTrialHandlerTrait, GatewaySettingsRendererTrait;
|
||||
|
||||
const ID = 'ppcp-card-button-gateway';
|
||||
|
||||
/**
|
||||
* The Settings Renderer.
|
||||
*
|
||||
* @var SettingsRenderer
|
||||
*/
|
||||
protected $settings_renderer;
|
||||
|
||||
/**
|
||||
* The processor for orders.
|
||||
*
|
||||
* @var OrderProcessor
|
||||
*/
|
||||
protected $order_processor;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The Session Handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
protected $session_handler;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* The state.
|
||||
*
|
||||
* @var State
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* The subscription helper.
|
||||
*
|
||||
* @var SubscriptionHelper
|
||||
*/
|
||||
protected $subscription_helper;
|
||||
|
||||
/**
|
||||
* The payment token repository.
|
||||
*
|
||||
* @var PaymentTokenRepository
|
||||
*/
|
||||
protected $payment_token_repository;
|
||||
|
||||
/**
|
||||
* Whether the plugin is in onboarded state.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $onboarded;
|
||||
|
||||
/**
|
||||
* Whether the gateway should be enabled by default.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $default_enabled;
|
||||
|
||||
/**
|
||||
* The environment.
|
||||
*
|
||||
* @var Environment
|
||||
*/
|
||||
protected $environment;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* CardButtonGateway constructor.
|
||||
*
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param State $state The state.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param bool $default_enabled Whether the gateway should be enabled by default.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
OrderProcessor $order_processor,
|
||||
ContainerInterface $config,
|
||||
SessionHandler $session_handler,
|
||||
RefundProcessor $refund_processor,
|
||||
State $state,
|
||||
TransactionUrlProvider $transaction_url_provider,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
bool $default_enabled,
|
||||
Environment $environment,
|
||||
PaymentTokenRepository $payment_token_repository,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->state = $state;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->default_enabled = $default_enabled;
|
||||
$this->environment = $environment;
|
||||
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->logger = $logger;
|
||||
|
||||
if ( $this->onboarded ) {
|
||||
$this->supports = array( 'refunds' );
|
||||
}
|
||||
if (
|
||||
defined( 'PPCP_FLAG_SUBSCRIPTION' )
|
||||
&& PPCP_FLAG_SUBSCRIPTION
|
||||
&& $this->gateways_enabled()
|
||||
&& $this->vault_setting_enabled()
|
||||
) {
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
'subscriptions',
|
||||
'subscription_cancellation',
|
||||
'subscription_suspension',
|
||||
'subscription_reactivation',
|
||||
'subscription_amount_changes',
|
||||
'subscription_date_changes',
|
||||
'subscription_payment_method_change',
|
||||
'subscription_payment_method_change_customer',
|
||||
'subscription_payment_method_change_admin',
|
||||
'multiple_subscriptions',
|
||||
);
|
||||
}
|
||||
|
||||
$this->method_title = __( 'PayPal Card Button', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'The separate payment gateway with the card button. If disabled, the button is included in the PayPal gateway.', 'woocommerce-paypal-payments' );
|
||||
$this->title = $this->get_option( 'title', __( 'Debit & Credit Cards', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action(
|
||||
'woocommerce_update_options_payment_gateways_' . $this->id,
|
||||
array(
|
||||
$this,
|
||||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the Gateway needs to be setup.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function needs_setup(): bool {
|
||||
return ! $this->onboarded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable PayPal Card Button', 'woocommerce-paypal-payments' ),
|
||||
'default' => $this->default_enabled ? 'yes' : 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable the separate payment gateway with the card button.', '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' ),
|
||||
),
|
||||
'ppcp' => array(
|
||||
'type' => 'ppcp',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process payment for a WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$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.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen change Subscription payment.
|
||||
*/
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
||||
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
||||
if ( $saved_paypal_payment ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the WC_Order is paid through the approved webhook.
|
||||
*/
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
try {
|
||||
if ( ! $this->order_processor->process( $wc_order ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
$this->order_processor->last_error()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
||||
}
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalApiException $error ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
} catch ( RuntimeException $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 = '' ) {
|
||||
$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 the settings renderer.
|
||||
*
|
||||
* @return SettingsRenderer
|
||||
*/
|
||||
protected function settings_renderer(): SettingsRenderer {
|
||||
return $this->settings_renderer;
|
||||
}
|
||||
}
|
|
@ -9,17 +9,19 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WC_Customer;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\VaultedCreditCardHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
|
@ -30,7 +32,7 @@ use Psr\Container\ContainerInterface;
|
|||
*/
|
||||
class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||
|
||||
use ProcessPaymentTrait;
|
||||
use ProcessPaymentTrait, GatewaySettingsRendererTrait;
|
||||
|
||||
const ID = 'ppcp-credit-card-gateway';
|
||||
|
||||
|
@ -48,13 +50,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
protected $order_processor;
|
||||
|
||||
/**
|
||||
* The processor for authorized payments.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor
|
||||
*/
|
||||
protected $authorized_payments_processor;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
|
@ -62,6 +57,13 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The vaulted credit card handler.
|
||||
*
|
||||
* @var VaultedCreditCardHandler
|
||||
*/
|
||||
protected $vaulted_credit_card_handler;
|
||||
|
||||
/**
|
||||
* The URL to the module.
|
||||
*
|
||||
|
@ -104,27 +106,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
private $payment_token_repository;
|
||||
|
||||
/**
|
||||
* The purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The payer factory.
|
||||
*
|
||||
* @var PayerFactory
|
||||
*/
|
||||
private $payer_factory;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
private $order_endpoint;
|
||||
|
||||
/**
|
||||
* The subscription helper.
|
||||
*
|
||||
|
@ -139,13 +120,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* The environment.
|
||||
*
|
||||
* @var Environment
|
||||
*/
|
||||
protected $environment;
|
||||
|
||||
/**
|
||||
* The payments endpoint
|
||||
*
|
||||
|
@ -156,52 +130,46 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
/**
|
||||
* CreditCardGateway constructor.
|
||||
*
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param OrderProcessor $order_processor The Order processor.
|
||||
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param string $module_url The URL to the module.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param RefundProcessor $refund_processor The refund processor.
|
||||
* @param State $state The state.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service able to provide view transaction url base.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param PayerFactory $payer_factory The payer factory.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param OrderProcessor $order_processor The Order processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param string $module_url The URL to the module.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param RefundProcessor $refund_processor The refund processor.
|
||||
* @param State $state The state.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service able to provide view transaction url base.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
|
||||
* @param VaultedCreditCardHandler $vaulted_credit_card_handler The vaulted credit card handler.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
OrderProcessor $order_processor,
|
||||
AuthorizedPaymentsProcessor $authorized_payments_processor,
|
||||
ContainerInterface $config,
|
||||
string $module_url,
|
||||
SessionHandler $session_handler,
|
||||
RefundProcessor $refund_processor,
|
||||
State $state,
|
||||
TransactionUrlProvider $transaction_url_provider,
|
||||
PaymentTokenRepository $payment_token_repository,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
PayerFactory $payer_factory,
|
||||
OrderEndpoint $order_endpoint,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
LoggerInterface $logger,
|
||||
Environment $environment,
|
||||
PaymentsEndpoint $payments_endpoint
|
||||
PaymentsEndpoint $payments_endpoint,
|
||||
VaultedCreditCardHandler $vaulted_credit_card_handler
|
||||
) {
|
||||
|
||||
$this->id = self::ID;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->environment = $environment;
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->config = $config;
|
||||
$this->module_url = $module_url;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->state = $state;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
$this->vaulted_credit_card_handler = $vaulted_credit_card_handler;
|
||||
|
||||
if ( $state->current_state() === State::STATE_ONBOARDED ) {
|
||||
$this->supports = array( 'refunds' );
|
||||
|
@ -251,17 +219,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
|
||||
$this->module_url = $module_url;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -284,20 +241,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
remove_action( 'gettext', 'replace_credit_card_cvv_label' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_ppcp_html(): string {
|
||||
|
||||
ob_start();
|
||||
$this->settings_renderer->render();
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace WooCommerce credit card field label.
|
||||
*
|
||||
|
@ -398,6 +341,77 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
return $this->is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process payment for a WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$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.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen a saved credit card payment.
|
||||
*/
|
||||
$saved_credit_card = filter_input( INPUT_POST, 'saved_credit_card', FILTER_SANITIZE_STRING );
|
||||
if ( $saved_credit_card ) {
|
||||
try {
|
||||
$wc_order = $this->vaulted_credit_card_handler->handle_payment(
|
||||
$saved_credit_card,
|
||||
$wc_order
|
||||
);
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the WC_Order is paid through the approved webhook.
|
||||
*/
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
try {
|
||||
if ( ! $this->order_processor->process( $wc_order ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
$this->order_processor->last_error()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
||||
}
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalApiException $error ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
|
@ -489,11 +503,11 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the environment.
|
||||
* Returns the settings renderer.
|
||||
*
|
||||
* @return Environment
|
||||
* @return SettingsRenderer
|
||||
*/
|
||||
protected function environment(): Environment {
|
||||
return $this->environment;
|
||||
protected function settings_renderer(): SettingsRenderer {
|
||||
return $this->settings_renderer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* Adds generate_ppcp_html method for rendering settings.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
|
||||
/**
|
||||
* Trait GatewaySettingsRendererTrait
|
||||
*/
|
||||
trait GatewaySettingsRendererTrait {
|
||||
/**
|
||||
* Renders the settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_ppcp_html(): string {
|
||||
ob_start();
|
||||
$this->settings_renderer()->render();
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings renderer.
|
||||
*
|
||||
* @return SettingsRenderer
|
||||
*/
|
||||
abstract protected function settings_renderer(): SettingsRenderer;
|
||||
}
|
27
modules/ppcp-wc-gateway/src/Gateway/Messages.php
Normal file
27
modules/ppcp-wc-gateway/src/Gateway/Messages.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* Common messages.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
/**
|
||||
* Class Messages
|
||||
*/
|
||||
class Messages {
|
||||
/**
|
||||
* The generic payment failure message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function generic_payment_error_message(): string {
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_generic_payment_error_message',
|
||||
__( 'Failed to process the payment. Please try again or contact the shop admin.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
}
|
223
modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXO.php
Normal file
223
modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXO.php
Normal file
|
@ -0,0 +1,223 @@
|
|||
<?php
|
||||
/**
|
||||
* OXXO integration.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO;
|
||||
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
||||
|
||||
/**
|
||||
* Class OXXO.
|
||||
*/
|
||||
class OXXO {
|
||||
|
||||
/**
|
||||
* The checkout helper.
|
||||
*
|
||||
* @var CheckoutHelper
|
||||
*/
|
||||
protected $checkout_helper;
|
||||
|
||||
/**
|
||||
* The module URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $module_url;
|
||||
|
||||
/**
|
||||
* The asset version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $asset_version;
|
||||
|
||||
/**
|
||||
* OXXO constructor.
|
||||
*
|
||||
* @param CheckoutHelper $checkout_helper The checkout helper.
|
||||
* @param string $module_url The module URL.
|
||||
* @param string $asset_version The asset version.
|
||||
*/
|
||||
public function __construct(
|
||||
CheckoutHelper $checkout_helper,
|
||||
string $module_url,
|
||||
string $asset_version
|
||||
) {
|
||||
|
||||
$this->checkout_helper = $checkout_helper;
|
||||
$this->module_url = $module_url;
|
||||
$this->asset_version = $asset_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes OXXO integration.
|
||||
*/
|
||||
public function init(): void {
|
||||
|
||||
add_filter(
|
||||
'woocommerce_available_payment_gateways',
|
||||
function ( array $methods ): array {
|
||||
|
||||
if ( ! $this->checkout_allowed_for_oxxo() ) {
|
||||
unset( $methods[ OXXOGateway::ID ] );
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wp_enqueue_scripts',
|
||||
array( $this, 'register_assets' )
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_thankyou_order_received_text',
|
||||
function( string $message, WC_Order $order ) {
|
||||
$payer_action = $order->get_meta( 'ppcp_oxxo_payer_action' ) ?? '';
|
||||
|
||||
$button = '';
|
||||
if ( $payer_action ) {
|
||||
$button = '<p><a id="ppcp-oxxo-payer-action" class="button" href="' . $payer_action . '" target="_blank">' . esc_html__( 'See OXXO voucher', 'woocommerce-paypal-payments' ) . '</a></p>';
|
||||
}
|
||||
|
||||
return $message . ' ' . $button;
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_email_before_order_table',
|
||||
function ( WC_Order $order, bool $sent_to_admin ) {
|
||||
if (
|
||||
! $sent_to_admin
|
||||
&& $order->get_payment_method() === OXXOGateway::ID
|
||||
&& $order->has_status( 'on-hold' )
|
||||
) {
|
||||
$payer_action = $order->get_meta( 'ppcp_oxxo_payer_action' ) ?? '';
|
||||
if ( $payer_action ) {
|
||||
echo '<p><a class="button" href="' . esc_url( $payer_action ) . '" target="_blank">' . esc_html__( 'See OXXO voucher', 'woocommerce-paypal-payments' ) . '</a></p>';
|
||||
}
|
||||
}
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'ppcp_payment_capture_reversed_webhook_update_status_note',
|
||||
function( string $note, WC_Order $wc_order, string $event_type ): string {
|
||||
if ( $wc_order->get_payment_method() === OXXOGateway::ID && $event_type === 'PAYMENT.CAPTURE.DENIED' ) {
|
||||
$note = __( 'OXXO voucher has expired or the buyer didn\'t complete the payment successfully.', 'woocommerce-paypal-payments' );
|
||||
}
|
||||
|
||||
return $note;
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
|
||||
add_action(
|
||||
'add_meta_boxes',
|
||||
function( string $post_type ) {
|
||||
if ( $post_type === 'shop_order' ) {
|
||||
$post_id = filter_input( INPUT_GET, 'post', FILTER_SANITIZE_STRING );
|
||||
$order = wc_get_order( $post_id );
|
||||
if ( is_a( $order, WC_Order::class ) && $order->get_payment_method() === OXXOGateway::ID ) {
|
||||
$payer_action = $order->get_meta( 'ppcp_oxxo_payer_action' );
|
||||
if ( $payer_action ) {
|
||||
add_meta_box(
|
||||
'ppcp_oxxo_payer_action',
|
||||
__( 'OXXO Voucher/Ticket', 'woocommerce-paypal-payments' ),
|
||||
function() use ( $payer_action ) {
|
||||
echo '<p><a class="button" href="' . esc_url( $payer_action ) . '" target="_blank">' . esc_html__( 'See OXXO voucher', 'woocommerce-paypal-payments' ) . '</a></p>';
|
||||
},
|
||||
$post_type,
|
||||
'side',
|
||||
'high'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_order_details_before_order_table_items',
|
||||
function( WC_Order $order ) {
|
||||
if ( $order->get_payment_method() === OXXOGateway::ID ) {
|
||||
$payer_action = $order->get_meta( 'ppcp_oxxo_payer_action' );
|
||||
if ( $payer_action ) {
|
||||
echo '<p><a class="button" href="' . esc_url( $payer_action ) . '" target="_blank">' . esc_html__( 'See OXXO voucher', 'woocommerce-paypal-payments' ) . '</a></p>';
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if checkout is allowed for OXXO.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function checkout_allowed_for_oxxo(): bool {
|
||||
if ( 'MXN' !== get_woocommerce_currency() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$billing_country = filter_input( INPUT_POST, 'country', FILTER_SANITIZE_STRING ) ?? null;
|
||||
if ( $billing_country && 'MX' !== $billing_country ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->checkout_helper->is_checkout_amount_allowed( 0, 10000 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register OXXO assets.
|
||||
*/
|
||||
public function register_assets(): void {
|
||||
$gateway_settings = get_option( 'woocommerce_ppcp-oxxo-gateway_settings' );
|
||||
$gateway_enabled = $gateway_settings['enabled'] ?? '';
|
||||
if ( $gateway_enabled === 'yes' && is_checkout() ) {
|
||||
wp_enqueue_script(
|
||||
'ppcp-oxxo',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/oxxo.js',
|
||||
array(),
|
||||
$this->asset_version,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
wp_localize_script(
|
||||
'ppcp-oxxo',
|
||||
'OXXOConfig',
|
||||
array(
|
||||
'oxxo_endpoint' => \WC_AJAX::get_endpoint( 'ppc-oxxo' ),
|
||||
'oxxo_nonce' => wp_create_nonce( 'ppc-oxxo' ),
|
||||
'error' => array(
|
||||
'generic' => __(
|
||||
'Something went wrong. Please try again or choose another payment source.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'js_validation' => __(
|
||||
'Required form fields are not filled or invalid.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
156
modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOEndpoint.php
Normal file
156
modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOEndpoint.php
Normal file
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles OXXO payer action.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Onboarding\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
|
||||
/**
|
||||
* OXXOEndpoint constructor.
|
||||
*/
|
||||
class OXXOEndpoint implements EndpointInterface {
|
||||
|
||||
|
||||
/**
|
||||
* The request data
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
protected $request_data;
|
||||
|
||||
/**
|
||||
* The purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
protected $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The shipping preference factory.
|
||||
*
|
||||
* @var ShippingPreferenceFactory
|
||||
*/
|
||||
protected $shipping_preference_factory;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
protected $order_endpoint;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* OXXOEndpoint constructor
|
||||
*
|
||||
* @param RequestData $request_data The request data.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping preference factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
OrderEndpoint $order_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
ShippingPreferenceFactory $shipping_preference_factory,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->request_data = $request_data;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* The nonce
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return 'ppc-oxxo';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_cart();
|
||||
$payer_action = '';
|
||||
|
||||
try {
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$purchase_unit,
|
||||
'checkout'
|
||||
);
|
||||
|
||||
$order = $this->order_endpoint->create( array( $purchase_unit ), $shipping_preference );
|
||||
|
||||
$payment_source = array(
|
||||
'oxxo' => array(
|
||||
'name' => 'John Doe',
|
||||
'email' => 'foo@bar.com',
|
||||
'country_code' => 'MX',
|
||||
),
|
||||
);
|
||||
|
||||
$payment_method = $this->order_endpoint->confirm_payment_source( $order->id(), $payment_source );
|
||||
|
||||
foreach ( $payment_method->links as $link ) {
|
||||
if ( $link->rel === 'payer-action' ) {
|
||||
$payer_action = $link->href;
|
||||
}
|
||||
}
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$error = $exception->getMessage();
|
||||
|
||||
if ( is_a( $exception, PayPalApiException::class ) && is_array( $exception->details() ) ) {
|
||||
$details = '';
|
||||
foreach ( $exception->details() as $detail ) {
|
||||
$issue = $detail->issue ?? '';
|
||||
$field = $detail->field ?? '';
|
||||
$description = $detail->description ?? '';
|
||||
$details .= $issue . ' ' . $field . ' ' . $description . '<br>';
|
||||
}
|
||||
|
||||
$error = $details;
|
||||
}
|
||||
|
||||
$this->logger->error( $error );
|
||||
wc_add_notice( $error, 'error' );
|
||||
|
||||
wp_send_json_error( 'Could not get OXXO payer action.' );
|
||||
return false;
|
||||
}
|
||||
|
||||
WC()->session->set( 'ppcp_payer_action', $payer_action );
|
||||
|
||||
wp_send_json_success(
|
||||
array( 'payer_action' => $payer_action )
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
210
modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php
Normal file
210
modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php
Normal file
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
/**
|
||||
* The OXXO Gateway
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
|
||||
/**
|
||||
* Class OXXOGateway.
|
||||
*/
|
||||
class OXXOGateway extends WC_Payment_Gateway {
|
||||
const ID = 'ppcp-oxxo-gateway';
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
protected $order_endpoint;
|
||||
|
||||
/**
|
||||
* The purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
protected $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The shipping preference factory.
|
||||
*
|
||||
* @var ShippingPreferenceFactory
|
||||
*/
|
||||
protected $shipping_preference_factory;
|
||||
|
||||
/**
|
||||
* The URL to the module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* OXXOGateway constructor.
|
||||
*
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping preference factory.
|
||||
* @param string $module_url The URL to the module.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
OrderEndpoint $order_endpoint,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
ShippingPreferenceFactory $shipping_preference_factory,
|
||||
string $module_url,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->method_title = __( 'OXXO', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'OXXO is a Mexican chain of convenience stores.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$this->title = $this->get_option( 'title', $this->method_title );
|
||||
$this->description = $this->get_option( 'description', __( 'OXXO allows you to pay bills and online purchases in-store with cash.', 'woocommerce-paypal-payments' ) );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action(
|
||||
'woocommerce_update_options_payment_gateways_' . $this->id,
|
||||
array(
|
||||
$this,
|
||||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->module_url = $module_url;
|
||||
$this->logger = $logger;
|
||||
|
||||
$this->icon = esc_url( $this->module_url ) . 'assets/images/oxxo.svg';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'OXXO', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable OXXO 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 );
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payer_action = '';
|
||||
|
||||
try {
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$purchase_unit,
|
||||
'checkout'
|
||||
);
|
||||
|
||||
$order = $this->order_endpoint->create( array( $purchase_unit ), $shipping_preference );
|
||||
$payment_source = array(
|
||||
'oxxo' => array(
|
||||
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
||||
'email' => $wc_order->get_billing_email(),
|
||||
'country_code' => $wc_order->get_billing_country(),
|
||||
),
|
||||
);
|
||||
$payment_method = $this->order_endpoint->confirm_payment_source( $order->id(), $payment_source );
|
||||
foreach ( $payment_method->links as $link ) {
|
||||
if ( $link->rel === 'payer-action' ) {
|
||||
$payer_action = $link->href;
|
||||
$wc_order->add_meta_data( 'ppcp_oxxo_payer_action', $payer_action );
|
||||
$wc_order->save_meta_data();
|
||||
}
|
||||
}
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$error = $exception->getMessage();
|
||||
|
||||
if ( is_a( $exception, PayPalApiException::class ) && is_array( $exception->details() ) ) {
|
||||
$details = '';
|
||||
foreach ( $exception->details() as $detail ) {
|
||||
$issue = $detail->issue ?? '';
|
||||
$field = $detail->field ?? '';
|
||||
$description = $detail->description ?? '';
|
||||
$details .= $issue . ' ' . $field . ' ' . $description . '<br>';
|
||||
}
|
||||
|
||||
$error = $details;
|
||||
}
|
||||
|
||||
$this->logger->error( $error );
|
||||
wc_add_notice( $error, 'error' );
|
||||
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$error
|
||||
);
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
$result = array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
|
||||
if ( $payer_action ) {
|
||||
$result['payer_action'] = $payer_action;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -9,17 +9,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
|
@ -31,7 +35,7 @@ use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
|||
*/
|
||||
class PayPalGateway extends \WC_Payment_Gateway {
|
||||
|
||||
use ProcessPaymentTrait;
|
||||
use ProcessPaymentTrait, FreeTrialHandlerTrait, GatewaySettingsRendererTrait;
|
||||
|
||||
const ID = 'ppcp-gateway';
|
||||
const INTENT_META_KEY = '_ppcp_paypal_intent';
|
||||
|
@ -62,13 +66,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
*/
|
||||
protected $order_processor;
|
||||
|
||||
/**
|
||||
* The processor for authorized payments.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor
|
||||
*/
|
||||
protected $authorized_payments_processor;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
|
@ -118,20 +115,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
*/
|
||||
protected $payment_token_repository;
|
||||
|
||||
/**
|
||||
* The payments endpoint
|
||||
*
|
||||
* @var PaymentsEndpoint
|
||||
*/
|
||||
protected $payments_endpoint;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
protected $order_endpoint;
|
||||
|
||||
/**
|
||||
* Whether the plugin is in onboarded state.
|
||||
*
|
||||
|
@ -170,29 +153,25 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
/**
|
||||
* PayPalGateway constructor.
|
||||
*
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param State $state The state.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param string $api_shop_country The api shop country.
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param State $state The state.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $api_shop_country The api shop country.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
FundingSourceRenderer $funding_source_renderer,
|
||||
OrderProcessor $order_processor,
|
||||
AuthorizedPaymentsProcessor $authorized_payments_processor,
|
||||
ContainerInterface $config,
|
||||
SessionHandler $session_handler,
|
||||
RefundProcessor $refund_processor,
|
||||
|
@ -203,34 +182,24 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
Environment $environment,
|
||||
PaymentTokenRepository $payment_token_repository,
|
||||
LoggerInterface $logger,
|
||||
PaymentsEndpoint $payments_endpoint,
|
||||
OrderEndpoint $order_endpoint,
|
||||
string $api_shop_country
|
||||
) {
|
||||
|
||||
$this->id = self::ID;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->funding_source_renderer = $funding_source_renderer;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->page_id = $page_id;
|
||||
$this->environment = $environment;
|
||||
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
||||
$this->id = self::ID;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->authorized_payments = $authorized_payments_processor;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->page_id = $page_id;
|
||||
$this->environment = $environment;
|
||||
$this->logger = $logger;
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->funding_source_renderer = $funding_source_renderer;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->state = $state;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->page_id = $page_id;
|
||||
$this->environment = $environment;
|
||||
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->logger = $logger;
|
||||
$this->api_shop_country = $api_shop_country;
|
||||
|
||||
if ( $this->onboarded ) {
|
||||
$this->supports = array( 'refunds' );
|
||||
|
@ -280,13 +249,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->logger = $logger;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->state = $state;
|
||||
$this->api_shop_country = $api_shop_country;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -295,7 +257,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
* @return bool
|
||||
*/
|
||||
public function needs_setup(): bool {
|
||||
|
||||
return ! $this->onboarded;
|
||||
}
|
||||
|
||||
|
@ -323,20 +284,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_ppcp_html(): string {
|
||||
|
||||
ob_start();
|
||||
$this->settings_renderer->render( false );
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the method title. If we are on the credit card tab in the settings, we want to change this.
|
||||
*
|
||||
|
@ -353,7 +300,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
return __( 'PayPal Checkout', 'woocommerce-paypal-payments' );
|
||||
}
|
||||
if ( $this->is_pui_tab() ) {
|
||||
return __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' );
|
||||
return __( 'Pay upon Invoice', 'woocommerce-paypal-payments' );
|
||||
}
|
||||
|
||||
return __( 'PayPal', 'woocommerce-paypal-payments' );
|
||||
|
@ -439,6 +386,130 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
/**
|
||||
* Process payment for a WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$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.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
$funding_source = filter_input( INPUT_POST, 'ppcp-funding-source', FILTER_SANITIZE_STRING );
|
||||
|
||||
if ( 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) ) {
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
||||
if ( ! array_filter(
|
||||
$tokens,
|
||||
function ( PaymentToken $token ): bool {
|
||||
return isset( $token->source()->paypal );
|
||||
}
|
||||
) ) {
|
||||
return $this->handle_payment_failure( $wc_order, new Exception( 'No saved PayPal account.' ) );
|
||||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen change Subscription payment.
|
||||
*/
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
||||
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
||||
if ( $saved_paypal_payment ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the WC_Order is paid through the approved webhook.
|
||||
*/
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
try {
|
||||
if ( ! $this->order_processor->process( $wc_order ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
$this->order_processor->last_error()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
||||
}
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalApiException $error ) {
|
||||
$retry_keys_messages = array(
|
||||
'INSTRUMENT_DECLINED' => __( 'Instrument declined.', 'woocommerce-paypal-payments' ),
|
||||
'PAYER_ACTION_REQUIRED' => __( 'Payer action required, possibly overcharge.', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
$retry_errors = array_filter(
|
||||
array_keys( $retry_keys_messages ),
|
||||
function ( string $key ) use ( $error ): bool {
|
||||
return $error->has_detail( $key );
|
||||
}
|
||||
);
|
||||
if ( $retry_errors ) {
|
||||
$retry_error_key = $retry_errors[0];
|
||||
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$retry_keys_messages[ $retry_error_key ] . ' ' . $error->details()[0]->description ?? ''
|
||||
);
|
||||
|
||||
$this->session_handler->increment_insufficient_funding_tries();
|
||||
if ( $this->session_handler->insufficient_funding_tries() >= 3 ) {
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new Exception(
|
||||
__( 'Please use a different payment method.', 'woocommerce-paypal-payments' ),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$host = $this->config->has( 'sandbox_on' ) && $this->config->get( 'sandbox_on' ) ?
|
||||
'https://www.sandbox.paypal.com/' : 'https://www.paypal.com/';
|
||||
$url = $host . 'checkoutnow?token=' . $this->session_handler->order()->id();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $url,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
|
@ -492,11 +563,11 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the environment.
|
||||
* Returns the settings renderer.
|
||||
*
|
||||
* @return Environment
|
||||
* @return SettingsRenderer
|
||||
*/
|
||||
protected function environment(): Environment {
|
||||
return $this->environment;
|
||||
protected function settings_renderer(): SettingsRenderer {
|
||||
return $this->settings_renderer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ class FraudNetSessionId {
|
|||
return WC()->session->get( 'ppcp_fraudnet_session_id' );
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_GET['pay_for_order'] ) && 'true' === $_GET['pay_for_order'] ) {
|
||||
$pui_pay_for_order_session_id = filter_input( INPUT_POST, 'pui_pay_for_order_session_id', FILTER_SANITIZE_STRING );
|
||||
if ( $pui_pay_for_order_session_id && '' !== $pui_pay_for_order_session_id ) {
|
||||
|
|
|
@ -11,14 +11,12 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WC_Order_Item;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Product;
|
||||
use WC_Product_Variable;
|
||||
use WC_Product_Variation;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\CaptureFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
||||
|
@ -118,6 +116,20 @@ class PayUponInvoice {
|
|||
*/
|
||||
protected $pui_product_status;
|
||||
|
||||
/**
|
||||
* The checkout helper.
|
||||
*
|
||||
* @var CheckoutHelper
|
||||
*/
|
||||
protected $checkout_helper;
|
||||
|
||||
/**
|
||||
* The capture factory.
|
||||
*
|
||||
* @var CaptureFactory
|
||||
*/
|
||||
protected $capture_factory;
|
||||
|
||||
/**
|
||||
* PayUponInvoice constructor.
|
||||
*
|
||||
|
@ -133,6 +145,8 @@ class PayUponInvoice {
|
|||
* @param string $current_ppcp_settings_page_id Current PayPal settings page id.
|
||||
* @param PayUponInvoiceProductStatus $pui_product_status The PUI product status.
|
||||
* @param PayUponInvoiceHelper $pui_helper The PUI helper.
|
||||
* @param CheckoutHelper $checkout_helper The checkout helper.
|
||||
* @param CaptureFactory $capture_factory The capture factory.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
|
@ -146,7 +160,9 @@ class PayUponInvoice {
|
|||
bool $is_ppcp_settings_page,
|
||||
string $current_ppcp_settings_page_id,
|
||||
PayUponInvoiceProductStatus $pui_product_status,
|
||||
PayUponInvoiceHelper $pui_helper
|
||||
PayUponInvoiceHelper $pui_helper,
|
||||
CheckoutHelper $checkout_helper,
|
||||
CaptureFactory $capture_factory
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->fraud_net = $fraud_net;
|
||||
|
@ -160,6 +176,8 @@ class PayUponInvoice {
|
|||
$this->current_ppcp_settings_page_id = $current_ppcp_settings_page_id;
|
||||
$this->pui_product_status = $pui_product_status;
|
||||
$this->pui_helper = $pui_helper;
|
||||
$this->checkout_helper = $checkout_helper;
|
||||
$this->capture_factory = $capture_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,7 +228,12 @@ class PayUponInvoice {
|
|||
'ppcp_payment_capture_completed_webhook_handler',
|
||||
function ( WC_Order $wc_order, string $order_id ) {
|
||||
try {
|
||||
$payment_instructions = $this->pui_order_endpoint->order_payment_instructions( $order_id );
|
||||
$order = $this->pui_order_endpoint->order( $order_id );
|
||||
|
||||
$payment_instructions = array(
|
||||
$order->payment_source->pay_upon_invoice->payment_reference,
|
||||
$order->payment_source->pay_upon_invoice->deposit_bank_details,
|
||||
);
|
||||
$wc_order->update_meta_data(
|
||||
'ppcp_ratepay_payment_instructions_payment_reference',
|
||||
$payment_instructions
|
||||
|
@ -218,6 +241,12 @@ class PayUponInvoice {
|
|||
$wc_order->save_meta_data();
|
||||
$this->logger->info( "Ratepay payment instructions added to order #{$wc_order->get_id()}." );
|
||||
|
||||
$capture = $this->capture_factory->from_paypal_response( $order->purchase_units[0]->payments->captures[0] );
|
||||
$breakdown = $capture->seller_receivable_breakdown();
|
||||
if ( $breakdown ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::FEES_META_KEY, $breakdown->to_array() );
|
||||
$wc_order->save_meta_data();
|
||||
}
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$this->logger->error( $exception->getMessage() );
|
||||
}
|
||||
|
@ -280,7 +309,7 @@ class PayUponInvoice {
|
|||
}
|
||||
},
|
||||
10,
|
||||
3
|
||||
2
|
||||
);
|
||||
|
||||
add_filter(
|
||||
|
@ -304,6 +333,23 @@ class PayUponInvoice {
|
|||
)
|
||||
);
|
||||
|
||||
$checkout_fields = WC()->checkout()->get_checkout_fields();
|
||||
$checkout_phone_required = $checkout_fields['billing']['billing_phone']['required'] ?? false;
|
||||
if ( ! array_key_exists( 'billing_phone', $checkout_fields['billing'] ) || $checkout_phone_required === false ) {
|
||||
woocommerce_form_field(
|
||||
'billing_phone',
|
||||
array(
|
||||
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
||||
'label' => __( 'Phone', 'woocommerce' ),
|
||||
'type' => 'tel',
|
||||
'class' => array( 'form-row-wide' ),
|
||||
'validate' => array( 'phone' ),
|
||||
'autocomplete' => 'tel',
|
||||
'required' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
echo '</div><div>';
|
||||
|
||||
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
||||
|
@ -342,11 +388,14 @@ class PayUponInvoice {
|
|||
}
|
||||
|
||||
$birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING );
|
||||
if ( ( $birth_date && ! $this->pui_helper->validate_birth_date( $birth_date ) ) || $birth_date === '' ) {
|
||||
if ( ( $birth_date && ! $this->checkout_helper->validate_birth_date( $birth_date ) ) || $birth_date === '' ) {
|
||||
$errors->add( 'validation', __( 'Invalid birth date.', 'woocommerce-paypal-payments' ) );
|
||||
}
|
||||
|
||||
$national_number = filter_input( INPUT_POST, 'billing_phone', FILTER_SANITIZE_STRING );
|
||||
if ( ! $national_number ) {
|
||||
$errors->add( 'validation', __( 'Phone field cannot be empty.', 'woocommerce-paypal-payments' ) );
|
||||
}
|
||||
if ( $national_number ) {
|
||||
$numeric_phone_number = preg_replace( '/[^0-9]/', '', $national_number );
|
||||
if ( $numeric_phone_number && ! preg_match( '/^[0-9]{1,14}?$/', $numeric_phone_number ) ) {
|
||||
|
@ -395,7 +444,7 @@ class PayUponInvoice {
|
|||
|
||||
printf(
|
||||
'<div class="notice notice-error"><p>%1$s</p></div>',
|
||||
esc_html__( 'Could not enable gateway because the connected PayPal account is not activated for Pay upon Invoice. Reconnect your account while Onboard with Pay Upon Invoice is selected to try again.', 'woocommerce-paypal-payments' )
|
||||
esc_html__( 'Could not enable gateway because the connected PayPal account is not activated for Pay upon Invoice. Reconnect your account while Onboard with Pay upon Invoice is selected to try again.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -459,7 +508,7 @@ class PayUponInvoice {
|
|||
if ( $post_type === 'shop_order' ) {
|
||||
$post_id = filter_input( INPUT_GET, 'post', FILTER_SANITIZE_STRING );
|
||||
$order = wc_get_order( $post_id );
|
||||
if ( is_a( $order, WC_Order::class ) && $order->get_payment_method() === 'ppcp-pay-upon-invoice-gateway' ) {
|
||||
if ( is_a( $order, WC_Order::class ) && $order->get_payment_method() === PayUponInvoiceGateway::ID ) {
|
||||
$instructions = $order->get_meta( 'ppcp_ratepay_payment_instructions_payment_reference' );
|
||||
if ( $instructions ) {
|
||||
add_meta_box(
|
||||
|
@ -495,21 +544,26 @@ class PayUponInvoice {
|
|||
* Registers PUI assets.
|
||||
*/
|
||||
public function register_assets(): void {
|
||||
wp_enqueue_script(
|
||||
'ppcp-pay-upon-invoice',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/pay-upon-invoice.js',
|
||||
array(),
|
||||
$this->asset_version
|
||||
);
|
||||
$gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' );
|
||||
$gateway_enabled = $gateway_settings['enabled'] ?? '';
|
||||
if ( $gateway_enabled === 'yes' && ( is_checkout() || is_checkout_pay_page() ) ) {
|
||||
wp_enqueue_script(
|
||||
'ppcp-pay-upon-invoice',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/pay-upon-invoice.js',
|
||||
array(),
|
||||
$this->asset_version,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'ppcp-pay-upon-invoice',
|
||||
'FraudNetConfig',
|
||||
array(
|
||||
'f' => $this->fraud_net->session_id(),
|
||||
's' => $this->fraud_net->source_website_id(),
|
||||
'sandbox' => $this->environment->current_environment_is( Environment::SANDBOX ),
|
||||
)
|
||||
);
|
||||
wp_localize_script(
|
||||
'ppcp-pay-upon-invoice',
|
||||
'FraudNetConfig',
|
||||
array(
|
||||
'f' => $this->fraud_net->session_id(),
|
||||
's' => $this->fraud_net->source_website_id(),
|
||||
'sandbox' => $this->environment->current_environment_is( Environment::SANDBOX ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,14 +12,13 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Payment_Gateway;
|
||||
use WC_Product;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
||||
|
||||
|
@ -81,6 +80,13 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
*/
|
||||
protected $pui_helper;
|
||||
|
||||
/**
|
||||
* The checkout helper.
|
||||
*
|
||||
* @var CheckoutHelper
|
||||
*/
|
||||
protected $checkout_helper;
|
||||
|
||||
/**
|
||||
* PayUponInvoiceGateway constructor.
|
||||
*
|
||||
|
@ -91,6 +97,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
* @param TransactionUrlProvider $transaction_url_provider The transaction URL provider.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PayUponInvoiceHelper $pui_helper The PUI helper.
|
||||
* @param CheckoutHelper $checkout_helper The checkout helper.
|
||||
*/
|
||||
public function __construct(
|
||||
PayUponInvoiceOrderEndpoint $order_endpoint,
|
||||
|
@ -99,11 +106,12 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
Environment $environment,
|
||||
TransactionUrlProvider $transaction_url_provider,
|
||||
LoggerInterface $logger,
|
||||
PayUponInvoiceHelper $pui_helper
|
||||
PayUponInvoiceHelper $pui_helper,
|
||||
CheckoutHelper $checkout_helper
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
|
||||
$this->method_title = __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' );
|
||||
$this->method_title = __( 'Pay upon Invoice', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'Pay upon Invoice is an invoice payment method in Germany. It is a local buy now, pay later payment method that allows the buyer to place an order, receive the goods, try them, verify they are in good order, and then pay the invoice within 30 days.', 'woocommerce-paypal-payments' );
|
||||
|
||||
$gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' );
|
||||
|
@ -128,6 +136,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
$this->environment = $environment;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->pui_helper = $pui_helper;
|
||||
$this->checkout_helper = $checkout_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,7 +150,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable Pay Upon Invoice payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
'description' => __( 'Enable/Disable Pay upon Invoice payment gateway.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
|
@ -198,7 +207,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
|
||||
$pay_for_order = filter_input( INPUT_GET, 'pay_for_order', FILTER_SANITIZE_STRING );
|
||||
if ( 'true' === $pay_for_order ) {
|
||||
if ( ! $this->pui_helper->validate_birth_date( $birth_date ) ) {
|
||||
if ( ! $this->checkout_helper->validate_birth_date( $birth_date ) ) {
|
||||
wc_add_notice( 'Invalid birth date.', 'error' );
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
|
@ -206,7 +215,13 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
}
|
||||
}
|
||||
|
||||
$wc_order->update_status( 'on-hold', __( 'Awaiting Pay Upon Invoice payment.', 'woocommerce-paypal-payments' ) );
|
||||
$phone_number = filter_input( INPUT_POST, 'billing_phone', FILTER_SANITIZE_STRING ) ?? '';
|
||||
if ( $phone_number ) {
|
||||
$wc_order->set_billing_phone( $phone_number );
|
||||
$wc_order->save();
|
||||
}
|
||||
|
||||
$wc_order->update_status( 'on-hold', __( 'Awaiting Pay upon Invoice payment.', 'woocommerce-paypal-payments' ) );
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payment_source = $this->payment_source_factory->from_wc_order( $wc_order, $birth_date );
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ class PaymentSourceFactory {
|
|||
* @return PaymentSource
|
||||
*/
|
||||
public function from_wc_order( WC_Order $order, string $birth_date ) {
|
||||
$address = $order->get_address();
|
||||
|
||||
$address = $order->get_address();
|
||||
$phone = filter_input( INPUT_POST, 'billing_phone', FILTER_SANITIZE_STRING ) ?? $address['phone'] ?: '';
|
||||
$phone_country_code = WC()->countries->get_country_calling_code( $address['country'] );
|
||||
$phone_country_code = is_array( $phone_country_code ) && ! empty( $phone_country_code ) ? $phone_country_code[0] : $phone_country_code;
|
||||
if ( is_string( $phone_country_code ) && '' !== $phone_country_code ) {
|
||||
|
@ -44,13 +44,13 @@ class PaymentSourceFactory {
|
|||
$address['last_name'] ?? '',
|
||||
$address['email'] ?? '',
|
||||
$birth_date,
|
||||
preg_replace( '/[^0-9]/', '', $address['phone'] ) ?? '',
|
||||
preg_replace( '/[^0-9]/', '', $phone ) ?? '',
|
||||
$phone_country_code,
|
||||
$address['address_1'] ?? '',
|
||||
$address['city'] ?? '',
|
||||
$address['postcode'] ?? '',
|
||||
$address['country'] ?? '',
|
||||
'en-DE',
|
||||
'de-DE',
|
||||
$merchant_name,
|
||||
$logo_url,
|
||||
array( $customer_service_instructions )
|
||||
|
|
|
@ -10,272 +10,14 @@ declare( strict_types=1 );
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use Throwable;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
|
||||
/**
|
||||
* Trait ProcessPaymentTrait
|
||||
*/
|
||||
trait ProcessPaymentTrait {
|
||||
|
||||
use OrderMetaTrait, PaymentsStatusHandlingTrait, TransactionIdHandlingTrait, FreeTrialHandlerTrait;
|
||||
|
||||
/**
|
||||
* Process a payment for an WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws RuntimeException When processing payment fails.
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
|
||||
$failure_data = array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
||||
wc_add_notice(
|
||||
__( 'Couldn\'t find order to process', 'woocommerce-paypal-payments' ),
|
||||
'error'
|
||||
);
|
||||
|
||||
return $failure_data;
|
||||
}
|
||||
|
||||
$payment_method = filter_input( INPUT_POST, 'payment_method', FILTER_SANITIZE_STRING );
|
||||
$funding_source = filter_input( INPUT_POST, 'ppcp-funding-source', FILTER_SANITIZE_STRING );
|
||||
|
||||
/**
|
||||
* If customer has chosen a saved credit card payment.
|
||||
*/
|
||||
$saved_credit_card = filter_input( INPUT_POST, 'saved_credit_card', FILTER_SANITIZE_STRING );
|
||||
$change_payment = filter_input( INPUT_POST, 'woocommerce_change_payment', FILTER_SANITIZE_STRING );
|
||||
if ( CreditCardGateway::ID === $payment_method && $saved_credit_card && ! isset( $change_payment ) ) {
|
||||
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$customer = new \WC_Customer( $user_id );
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( (int) $customer->get_id() );
|
||||
|
||||
$selected_token = null;
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->id() === $saved_credit_card ) {
|
||||
$selected_token = $token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $selected_token ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payer = $this->payer_factory->from_customer( $customer );
|
||||
try {
|
||||
$order = $this->order_endpoint->create(
|
||||
array( $purchase_unit ),
|
||||
$payer,
|
||||
$selected_token
|
||||
);
|
||||
|
||||
$this->add_paypal_meta( $wc_order, $order, $this->environment() );
|
||||
|
||||
if ( ! $order->status()->is( OrderStatus::COMPLETED ) ) {
|
||||
$this->logger->warning( "Unexpected status for order {$order->id()} using a saved credit card: " . $order->status()->name() );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! in_array(
|
||||
$order->intent(),
|
||||
array( 'CAPTURE', 'AUTHORIZE' ),
|
||||
true
|
||||
) ) {
|
||||
$this->logger->warning( "Could neither capture nor authorize order {$order->id()} using a saved credit card:" . 'Status: ' . $order->status()->name() . ' Intent: ' . $order->intent() );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'AUTHORIZE' ) {
|
||||
$order = $this->order_endpoint->authorize( $order );
|
||||
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' );
|
||||
}
|
||||
|
||||
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
||||
if ( $transaction_id ) {
|
||||
$this->update_transaction_id( $transaction_id, $wc_order );
|
||||
}
|
||||
|
||||
$this->handle_new_order_status( $order, $wc_order );
|
||||
|
||||
if ( $this->is_free_trial_order( $wc_order ) ) {
|
||||
$this->authorized_payments_processor->void_authorizations( $order );
|
||||
$wc_order->payment_complete();
|
||||
} elseif ( $this->config->has( 'intent' ) && strtoupper( (string) $this->config->get( 'intent' ) ) === 'CAPTURE' ) {
|
||||
$this->authorized_payments_processor->capture_authorized_payment( $wc_order );
|
||||
}
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
} catch ( RuntimeException $error ) {
|
||||
$this->handle_failure( $wc_order, $error );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( PayPalGateway::ID === $payment_method && 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) ) {
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
||||
if ( ! array_filter(
|
||||
$tokens,
|
||||
function ( PaymentToken $token ): bool {
|
||||
return isset( $token->source()->paypal );
|
||||
}
|
||||
) ) {
|
||||
$this->handle_failure( $wc_order, new Exception( 'No saved PayPal account.' ) );
|
||||
return null;
|
||||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen change Subscription payment.
|
||||
*/
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
||||
if ( 'ppcp-credit-card-gateway' === $this->id && $saved_credit_card ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_credit_card );
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
|
||||
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
||||
if ( 'ppcp-gateway' === $this->id && $saved_paypal_payment ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the WC_Order is payed through the approved webhook.
|
||||
*/
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
try {
|
||||
if ( $this->order_processor->process( $wc_order ) ) {
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
as_schedule_single_action(
|
||||
time() + ( 1 * MINUTE_IN_SECONDS ),
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
array(
|
||||
'order_id' => $order_id,
|
||||
'customer_id' => $wc_order->get_customer_id(),
|
||||
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
$this->session_handler->destroy_session_data();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
} catch ( PayPalApiException $error ) {
|
||||
if ( $error->has_detail( 'INSTRUMENT_DECLINED' ) ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Instrument declined. ', 'woocommerce-paypal-payments' ) . $error->details()[0]->description ?? ''
|
||||
);
|
||||
|
||||
$this->session_handler->increment_insufficient_funding_tries();
|
||||
$host = $this->config->has( 'sandbox_on' ) && $this->config->get( 'sandbox_on' ) ?
|
||||
'https://www.sandbox.paypal.com/' : 'https://www.paypal.com/';
|
||||
$url = $host . 'checkoutnow?token=' . $this->session_handler->order()->id();
|
||||
if ( $this->session_handler->insufficient_funding_tries() >= 3 ) {
|
||||
$this->session_handler->destroy_session_data();
|
||||
wc_add_notice(
|
||||
__( 'Please use a different payment method.', 'woocommerce-paypal-payments' ),
|
||||
'error'
|
||||
);
|
||||
return $failure_data;
|
||||
}
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $url,
|
||||
);
|
||||
}
|
||||
|
||||
$error_message = $error->getMessage();
|
||||
if ( $error->issues() ) {
|
||||
$error_message = implode(
|
||||
array_map(
|
||||
function( $issue ) {
|
||||
return $issue->issue . ' ' . $issue->description . '<br/>';
|
||||
},
|
||||
$error->issues()
|
||||
)
|
||||
);
|
||||
}
|
||||
wc_add_notice( $error_message, 'error' );
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
} catch ( RuntimeException $error ) {
|
||||
$this->handle_failure( $wc_order, $error );
|
||||
return $failure_data;
|
||||
}
|
||||
|
||||
wc_add_notice(
|
||||
$this->order_processor->last_error(),
|
||||
'error'
|
||||
);
|
||||
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Could not process order. ', 'woocommerce-paypal-payments' ) . $this->order_processor->last_error()
|
||||
);
|
||||
|
||||
return $failure_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if PayPal or Credit Card gateways are enabled.
|
||||
*
|
||||
|
@ -304,29 +46,86 @@ trait ProcessPaymentTrait {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled the vaulted payment check.
|
||||
*
|
||||
* @param int $wc_order_id The WC order ID.
|
||||
* @param int $customer_id The customer ID.
|
||||
*/
|
||||
protected function schedule_saved_payment_check( int $wc_order_id, int $customer_id ): void {
|
||||
as_schedule_single_action(
|
||||
time() + ( 1 * MINUTE_IN_SECONDS ),
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
array(
|
||||
'order_id' => $wc_order_id,
|
||||
'customer_id' => $customer_id,
|
||||
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the payment failure.
|
||||
*
|
||||
* @param \WC_Order $wc_order The order.
|
||||
* @param Exception $error The error causing the failure.
|
||||
* @param WC_Order|null $wc_order The order.
|
||||
* @param Exception $error The error causing the failure.
|
||||
* @return array The data that can be returned by the gateway process_payment method.
|
||||
*/
|
||||
protected function handle_failure( \WC_Order $wc_order, Exception $error ): void {
|
||||
$this->logger->error( 'Payment failed: ' . $error->getMessage() );
|
||||
protected function handle_payment_failure( ?WC_Order $wc_order, Exception $error ): array {
|
||||
$this->logger->error( 'Payment failed: ' . $this->format_exception( $error ) );
|
||||
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Could not process order. ', 'woocommerce-paypal-payments' ) . $error->getMessage()
|
||||
);
|
||||
if ( $wc_order ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$this->format_exception( $error )
|
||||
);
|
||||
}
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
|
||||
wc_add_notice( $error->getMessage(), 'error' );
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the environment.
|
||||
* Handles the payment completion.
|
||||
*
|
||||
* @return Environment
|
||||
* @param WC_Order|null $wc_order The order.
|
||||
* @param string|null $url The redirect URL.
|
||||
* @return array The data that can be returned by the gateway process_payment method.
|
||||
*/
|
||||
abstract protected function environment(): Environment;
|
||||
protected function handle_payment_success( ?WC_Order $wc_order, string $url = null ): array {
|
||||
if ( ! $url ) {
|
||||
$url = $this->get_return_url( $wc_order );
|
||||
}
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $url,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the exception, including the inner exception.
|
||||
*
|
||||
* @param Throwable $exception The exception to format.
|
||||
* @return string
|
||||
*/
|
||||
protected function format_exception( Throwable $exception ): string {
|
||||
$output = $exception->getMessage() . ' ' . basename( $exception->getFile() ) . ':' . $exception->getLine();
|
||||
$prev = $exception->getPrevious();
|
||||
if ( ! $prev ) {
|
||||
return $output;
|
||||
}
|
||||
if ( $exception instanceof GatewayGenericException ) {
|
||||
$output = '';
|
||||
}
|
||||
return $output . ' ' . $this->format_exception( $prev );
|
||||
}
|
||||
}
|
||||
|
|
131
modules/ppcp-wc-gateway/src/Helper/CheckoutHelper.php
Normal file
131
modules/ppcp-wc-gateway/src/Helper/CheckoutHelper.php
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
/**
|
||||
* The Checkout helper.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
|
||||
use DateTime;
|
||||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Product;
|
||||
use WC_Product_Variable;
|
||||
use WC_Product_Variation;
|
||||
|
||||
/**
|
||||
* CheckoutHelper class.
|
||||
*/
|
||||
class CheckoutHelper {
|
||||
|
||||
/**
|
||||
* Checks if amount is allowed within the given range.
|
||||
*
|
||||
* @param float $minimum Minimum amount.
|
||||
* @param float $maximum Maximum amount.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_checkout_amount_allowed( float $minimum, float $maximum ): bool {
|
||||
$cart = WC()->cart ?? null;
|
||||
if ( $cart && ! is_checkout_pay_page() ) {
|
||||
$cart_total = (float) $cart->get_total( 'numeric' );
|
||||
if ( $cart_total < $minimum || $cart_total > $maximum ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$items = $cart->get_cart_contents();
|
||||
foreach ( $items as $item ) {
|
||||
$product = wc_get_product( $item['product_id'] );
|
||||
if ( is_a( $product, WC_Product::class ) && ! $this->is_physical_product( $product ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_wc_endpoint_url( 'order-pay' ) ) {
|
||||
/**
|
||||
* Needed for WordPress `query_vars`.
|
||||
*
|
||||
* @psalm-suppress InvalidGlobal
|
||||
*/
|
||||
global $wp;
|
||||
|
||||
if ( isset( $wp->query_vars['order-pay'] ) && absint( $wp->query_vars['order-pay'] ) > 0 ) {
|
||||
$order_id = absint( $wp->query_vars['order-pay'] );
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( is_a( $order, WC_Order::class ) ) {
|
||||
$order_total = (float) $order->get_total();
|
||||
if ( $order_total < $minimum || $order_total > $maximum ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $order->get_items() as $item_id => $item ) {
|
||||
if ( is_a( $item, WC_Order_Item_Product::class ) ) {
|
||||
$product = wc_get_product( $item->get_product_id() );
|
||||
if ( is_a( $product, WC_Product::class ) && ! $this->is_physical_product( $product ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures date is valid and at least 18 years back.
|
||||
*
|
||||
* @param string $date The date.
|
||||
* @param string $format The date format.
|
||||
* @return bool
|
||||
*/
|
||||
public function validate_birth_date( string $date, string $format = 'Y-m-d' ): bool {
|
||||
$d = DateTime::createFromFormat( $format, $date );
|
||||
if ( false === $d ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $date !== $d->format( $format ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$date_time = strtotime( $date );
|
||||
if ( $date_time && time() < strtotime( '+18 years', $date_time ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( $date_time < strtotime( '-100 years', time() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures product is neither downloadable nor virtual.
|
||||
*
|
||||
* @param WC_Product $product WC product.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_physical_product( WC_Product $product ):bool {
|
||||
if ( $product->is_downloadable() || $product->is_virtual() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_a( $product, WC_Product_Variable::class ) ) {
|
||||
foreach ( $product->get_available_variations( 'object' ) as $variation ) {
|
||||
if ( is_a( $variation, WC_Product_Variation::class ) ) {
|
||||
if ( true === $variation->is_downloadable() || true === $variation->is_virtual() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -9,12 +9,7 @@ declare( strict_types=1 );
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
|
||||
use DateTime;
|
||||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Product;
|
||||
use WC_Product_Variable;
|
||||
use WC_Product_Variation;
|
||||
|
||||
/**
|
||||
* Class PayUponInvoiceHelper
|
||||
|
@ -22,52 +17,19 @@ use WC_Product_Variation;
|
|||
class PayUponInvoiceHelper {
|
||||
|
||||
/**
|
||||
* Ensures date is valid and at least 18 years back.
|
||||
* The checkout helper.
|
||||
*
|
||||
* @param string $date The date.
|
||||
* @param string $format The date format.
|
||||
* @return bool
|
||||
* @var CheckoutHelper
|
||||
*/
|
||||
public function validate_birth_date( string $date, string $format = 'Y-m-d' ): bool {
|
||||
$d = DateTime::createFromFormat( $format, $date );
|
||||
if ( false === $d ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $date !== $d->format( $format ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$date_time = strtotime( $date );
|
||||
if ( $date_time && time() < strtotime( '+18 years', $date_time ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected $checkout_helper;
|
||||
|
||||
/**
|
||||
* Ensures product is ready for PUI.
|
||||
* PayUponInvoiceHelper constructor.
|
||||
*
|
||||
* @param WC_Product $product WC product.
|
||||
* @return bool
|
||||
* @param CheckoutHelper $checkout_helper The checkout helper.
|
||||
*/
|
||||
public function product_ready_for_pui( WC_Product $product ):bool {
|
||||
if ( $product->is_downloadable() || $product->is_virtual() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_a( $product, WC_Product_Variable::class ) ) {
|
||||
foreach ( $product->get_available_variations( 'object' ) as $variation ) {
|
||||
if ( is_a( $variation, WC_Product_Variation::class ) ) {
|
||||
if ( true === $variation->is_downloadable() || true === $variation->is_virtual() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
public function __construct( CheckoutHelper $checkout_helper ) {
|
||||
$this->checkout_helper = $checkout_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,55 +48,34 @@ class PayUponInvoiceHelper {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ( 'EUR' !== get_woocommerce_currency() ) {
|
||||
if ( ! $this->is_valid_currency() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cart = WC()->cart ?? null;
|
||||
if ( $cart && ! is_checkout_pay_page() ) {
|
||||
$cart_total = (float) $cart->get_total( 'numeric' );
|
||||
if ( $cart_total < 5 || $cart_total > 2500 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$items = $cart->get_cart_contents();
|
||||
foreach ( $items as $item ) {
|
||||
$product = wc_get_product( $item['product_id'] );
|
||||
if ( is_a( $product, WC_Product::class ) && ! $this->product_ready_for_pui( $product ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_wc_endpoint_url( 'order-pay' ) ) {
|
||||
/**
|
||||
* Needed for WordPress `query_vars`.
|
||||
*
|
||||
* @psalm-suppress InvalidGlobal
|
||||
*/
|
||||
global $wp;
|
||||
|
||||
if ( isset( $wp->query_vars['order-pay'] ) && absint( $wp->query_vars['order-pay'] ) > 0 ) {
|
||||
$order_id = absint( $wp->query_vars['order-pay'] );
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( is_a( $order, WC_Order::class ) ) {
|
||||
$order_total = (float) $order->get_total();
|
||||
if ( $order_total < 5 || $order_total > 2500 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $order->get_items() as $item_id => $item ) {
|
||||
if ( is_a( $item, WC_Order_Item_Product::class ) ) {
|
||||
$product = wc_get_product( $item->get_product_id() );
|
||||
if ( is_a( $product, WC_Product::class ) && ! $this->product_ready_for_pui( $product ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ! $this->checkout_helper->is_checkout_amount_allowed( 5, 2500 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if currency is allowed for PUI.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_valid_currency(): bool {
|
||||
global $wp;
|
||||
$order_id = isset( $wp->query_vars['order-pay'] ) ? (int) $wp->query_vars['order-pay'] : 0;
|
||||
if ( 0 === $order_id ) {
|
||||
return 'EUR' === get_woocommerce_currency();
|
||||
}
|
||||
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( is_a( $order, WC_Order::class ) ) {
|
||||
return 'EUR' === $order->get_currency();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Creates the admin message about the DCC gateway being enabled without the PayPal gateway.
|
||||
* Creates the admin message about the gateway being enabled without the PayPal gateway.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Notice
|
||||
*/
|
||||
|
@ -9,14 +9,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Notice;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Creates the admin message about the DCC gateway being enabled without the PayPal gateway.
|
||||
* Creates the admin message about the gateway being enabled without the PayPal gateway.
|
||||
*/
|
||||
class DccWithoutPayPalAdminNotice {
|
||||
class GatewayWithoutPayPalAdminNotice {
|
||||
/**
|
||||
* The gateway ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* The state.
|
||||
|
@ -49,17 +56,20 @@ class DccWithoutPayPalAdminNotice {
|
|||
/**
|
||||
* ConnectAdminNotice constructor.
|
||||
*
|
||||
* @param string $id The gateway ID.
|
||||
* @param State $state The state.
|
||||
* @param ContainerInterface $settings The settings.
|
||||
* @param bool $is_payments_page Whether the current page is the WC payment page.
|
||||
* @param bool $is_ppcp_settings_page Whether the current page is the PPCP settings page.
|
||||
*/
|
||||
public function __construct(
|
||||
string $id,
|
||||
State $state,
|
||||
ContainerInterface $settings,
|
||||
bool $is_payments_page,
|
||||
bool $is_ppcp_settings_page
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->state = $state;
|
||||
$this->settings = $settings;
|
||||
$this->is_payments_page = $is_payments_page;
|
||||
|
@ -76,12 +86,20 @@ class DccWithoutPayPalAdminNotice {
|
|||
return null;
|
||||
}
|
||||
|
||||
$gateway = $this->get_gateway();
|
||||
if ( ! $gateway ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$name = $gateway->get_method_title();
|
||||
|
||||
$message = sprintf(
|
||||
/* translators: %1$s the gateway name. */
|
||||
/* translators: %1$s the gateway name, %2$s URL. */
|
||||
__(
|
||||
'PayPal Card Processing cannot be used without the PayPal gateway. <a href="%1$s">Enable the PayPal Gateway</a>.',
|
||||
'%1$s cannot be used without the PayPal gateway. <a href="%2$s">Enable the PayPal gateway</a>.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
$name,
|
||||
admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' )
|
||||
);
|
||||
return new Message( $message, 'warning' );
|
||||
|
@ -93,9 +111,29 @@ class DccWithoutPayPalAdminNotice {
|
|||
* @return bool
|
||||
*/
|
||||
protected function should_display(): bool {
|
||||
return State::STATE_ONBOARDED === $this->state->current_state()
|
||||
&& ( $this->is_payments_page || $this->is_ppcp_settings_page )
|
||||
&& ( $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' ) )
|
||||
&& ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) );
|
||||
if ( State::STATE_ONBOARDED !== $this->state->current_state() ||
|
||||
( ! $this->is_payments_page && ! $this->is_ppcp_settings_page ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$gateway = $this->get_gateway();
|
||||
|
||||
return $gateway && wc_string_to_bool( $gateway->get_option( 'enabled' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the gateway object or null.
|
||||
*
|
||||
* @return WC_Payment_Gateway|null
|
||||
*/
|
||||
protected function get_gateway(): ?WC_Payment_Gateway {
|
||||
$gateways = WC()->payment_gateways->payment_gateways();
|
||||
if ( ! isset( $gateways[ $this->id ] ) ) {
|
||||
return null;
|
||||
}
|
||||
return $gateways[ $this->id ];
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
|||
*/
|
||||
class AuthorizedPaymentsProcessor {
|
||||
|
||||
use PaymentsStatusHandlingTrait;
|
||||
use PaymentsStatusHandlingTrait, TransactionIdHandlingTrait;
|
||||
|
||||
const SUCCESSFUL = 'SUCCESSFUL';
|
||||
const ALREADY_CAPTURED = 'ALREADY_CAPTURED';
|
||||
|
@ -200,6 +200,9 @@ class AuthorizedPaymentsProcessor {
|
|||
|
||||
$this->handle_capture_status( $capture, $wc_order );
|
||||
|
||||
$transaction_id = $capture->id();
|
||||
$this->update_transaction_id( $transaction_id, $wc_order );
|
||||
|
||||
if ( self::SUCCESSFUL === $result_status ) {
|
||||
if ( $capture->status()->is( CaptureStatus::COMPLETED ) ) {
|
||||
$wc_order->add_order_note(
|
||||
|
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||
|
@ -34,6 +35,7 @@ trait PageMatcherTrait {
|
|||
$gateway_page_id_map = array(
|
||||
PayPalGateway::ID => 'paypal',
|
||||
CreditCardGateway::ID => 'dcc', // TODO: consider using just the gateway ID for PayPal and DCC too.
|
||||
CardButtonGateway::ID => CardButtonGateway::ID,
|
||||
WebhooksStatusPage::ID => WebhooksStatusPage::ID,
|
||||
);
|
||||
return array_key_exists( $current_page_id, $gateway_page_id_map )
|
||||
|
|
|
@ -10,8 +10,6 @@ declare( strict_types=1 );
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||
|
||||
/**
|
||||
|
@ -29,21 +27,21 @@ class SectionsRenderer {
|
|||
protected $page_id;
|
||||
|
||||
/**
|
||||
* The api shop country.
|
||||
* Key - page/gateway ID, value - displayed text.
|
||||
*
|
||||
* @var string
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $api_shop_country;
|
||||
protected $sections;
|
||||
|
||||
/**
|
||||
* SectionsRenderer constructor.
|
||||
*
|
||||
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
||||
* @param string $api_shop_country The api shop country.
|
||||
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
||||
* @param array<string, string> $sections Key - page/gateway ID, value - displayed text.
|
||||
*/
|
||||
public function __construct( string $page_id, string $api_shop_country ) {
|
||||
$this->page_id = $page_id;
|
||||
$this->api_shop_country = $api_shop_country;
|
||||
public function __construct( string $page_id, array $sections ) {
|
||||
$this->page_id = $page_id;
|
||||
$this->sections = $sections;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,34 +56,26 @@ class SectionsRenderer {
|
|||
/**
|
||||
* Renders the Sections tab.
|
||||
*/
|
||||
public function render() {
|
||||
public function render(): string {
|
||||
if ( ! $this->should_render() ) {
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
$sections = array(
|
||||
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
|
||||
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
|
||||
PayUponInvoiceGateway::ID => __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' ),
|
||||
WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
$html = '<nav class="nav-tab-wrapper woo-nav-tab-wrapper">';
|
||||
|
||||
if ( 'DE' !== $this->api_shop_country ) {
|
||||
unset( $sections[ PayUponInvoiceGateway::ID ] );
|
||||
}
|
||||
|
||||
echo '<ul class="subsubsub">';
|
||||
|
||||
$array_keys = array_keys( $sections );
|
||||
|
||||
foreach ( $sections as $id => $label ) {
|
||||
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&' . self::KEY . '=' . $id );
|
||||
if ( PayUponInvoiceGateway::ID === $id ) {
|
||||
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-pay-upon-invoice-gateway' );
|
||||
foreach ( $this->sections as $id => $label ) {
|
||||
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=' . $id );
|
||||
if ( in_array( $id, array( CreditCardGateway::ID, WebhooksStatusPage::ID ), true ) ) {
|
||||
// We need section=ppcp-gateway for the webhooks page because it is not a gateway,
|
||||
// and for DCC because otherwise it will not render the page if gateway is not available (country/currency).
|
||||
// Other gateways render fields differently, and their pages are not expected to work when gateway is not available.
|
||||
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&' . self::KEY . '=' . $id );
|
||||
}
|
||||
echo '<li><a href="' . esc_url( $url ) . '" class="' . ( $this->page_id === $id ? 'current' : '' ) . '">' . esc_html( $label ) . '</a> ' . ( end( $array_keys ) === $id ? '' : '|' ) . ' </li>';
|
||||
$html .= '<a href="' . esc_url( $url ) . '" class="nav-tab ' . ( $this->page_id === $id ? 'nav-tab-active' : '' ) . '">' . esc_html( $label ) . '</a> ';
|
||||
}
|
||||
|
||||
echo '</ul><br class="clear" />';
|
||||
$html .= '</nav>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\GatewayWithoutPayPalAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
@ -66,13 +66,12 @@ class WCGatewayModule implements ModuleInterface {
|
|||
'woocommerce_sections_checkout',
|
||||
function() use ( $c ) {
|
||||
$section_renderer = $c->get( 'wcgateway.settings.sections-renderer' );
|
||||
/**
|
||||
* The Section Renderer.
|
||||
*
|
||||
* @var SectionsRenderer $section_renderer
|
||||
*/
|
||||
$section_renderer->render();
|
||||
}
|
||||
assert( $section_renderer instanceof SectionsRenderer );
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput
|
||||
echo $section_renderer->render();
|
||||
},
|
||||
20
|
||||
);
|
||||
|
||||
add_action(
|
||||
|
@ -164,11 +163,15 @@ class WCGatewayModule implements ModuleInterface {
|
|||
$notices[] = $connect_message;
|
||||
}
|
||||
|
||||
$dcc_without_paypal_notice = $c->get( 'wcgateway.notice.dcc-without-paypal' );
|
||||
assert( $dcc_without_paypal_notice instanceof DccWithoutPayPalAdminNotice );
|
||||
$dcc_without_paypal_message = $dcc_without_paypal_notice->message();
|
||||
if ( $dcc_without_paypal_message ) {
|
||||
$notices[] = $dcc_without_paypal_message;
|
||||
foreach ( array(
|
||||
$c->get( 'wcgateway.notice.dcc-without-paypal' ),
|
||||
$c->get( 'wcgateway.notice.card-button-without-paypal' ),
|
||||
) as $gateway_without_paypal_notice ) {
|
||||
assert( $gateway_without_paypal_notice instanceof GatewayWithoutPayPalAdminNotice );
|
||||
$message = $gateway_without_paypal_notice->message();
|
||||
if ( $message ) {
|
||||
$notices[] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
$authorize_order_action = $c->get( 'wcgateway.notice.authorize-order-action' );
|
||||
|
@ -228,9 +231,13 @@ class WCGatewayModule implements ModuleInterface {
|
|||
add_action(
|
||||
'init',
|
||||
function () use ( $c ) {
|
||||
if ( 'DE' === $c->get( 'api.shop.country' ) && 'EUR' === get_woocommerce_currency() ) {
|
||||
if ( 'DE' === $c->get( 'api.shop.country' ) ) {
|
||||
( $c->get( 'wcgateway.pay-upon-invoice' ) )->init();
|
||||
}
|
||||
|
||||
if ( defined( 'PPCP_FLAG_OXXO' ) && PPCP_FLAG_OXXO === true ) {
|
||||
( $c->get( 'wcgateway.oxxo' ) )->init();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -260,6 +267,18 @@ class WCGatewayModule implements ModuleInterface {
|
|||
10,
|
||||
2
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_ppc-oxxo',
|
||||
static function () use ( $c ) {
|
||||
if ( defined( 'PPCP_FLAG_OXXO' ) && PPCP_FLAG_OXXO === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$endpoint = $c->get( 'wcgateway.endpoint.oxxo' );
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,7 +291,12 @@ class WCGatewayModule implements ModuleInterface {
|
|||
add_filter(
|
||||
'woocommerce_payment_gateways',
|
||||
static function ( $methods ) use ( $container ): array {
|
||||
$methods[] = $container->get( 'wcgateway.paypal-gateway' );
|
||||
$paypal_gateway = $container->get( 'wcgateway.paypal-gateway' );
|
||||
assert( $paypal_gateway instanceof \WC_Payment_Gateway );
|
||||
|
||||
$paypal_gateway_enabled = wc_string_to_bool( $paypal_gateway->get_option( 'enabled' ) );
|
||||
|
||||
$methods[] = $paypal_gateway;
|
||||
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
|
||||
|
||||
/**
|
||||
|
@ -284,10 +308,18 @@ class WCGatewayModule implements ModuleInterface {
|
|||
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
|
||||
}
|
||||
|
||||
if ( $paypal_gateway_enabled && $container->get( 'wcgateway.settings.allow_card_button_gateway' ) ) {
|
||||
$methods[] = $container->get( 'wcgateway.card-button-gateway' );
|
||||
}
|
||||
|
||||
if ( 'DE' === $container->get( 'api.shop.country' ) ) {
|
||||
$methods[] = $container->get( 'wcgateway.pay-upon-invoice-gateway' );
|
||||
}
|
||||
|
||||
if ( defined( 'PPCP_FLAG_OXXO' ) && PPCP_FLAG_OXXO === true ) {
|
||||
$methods[] = $container->get( 'wcgateway.oxxo-gateway' );
|
||||
}
|
||||
|
||||
return (array) $methods;
|
||||
}
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@ module.exports = {
|
|||
entry: {
|
||||
'gateway-settings': path.resolve('./resources/js/gateway-settings.js'),
|
||||
'pay-upon-invoice': path.resolve('./resources/js/pay-upon-invoice.js'),
|
||||
'oxxo': path.resolve('./resources/js/oxxo.js'),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'assets/'),
|
||||
|
|
|
@ -873,6 +873,46 @@
|
|||
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3"
|
||||
integrity sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.0":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
|
||||
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
|
||||
dependencies:
|
||||
"@jridgewell/set-array" "^1.0.1"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.0.3":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
||||
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
||||
|
||||
"@jridgewell/set-array@^1.0.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
|
||||
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||
|
||||
"@jridgewell/source-map@^0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
|
||||
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10":
|
||||
version "1.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.9":
|
||||
version "0.3.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
|
||||
integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@types/eslint-scope@^3.7.0":
|
||||
version "3.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e"
|
||||
|
@ -1057,10 +1097,10 @@ acorn-import-assertions@^1.7.6:
|
|||
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz#580e3ffcae6770eebeec76c3b9723201e9d01f78"
|
||||
integrity sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==
|
||||
|
||||
acorn@^8.4.1:
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
|
||||
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
|
||||
acorn@^8.4.1, acorn@^8.5.0:
|
||||
version "8.7.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
|
||||
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
|
||||
|
||||
ajv-keywords@^3.5.2:
|
||||
version "3.5.2"
|
||||
|
@ -1902,9 +1942,9 @@ signal-exit@^3.0.3:
|
|||
integrity sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==
|
||||
|
||||
source-map-support@~0.5.20:
|
||||
version "0.5.20"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9"
|
||||
integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==
|
||||
version "0.5.21"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
||||
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
|
||||
dependencies:
|
||||
buffer-from "^1.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
@ -1919,11 +1959,6 @@ source-map@^0.6.0, source-map@^0.6.1:
|
|||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@~0.7.2:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
|
||||
|
||||
strip-final-newline@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||
|
@ -1961,12 +1996,13 @@ terser-webpack-plugin@^5.1.3:
|
|||
terser "^5.7.2"
|
||||
|
||||
terser@^5.7.2:
|
||||
version "5.9.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351"
|
||||
integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==
|
||||
version "5.14.2"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
|
||||
integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
|
||||
dependencies:
|
||||
"@jridgewell/source-map" "^0.3.2"
|
||||
acorn "^8.5.0"
|
||||
commander "^2.20.0"
|
||||
source-map "~0.7.2"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
|
|
|
@ -20,6 +20,8 @@ use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulationStateEndpoint;
|
|||
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderApproved;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderCompleted;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureCompleted;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureDenied;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCapturePending;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureRefunded;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureReversed;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
@ -78,6 +80,7 @@ return array(
|
|||
new PaymentCaptureCompleted( $logger, $prefix, $order_endpoint ),
|
||||
new VaultPaymentTokenCreated( $logger, $prefix, $authorized_payments_processor ),
|
||||
new VaultCreditCardCreated( $logger, $prefix ),
|
||||
new PaymentCapturePending( $logger ),
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
|
||||
/**
|
||||
|
@ -189,7 +190,7 @@ class CheckoutOrderApproved implements RequestHandler {
|
|||
}
|
||||
|
||||
foreach ( $wc_orders as $wc_order ) {
|
||||
if ( PayUponInvoiceGateway::ID === $wc_order->get_payment_method() ) {
|
||||
if ( PayUponInvoiceGateway::ID === $wc_order->get_payment_method() || OXXOGateway::ID === $wc_order->get_payment_method() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
122
modules/ppcp-webhooks/src/Handler/PaymentCapturePending.php
Normal file
122
modules/ppcp-webhooks/src/Handler/PaymentCapturePending.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles the Webhook PAYMENT.CAPTURE.PENDING
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
/**
|
||||
* Class PaymentCaptureCompleted
|
||||
*/
|
||||
class PaymentCapturePending implements RequestHandler {
|
||||
|
||||
use PrefixTrait;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* PaymentCaptureCompleted constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* The event types a handler handles.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function event_types(): array {
|
||||
return array( 'PAYMENT.CAPTURE.PENDING' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a handler is responsible for a given request or not.
|
||||
*
|
||||
* @param \WP_REST_Request $request The request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function responsible_for_request( \WP_REST_Request $request ): bool {
|
||||
return in_array( $request['event_type'], $this->event_types(), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for handling the request.
|
||||
*
|
||||
* @param WP_REST_Request $request The request.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function handle_request( WP_REST_Request $request ): WP_REST_Response {
|
||||
$response = array( 'success' => false );
|
||||
$order_id = $request['resource'] !== null && isset( $request['resource']['custom_id'] )
|
||||
? $this->sanitize_custom_id( $request['resource']['custom_id'] )
|
||||
: 0;
|
||||
if ( ! $order_id ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
__(
|
||||
'No order for webhook event %s was found.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
$request['id'] !== null && isset( $request['id'] ) ? $request['id'] : ''
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$message,
|
||||
array(
|
||||
'request' => $request,
|
||||
)
|
||||
);
|
||||
$response['message'] = $message;
|
||||
return new WP_REST_Response( $response );
|
||||
}
|
||||
|
||||
$resource = $request['resource'];
|
||||
if ( ! is_array( $resource ) ) {
|
||||
$message = 'Resource data not found in webhook request.';
|
||||
$this->logger->warning( $message, array( 'request' => $request ) );
|
||||
$response['message'] = $message;
|
||||
return new WP_REST_Response( $response );
|
||||
}
|
||||
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
||||
$message = sprintf(
|
||||
'WC order for PayPal ID %s not found.',
|
||||
$request['resource'] !== null && isset( $request['resource']['id'] ) ? $request['resource']['id'] : ''
|
||||
);
|
||||
|
||||
$this->logger->warning( $message );
|
||||
|
||||
$response['message'] = $message;
|
||||
return new WP_REST_Response( $response );
|
||||
}
|
||||
|
||||
if ( $wc_order->get_status() === 'pending' ) {
|
||||
$wc_order->update_status( 'on-hold', __( 'Payment initiation was successful, and is waiting for the buyer to complete the payment.', 'woocommerce-paypal-payments' ) );
|
||||
|
||||
}
|
||||
|
||||
$response['success'] = true;
|
||||
return new WP_REST_Response( $response );
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ class PaymentCaptureRefunded implements RequestHandler {
|
|||
* @return string[]
|
||||
*/
|
||||
public function event_types(): array {
|
||||
return array( 'PAYMENT.CAPTURE.REFUNDED' );
|
||||
return array( 'PAYMENT.CAPTURE.REFUNDED', 'PAYMENT.AUTHORIZATION.VOIDED' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -112,12 +112,17 @@ class PaymentCaptureReversed implements RequestHandler {
|
|||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows adding an update status note.
|
||||
*/
|
||||
$note = apply_filters( 'ppcp_payment_capture_reversed_webhook_update_status_note', '', $wc_order, $request['event_type'] );
|
||||
|
||||
/**
|
||||
* The WooCommerce order.
|
||||
*
|
||||
* @var \WC_Order $wc_order
|
||||
*/
|
||||
$response['success'] = (bool) $wc_order->update_status( 'cancelled' );
|
||||
$response['success'] = (bool) $wc_order->update_status( 'cancelled', $note );
|
||||
|
||||
$message = $response['success'] ? sprintf(
|
||||
// translators: %1$s is the order id.
|
||||
|
|
|
@ -873,6 +873,46 @@
|
|||
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3"
|
||||
integrity sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.0":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
|
||||
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
|
||||
dependencies:
|
||||
"@jridgewell/set-array" "^1.0.1"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.0.3":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
||||
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
||||
|
||||
"@jridgewell/set-array@^1.0.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
|
||||
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||
|
||||
"@jridgewell/source-map@^0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
|
||||
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10":
|
||||
version "1.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.9":
|
||||
version "0.3.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
|
||||
integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@types/eslint-scope@^3.7.0":
|
||||
version "3.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e"
|
||||
|
@ -1057,10 +1097,10 @@ acorn-import-assertions@^1.7.6:
|
|||
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz#580e3ffcae6770eebeec76c3b9723201e9d01f78"
|
||||
integrity sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==
|
||||
|
||||
acorn@^8.4.1:
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
|
||||
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
|
||||
acorn@^8.4.1, acorn@^8.5.0:
|
||||
version "8.7.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
|
||||
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
|
||||
|
||||
ajv-keywords@^3.5.2:
|
||||
version "3.5.2"
|
||||
|
@ -2017,9 +2057,9 @@ signal-exit@^3.0.3:
|
|||
integrity sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==
|
||||
|
||||
source-map-support@~0.5.20:
|
||||
version "0.5.20"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9"
|
||||
integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==
|
||||
version "0.5.21"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
||||
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
|
||||
dependencies:
|
||||
buffer-from "^1.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
@ -2034,11 +2074,6 @@ source-map@^0.6.0, source-map@^0.6.1:
|
|||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@~0.7.2:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
|
||||
|
||||
strip-final-newline@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||
|
@ -2076,12 +2111,13 @@ terser-webpack-plugin@^5.1.3:
|
|||
terser "^5.7.2"
|
||||
|
||||
terser@^5.7.2:
|
||||
version "5.9.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351"
|
||||
integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==
|
||||
version "5.14.2"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
|
||||
integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
|
||||
dependencies:
|
||||
"@jridgewell/source-map" "^0.3.2"
|
||||
acorn "^8.5.0"
|
||||
commander "^2.20.0"
|
||||
source-map "~0.7.2"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "woocommerce-paypal-payments",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.2",
|
||||
"description": "WooCommerce PayPal Payments",
|
||||
"repository": "https://github.com/woocommerce/woocommerce-paypal-payments",
|
||||
"license": "GPL-2.0",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"redefinable-internals": [
|
||||
"json_decode"
|
||||
]
|
||||
"redefinable-internals": [
|
||||
"json_decode",
|
||||
"filter_input"
|
||||
]
|
||||
}
|
||||
|
|
27
readme.txt
27
readme.txt
|
@ -4,7 +4,7 @@ Tags: woocommerce, paypal, payments, ecommerce, e-commerce, store, sales, sell,
|
|||
Requires at least: 5.3
|
||||
Tested up to: 6.0
|
||||
Requires PHP: 7.1
|
||||
Stable tag: 1.9.0
|
||||
Stable tag: 1.9.2
|
||||
License: GPLv2
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
|
@ -81,6 +81,31 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
|
||||
== Changelog ==
|
||||
|
||||
= 1.9.2 =
|
||||
* Fix - Do not allow birth date older than 100 years for PUI. #743
|
||||
* Fix - Store the customer id for vaulted payment method in usermeta to not lose vaulted methods after the invoice prefix change. #698
|
||||
* Fix - Capture Virtual-Only Orders setting did not auto-capture subscription renewal payments. #626
|
||||
* Fix - Voiding authorization at PayPal did not update the status/order notes. #712
|
||||
* Fix - PayPal scripts were loading on pages without smart buttons or Pay Later messaging. #750
|
||||
* Fix - Do not show links for unavailable gateways settings pages. #753
|
||||
* Fix - The smart buttons were not loaded on single product page if a subscription product exists in the cart. #703
|
||||
* Fix - DCC was causing other gateways to disappear after checkout validation error. #757
|
||||
* Fix - Buttons not loading on single product page with default settings when product is in cart. #777
|
||||
* Enhancement - Improve Checkout Field Validation Message. #739
|
||||
* Enhancement - Handle PAYER_ACTION_REQUIRED error. #759
|
||||
|
||||
= 1.9.1 =
|
||||
* Fix - ITEM_TOTAL_MISMATCH error when checking out with multiple products #721
|
||||
* Fix - Unable to purchase a product with Credit card button in pay for order page #718
|
||||
* Fix - Pay Later messaging only displayed when smart button is active on the same page #283
|
||||
* Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
|
||||
* Fix - Placeholders and card type detection not working for PayPal Card Processing (260) #685
|
||||
* Fix - PUI gateway is displayed with unsupported store currency #711
|
||||
* Fix - Wrong PUI locale sent causing error PAYMENT_SOURCE_CANNOT_BE_USED #741
|
||||
* Enhancement - Missing PayPal fee in WC order details for PUI purchase #714
|
||||
* Enhancement - Skip loading of PUI js file on all pages where PUI gateway is not displayed #723
|
||||
* Enhancement - PUI feature capitalization not consistent #724
|
||||
|
||||
= 1.9.0 =
|
||||
* Add - New Feature - Pay Upon Invoice (Germany only) #608
|
||||
* Fix - Order not approved: payment via vaulted PayPal account fails #677
|
||||
|
|
|
@ -46,6 +46,7 @@ class IdentityTokenTest extends TestCase
|
|||
|
||||
public function testGenerateForCustomerReturnsToken()
|
||||
{
|
||||
$id = 1;
|
||||
define( 'PPCP_FLAG_SUBSCRIPTION', true );
|
||||
$token = Mockery::mock(Token::class);
|
||||
$token
|
||||
|
@ -60,6 +61,7 @@ class IdentityTokenTest extends TestCase
|
|||
$this->settings->shouldReceive('has')->andReturn(true);
|
||||
$this->settings->shouldReceive('get')->andReturn(true);
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('prefix1');
|
||||
expect('update_user_meta')->with($id, 'ppcp_customer_id', 'prefix1');
|
||||
|
||||
$rawResponse = [
|
||||
'body' => '{"client_token":"abc123", "expires_in":3600}',
|
||||
|
@ -97,6 +99,7 @@ class IdentityTokenTest extends TestCase
|
|||
|
||||
public function testGenerateForCustomerFailsBecauseWpError()
|
||||
{
|
||||
$id = 1;
|
||||
$token = Mockery::mock(Token::class);
|
||||
$token
|
||||
->expects('token')->andReturn('bearer');
|
||||
|
@ -111,7 +114,8 @@ class IdentityTokenTest extends TestCase
|
|||
$this->logger->shouldReceive('debug');
|
||||
$this->settings->shouldReceive('has')->andReturn(true);
|
||||
$this->settings->shouldReceive('get')->andReturn(true);
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user');
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('prefix1');
|
||||
expect('update_user_meta')->with($id, 'ppcp_customer_id', 'prefix1');
|
||||
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->sut->generate_for_user(1);
|
||||
|
@ -119,6 +123,7 @@ class IdentityTokenTest extends TestCase
|
|||
|
||||
public function testGenerateForCustomerFailsBecauseResponseCodeIsNot200()
|
||||
{
|
||||
$id = 1;
|
||||
$token = Mockery::mock(Token::class);
|
||||
$token
|
||||
->expects('token')->andReturn('bearer');
|
||||
|
@ -137,7 +142,8 @@ class IdentityTokenTest extends TestCase
|
|||
$this->logger->shouldReceive('debug');
|
||||
$this->settings->shouldReceive('has')->andReturn(true);
|
||||
$this->settings->shouldReceive('get')->andReturn(true);
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user');
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('prefix1');
|
||||
expect('update_user_meta')->with($id, 'ppcp_customer_id', 'prefix1');
|
||||
|
||||
$this->expectException(PayPalApiException::class);
|
||||
$this->sut->generate_for_user(1);
|
||||
|
|
|
@ -952,7 +952,7 @@ class OrderEndpointTest extends TestCase
|
|||
->expects('email_address')
|
||||
->andReturn('');
|
||||
|
||||
$result = $testee->create([$purchaseUnit], $payer);
|
||||
$result = $testee->create([$purchaseUnit], ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING, $payer);
|
||||
$this->assertEquals($expectedOrder, $result);
|
||||
}
|
||||
|
||||
|
@ -1046,10 +1046,8 @@ class OrderEndpointTest extends TestCase
|
|||
|
||||
$payer = Mockery::mock(Payer::class);
|
||||
$payer->expects('email_address')->andReturn('email@email.com');
|
||||
$payerName = Mockery::mock(PayerName::class);
|
||||
$payer->expects('name')->andReturn($payerName);
|
||||
$payer->expects('to_array')->andReturn(['payer']);
|
||||
$result = $testee->create([$purchaseUnit], $payer);
|
||||
$result = $testee->create([$purchaseUnit], ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE, $payer);
|
||||
$this->assertEquals($expectedOrder, $result);
|
||||
}
|
||||
|
||||
|
@ -1138,10 +1136,8 @@ class OrderEndpointTest extends TestCase
|
|||
|
||||
$payer = Mockery::mock(Payer::class);
|
||||
$payer->expects('email_address')->andReturn('email@email.com');
|
||||
$payerName = Mockery::mock(PayerName::class);
|
||||
$payer->expects('name')->andReturn($payerName);
|
||||
$payer->expects('to_array')->andReturn(['payer']);
|
||||
$testee->create([$purchaseUnit], $payer);
|
||||
$testee->create([$purchaseUnit], ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING, $payer);
|
||||
}
|
||||
|
||||
public function testCreateForPurchaseUnitsIsNot201()
|
||||
|
@ -1229,9 +1225,7 @@ class OrderEndpointTest extends TestCase
|
|||
$this->expectException(RuntimeException::class);
|
||||
$payer = Mockery::mock(Payer::class);
|
||||
$payer->expects('email_address')->andReturn('email@email.com');
|
||||
$payerName = Mockery::mock(PayerName::class);
|
||||
$payer->expects('name')->andReturn($payerName);
|
||||
$payer->expects('to_array')->andReturn(['payer']);
|
||||
$testee->create([$purchaseUnit], $payer);
|
||||
$testee->create([$purchaseUnit], ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE, $payer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,7 @@ class AmountTest extends TestCase
|
|||
|
||||
public function testBreakdownIsNull()
|
||||
{
|
||||
$money = Mockery::mock(Money::class);
|
||||
$money->shouldReceive('currency_code')->andReturn('currencyCode');
|
||||
$money->shouldReceive('value')->andReturn(1.10);
|
||||
$money = new Money(1.10, 'currencyCode');
|
||||
$testee = new Amount($money);
|
||||
|
||||
$this->assertNull($testee->breakdown());
|
||||
|
@ -38,9 +36,7 @@ class AmountTest extends TestCase
|
|||
|
||||
public function testBreakdown()
|
||||
{
|
||||
$money = Mockery::mock(Money::class);
|
||||
$money->shouldReceive('currency_code')->andReturn('currencyCode');
|
||||
$money->shouldReceive('value')->andReturn(1.10);
|
||||
$money = new Money(1.10, 'currencyCode');
|
||||
$breakdown = Mockery::mock(AmountBreakdown::class);
|
||||
$breakdown->shouldReceive('to_array')->andReturn([1]);
|
||||
$testee = new Amount($money, $breakdown);
|
||||
|
|
|
@ -412,10 +412,8 @@ class PurchaseUnitTest extends TestCase
|
|||
foreach ($data as $testKey => $test) {
|
||||
$items = [];
|
||||
foreach ($test['items'] as $key => $item) {
|
||||
$unitAmount = Mockery::mock(Money::class);
|
||||
$unitAmount->shouldReceive('value')->andReturn($item['value']);
|
||||
$tax = Mockery::mock(Money::class);
|
||||
$tax->shouldReceive('value')->andReturn($item['tax']);
|
||||
$unitAmount = new Money($item['value'], 'EUR');
|
||||
$tax = new Money($item['tax'], 'EUR');
|
||||
$items[$key] = Mockery::mock(
|
||||
Item::class,
|
||||
[
|
||||
|
@ -436,15 +434,14 @@ class PurchaseUnitTest extends TestCase
|
|||
return null;
|
||||
}
|
||||
|
||||
$money = Mockery::mock(Money::class);
|
||||
$money->shouldReceive('value')->andReturn($value);
|
||||
$money = new Money($value, 'EUR');
|
||||
return $money;
|
||||
});
|
||||
}
|
||||
}
|
||||
$amount = Mockery::mock(Amount::class);
|
||||
$amount->shouldReceive('to_array')->andReturn(['value' => number_format( $test['amount'], 2, '.', '' ), 'breakdown' => []]);
|
||||
$amount->shouldReceive('value')->andReturn($test['amount']);
|
||||
$amount->shouldReceive('value_str')->andReturn(number_format( $test['amount'], 2, '.', '' ));
|
||||
$amount->shouldReceive('currency_code')->andReturn('EUR');
|
||||
$amount->shouldReceive('breakdown')->andReturn($breakdown);
|
||||
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use Mockery;
|
||||
use WC_Cart;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
|
||||
class ShippingPreferenceFactoryTest extends TestCase
|
||||
{
|
||||
private $testee;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->testee = new ShippingPreferenceFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider forStateData
|
||||
*/
|
||||
public function testFromState(
|
||||
PurchaseUnit $purchase_unit,
|
||||
string $context,
|
||||
?WC_Cart $cart,
|
||||
string $funding_source,
|
||||
string $expected_result
|
||||
) {
|
||||
$result = $this->testee->from_state($purchase_unit, $context, $cart, $funding_source);
|
||||
|
||||
self::assertEquals($expected_result, $result);
|
||||
}
|
||||
|
||||
public function forStateData()
|
||||
{
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
|
||||
'checkout',
|
||||
$this->createCart(true),
|
||||
'',
|
||||
ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(false, Mockery::mock(Shipping::class)),
|
||||
'checkout',
|
||||
$this->createCart(false),
|
||||
'',
|
||||
ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, null),
|
||||
'checkout',
|
||||
$this->createCart(true),
|
||||
'',
|
||||
ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
|
||||
'checkout',
|
||||
$this->createCart(true),
|
||||
'card',
|
||||
ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, null),
|
||||
'product',
|
||||
null,
|
||||
'',
|
||||
ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, null),
|
||||
'pay-now',
|
||||
null,
|
||||
'venmo',
|
||||
ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
|
||||
'pay-now',
|
||||
null,
|
||||
'venmo',
|
||||
ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
|
||||
'pay-now',
|
||||
null,
|
||||
'card',
|
||||
ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, null),
|
||||
'pay-now',
|
||||
null,
|
||||
'card',
|
||||
ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
];
|
||||
}
|
||||
|
||||
private function createPurchaseUnit(bool $containsPhysicalGoods, ?Shipping $shipping): PurchaseUnit {
|
||||
$pu = Mockery::mock(PurchaseUnit::class);
|
||||
$pu->shouldReceive('contains_physical_goods')->andReturn($containsPhysicalGoods);
|
||||
$pu->shouldReceive('shipping')->andReturn($shipping);
|
||||
return $pu;
|
||||
}
|
||||
|
||||
private function createCart(bool $needsShipping): WC_Cart {
|
||||
$cart = Mockery::mock(WC_Cart::class);
|
||||
$cart->shouldReceive('needs_shipping')->andReturn($needsShipping);
|
||||
return $cart;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
|||
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use Mockery;
|
||||
use WooCommerce\WooCommerce\Logging\Logger\NullLogger;
|
||||
|
@ -17,7 +17,7 @@ class ChangeCartEndpointTest extends TestCase
|
|||
/**
|
||||
* @dataProvider dataForTestProducts
|
||||
*/
|
||||
public function testProducts($data, $products, $lineItems, $responseExpectation) {
|
||||
public function testProducts($data, $products, $responseExpectation) {
|
||||
|
||||
$dataStore = Mockery::mock(\WC_Data_Store::class);
|
||||
$cart = Mockery::mock(\WC_Cart::class);
|
||||
|
@ -59,16 +59,21 @@ class ChangeCartEndpointTest extends TestCase
|
|||
->expects('read_request')
|
||||
->with(ChangeCartEndpoint::nonce())
|
||||
->andReturn($data);
|
||||
$cartRepository = Mockery::mock(CartRepository::class);
|
||||
$cartRepository
|
||||
->expects('all')
|
||||
->andReturn($lineItems);
|
||||
|
||||
$pu = Mockery::mock(PurchaseUnit::class);
|
||||
$pu
|
||||
->shouldReceive('to_array')
|
||||
->andReturn($responseExpectation[0]);
|
||||
$purchase_unit_factory = Mockery::mock(PurchaseUnitFactory::class);
|
||||
$purchase_unit_factory
|
||||
->expects('from_wc_cart')
|
||||
->andReturn($pu);
|
||||
|
||||
$testee = new ChangeCartEndpoint(
|
||||
$cart,
|
||||
$shipping,
|
||||
$requestData,
|
||||
$cartRepository,
|
||||
$purchase_unit_factory,
|
||||
$dataStore,
|
||||
new NullLogger()
|
||||
);
|
||||
|
@ -97,15 +102,6 @@ class ChangeCartEndpointTest extends TestCase
|
|||
->with('variable')
|
||||
->andReturn(true);
|
||||
|
||||
$defaultLineItem = Mockery::mock(PurchaseUnit::class);
|
||||
$defaultLineItem
|
||||
->shouldReceive('to_array')
|
||||
->andReturn([1]);
|
||||
$variationLineItem = Mockery::mock(PurchaseUnit::class);
|
||||
$variationLineItem
|
||||
->shouldReceive('to_array')
|
||||
->andReturn([2]);
|
||||
|
||||
$testData = [
|
||||
'default' => [
|
||||
[
|
||||
|
@ -120,9 +116,6 @@ class ChangeCartEndpointTest extends TestCase
|
|||
[
|
||||
$defaultProduct,
|
||||
],
|
||||
[
|
||||
$defaultLineItem,
|
||||
],
|
||||
[
|
||||
[1],
|
||||
]
|
||||
|
@ -162,11 +155,7 @@ class ChangeCartEndpointTest extends TestCase
|
|||
$variationProduct,
|
||||
],
|
||||
[
|
||||
$defaultLineItem,
|
||||
$variationLineItem,
|
||||
],
|
||||
[
|
||||
[1],[2]
|
||||
[1, 2]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
|
|
@ -10,10 +10,11 @@ use ReflectionClass;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\CardBillingMode;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
use WooCommerce\WooCommerce\Logging\Logger\NullLogger;
|
||||
|
@ -145,24 +146,26 @@ class CreateOrderEndpointTest extends TestCase
|
|||
protected function mockTestee()
|
||||
{
|
||||
$request_data = Mockery::mock(RequestData::class);
|
||||
$cart_repository = Mockery::mock(CartRepository::class);
|
||||
$shippingPreferenceFactory = Mockery::mock(ShippingPreferenceFactory::class);
|
||||
$purchase_unit_factory = Mockery::mock(PurchaseUnitFactory::class);
|
||||
$order_endpoint = Mockery::mock(OrderEndpoint::class);
|
||||
$payer_factory = Mockery::mock(PayerFactory::class);
|
||||
$session_handler = Mockery::mock(SessionHandler::class);
|
||||
$settings = Mockery::mock(Settings::class);
|
||||
$early_order_handler = Mockery::mock(EarlyOrderHandler::class);
|
||||
$settings->shouldReceive('has')->andReturnFalse();
|
||||
|
||||
$testee = new CreateOrderEndpoint(
|
||||
$request_data,
|
||||
$cart_repository,
|
||||
$purchase_unit_factory,
|
||||
$shippingPreferenceFactory,
|
||||
$order_endpoint,
|
||||
$payer_factory,
|
||||
$session_handler,
|
||||
$settings,
|
||||
$early_order_handler,
|
||||
false,
|
||||
CardBillingMode::MINIMAL_INPUT,
|
||||
new NullLogger()
|
||||
);
|
||||
return array($payer_factory, $testee);
|
||||
|
|
|
@ -16,12 +16,15 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use Mockery;
|
||||
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
class RenewalHandlerTest extends TestCase
|
||||
{
|
||||
|
@ -31,6 +34,7 @@ class RenewalHandlerTest extends TestCase
|
|||
private $repository;
|
||||
private $orderEndpoint;
|
||||
private $purchaseUnitFactory;
|
||||
private $shippingPreferenceFactory;
|
||||
private $payerFactory;
|
||||
private $environment;
|
||||
private $sut;
|
||||
|
@ -43,8 +47,14 @@ class RenewalHandlerTest extends TestCase
|
|||
$this->repository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$this->orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
$this->purchaseUnitFactory = Mockery::mock(PurchaseUnitFactory::class);
|
||||
$this->shippingPreferenceFactory = Mockery::mock(ShippingPreferenceFactory::class);
|
||||
$this->payerFactory = Mockery::mock(PayerFactory::class);
|
||||
$this->environment = new Environment(new Dictionary([]));
|
||||
$authorizedPaymentProcessor = Mockery::mock(AuthorizedPaymentsProcessor::class);
|
||||
$settings = Mockery::mock(Settings::class);
|
||||
$settings
|
||||
->shouldReceive('has')
|
||||
->andReturnFalse();
|
||||
|
||||
$this->logger->shouldReceive('error')->andReturnUsing(function ($msg) {
|
||||
throw new Exception($msg);
|
||||
|
@ -56,8 +66,11 @@ class RenewalHandlerTest extends TestCase
|
|||
$this->repository,
|
||||
$this->orderEndpoint,
|
||||
$this->purchaseUnitFactory,
|
||||
$this->shippingPreferenceFactory,
|
||||
$this->payerFactory,
|
||||
$this->environment
|
||||
$this->environment,
|
||||
$settings,
|
||||
$authorizedPaymentProcessor
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -133,8 +146,12 @@ class RenewalHandlerTest extends TestCase
|
|||
$this->payerFactory->shouldReceive('from_customer')
|
||||
->andReturn($payer);
|
||||
|
||||
$this->shippingPreferenceFactory->shouldReceive('from_state')
|
||||
->with($purchaseUnit, 'renewal')
|
||||
->andReturn('no_shipping');
|
||||
|
||||
$this->orderEndpoint->shouldReceive('create')
|
||||
->with([$purchaseUnit], $payer, $token)
|
||||
->with([$purchaseUnit], 'no_shipping', $payer, $token)
|
||||
->andReturn($order);
|
||||
|
||||
$wcOrder->shouldReceive('update_status');
|
||||
|
|
146
tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php
Normal file
146
tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php
Normal file
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
namespace PHPUnit\Vaulting;
|
||||
|
||||
use Mockery;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use WC_Customer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSourceCard;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\VaultedCreditCardHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use function Brain\Monkey\Functions\expect;
|
||||
use function Brain\Monkey\Functions\when;
|
||||
|
||||
class VaultedCreditCardHandlerTest extends TestCase
|
||||
{
|
||||
private $subscriptionHelper;
|
||||
private $paymentTokenRepository;
|
||||
private $purchaseUnitFactory;
|
||||
private $payerFactory;
|
||||
private $shippingPreferenceFactory;
|
||||
private $orderEndpoint;
|
||||
private $environment;
|
||||
private $authorizedPaymentProcessor;
|
||||
private $config;
|
||||
private $testee;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||
$this->paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$this->purchaseUnitFactory = Mockery::mock(PurchaseUnitFactory::class);
|
||||
$this->payerFactory = Mockery::mock(PayerFactory::class);
|
||||
$this->shippingPreferenceFactory = Mockery::mock(ShippingPreferenceFactory::class);
|
||||
$this->orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
$this->environment = Mockery::mock(Environment::class);
|
||||
$this->authorizedPaymentProcessor = Mockery::mock(AuthorizedPaymentsProcessor::class);
|
||||
$this->config = Mockery::mock(ContainerInterface::class);
|
||||
|
||||
$this->testee = new VaultedCreditCardHandler(
|
||||
$this->subscriptionHelper,
|
||||
$this->paymentTokenRepository,
|
||||
$this->purchaseUnitFactory,
|
||||
$this->payerFactory,
|
||||
$this->shippingPreferenceFactory,
|
||||
$this->orderEndpoint,
|
||||
$this->environment,
|
||||
$this->authorizedPaymentProcessor,
|
||||
$this->config
|
||||
);
|
||||
}
|
||||
|
||||
public function testHandlePaymentChangingPayment()
|
||||
{
|
||||
when('filter_input')->justReturn(1);
|
||||
$wcOrder = Mockery::mock(\WC_Order::class);
|
||||
$wcOrder->shouldReceive('get_id')->andReturn(1);
|
||||
$this->subscriptionHelper->shouldReceive('has_subscription')->andReturn(true);
|
||||
$this->subscriptionHelper->shouldReceive('is_subscription_change_payment')->andReturn(true);
|
||||
expect('update_post_meta')->with(1, 'payment_token_id', 'abc123');
|
||||
|
||||
$customer = Mockery::mock(WC_Customer::class);
|
||||
|
||||
$result = $this->testee->handle_payment('abc123', $wcOrder, $customer);
|
||||
$this->assertInstanceOf(\WC_Order::class, $result);
|
||||
}
|
||||
|
||||
public function testHandlePayment()
|
||||
{
|
||||
$wcOrder = Mockery::mock(\WC_Order::class);
|
||||
$wcOrder->shouldReceive('get_id')->andReturn(1);
|
||||
$wcOrder->shouldReceive('get_customer_id')->andReturn(1);
|
||||
$wcOrder->shouldReceive('update_meta_data')->andReturn(1);
|
||||
$wcOrder->shouldReceive('save')->once();
|
||||
$wcOrder->shouldReceive('payment_complete')->andReturn(true);
|
||||
|
||||
$token = Mockery::mock(PaymentToken::class);
|
||||
$tokenId = 'abc123';
|
||||
$token->shouldReceive('id')->andReturn($tokenId);
|
||||
$this->paymentTokenRepository->shouldReceive('all_for_user_id')
|
||||
->andReturn([$token]);
|
||||
|
||||
$purchaseUnit = Mockery::mock(PurchaseUnit::class);
|
||||
$this->purchaseUnitFactory->shouldReceive('from_wc_order')
|
||||
->andReturn($purchaseUnit);
|
||||
|
||||
$customer = Mockery::mock(WC_Customer::class);
|
||||
|
||||
$payer = Mockery::mock(Payer::class);
|
||||
$this->payerFactory->shouldReceive('from_wc_order')
|
||||
->andReturn($payer);
|
||||
$this->shippingPreferenceFactory->shouldReceive('from_state')
|
||||
->andReturn('some_preference');
|
||||
|
||||
$order = Mockery::mock(Order::class);
|
||||
$order->shouldReceive('id')->andReturn('1');
|
||||
$order->shouldReceive('intent')->andReturn('CAPTURE');
|
||||
$paymentSource = Mockery::mock(PaymentSource::class);
|
||||
$paymentSourceCard = Mockery::mock(PaymentSourceCard::class);
|
||||
$paymentSource->shouldReceive('card')->andReturn($paymentSourceCard);
|
||||
$order->shouldReceive('payment_source')->andReturn($paymentSource);
|
||||
$orderStatus = Mockery::mock(OrderStatus::class);
|
||||
$orderStatus->shouldReceive('is')->andReturn(true);
|
||||
$order->shouldReceive('status')->andReturn($orderStatus);
|
||||
|
||||
$order->shouldReceive('purchase_units')->andReturn([$purchaseUnit]);
|
||||
$payments = Mockery::mock(Payments::class);
|
||||
$capture = Mockery::mock(Capture::class);
|
||||
$capture->shouldReceive('id')->andReturn('1');
|
||||
$captureStatus = Mockery::mock(CaptureStatus::class);
|
||||
$captureStatus->shouldReceive('details')->andReturn(null);
|
||||
$captureStatus->shouldReceive('name')->andReturn(CaptureStatus::COMPLETED);
|
||||
$capture->shouldReceive('status')->andReturn($captureStatus);
|
||||
$payments->shouldReceive('captures')->andReturn([$capture]);
|
||||
$purchaseUnit->shouldReceive('payments')->andReturn($payments);
|
||||
|
||||
$this->orderEndpoint->shouldReceive('create')
|
||||
->with([$purchaseUnit], 'some_preference', $payer, $token)
|
||||
->andReturn($order);
|
||||
|
||||
$this->environment->shouldReceive('current_environment_is')->andReturn(true);
|
||||
|
||||
$this->config->shouldReceive('has')->andReturn(false);
|
||||
|
||||
$result = $this->testee->handle_payment($tokenId, $wcOrder, $customer);
|
||||
$this->assertInstanceOf(\WC_Order::class, $result);
|
||||
}
|
||||
}
|
109
tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php
Normal file
109
tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Mockery;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\VaultedCreditCardHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
use function Brain\Monkey\Functions\when;
|
||||
|
||||
class CreditCardGatewayTest extends TestCase
|
||||
{
|
||||
private $settingsRenderer;
|
||||
private $orderProcessor;
|
||||
private $config;
|
||||
private $moduleUrl;
|
||||
private $sessionHandler;
|
||||
private $refundProcessor;
|
||||
private $state;
|
||||
private $transactionUrlProvider;
|
||||
private $subscriptionHelper;
|
||||
private $logger;
|
||||
private $paymentsEndpoint;
|
||||
private $vaultedCreditCardHandler;
|
||||
private $testee;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->settingsRenderer = Mockery::mock(SettingsRenderer::class);
|
||||
$this->orderProcessor = Mockery::mock(OrderProcessor::class);
|
||||
$this->config = Mockery::mock(ContainerInterface::class);
|
||||
$this->moduleUrl = '';
|
||||
$this->sessionHandler = Mockery::mock(SessionHandler::class);
|
||||
$this->refundProcessor = Mockery::mock(RefundProcessor::class);
|
||||
$this->state = Mockery::mock(State::class);
|
||||
$this->transactionUrlProvider = Mockery::mock(TransactionUrlProvider::class);
|
||||
$this->subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||
$this->logger = Mockery::mock(LoggerInterface::class);
|
||||
$this->paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$this->vaultedCreditCardHandler = Mockery::mock(VaultedCreditCardHandler::class);
|
||||
|
||||
$this->state->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
|
||||
$this->config->shouldReceive('has')->andReturn(true);
|
||||
$this->config->shouldReceive('get')->andReturn('');
|
||||
|
||||
$this->testee = new CreditCardGateway(
|
||||
$this->settingsRenderer,
|
||||
$this->orderProcessor,
|
||||
$this->config,
|
||||
$this->moduleUrl,
|
||||
$this->sessionHandler,
|
||||
$this->refundProcessor,
|
||||
$this->state,
|
||||
$this->transactionUrlProvider,
|
||||
$this->subscriptionHelper,
|
||||
$this->logger,
|
||||
$this->paymentsEndpoint,
|
||||
$this->vaultedCreditCardHandler
|
||||
);
|
||||
}
|
||||
|
||||
public function testProcessPayment()
|
||||
{
|
||||
$wc_order = Mockery::mock(WC_Order::class);
|
||||
when('wc_get_order')->justReturn($wc_order);
|
||||
|
||||
$this->orderProcessor->shouldReceive('process')
|
||||
->with($wc_order)
|
||||
->andReturn(true);
|
||||
$this->subscriptionHelper->shouldReceive('has_subscription')
|
||||
->andReturn(false);
|
||||
$this->sessionHandler->shouldReceive('destroy_session_data')->once();
|
||||
|
||||
$result = $this->testee->process_payment(1);
|
||||
$this->assertEquals('success', $result['result']);
|
||||
}
|
||||
|
||||
public function testProcessPaymentVaultedCard()
|
||||
{
|
||||
$wc_order = Mockery::mock(WC_Order::class);
|
||||
$wc_order->shouldReceive('get_customer_id')->andReturn(1);
|
||||
when('wc_get_order')->justReturn($wc_order);
|
||||
|
||||
$savedCreditCard = 'abc123';
|
||||
when('filter_input')->justReturn($savedCreditCard);
|
||||
|
||||
$this->vaultedCreditCardHandler
|
||||
->shouldReceive('handle_payment')
|
||||
->with($savedCreditCard, $wc_order)
|
||||
->andReturn($wc_order);
|
||||
|
||||
$this->sessionHandler->shouldReceive('destroy_session_data')->once();
|
||||
|
||||
$result = $this->testee->process_payment(1);
|
||||
$this->assertEquals('success', $result['result']);
|
||||
}
|
||||
}
|
141
tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php
Normal file
141
tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php
Normal file
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO;
|
||||
|
||||
use Mockery;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use function Brain\Monkey\Functions\when;
|
||||
|
||||
class OXXOGatewayTest extends TestCase
|
||||
{
|
||||
private $orderEndpoint;
|
||||
private $purchaseUnitFactory;
|
||||
private $shippingPreferenceFactory;
|
||||
private $logger;
|
||||
private $wcOrder;
|
||||
private $testee;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
$this->purchaseUnitFactory = Mockery::mock(PurchaseUnitFactory::class);
|
||||
$this->shippingPreferenceFactory = Mockery::mock(ShippingPreferenceFactory::class);
|
||||
$this->logger = Mockery::mock(LoggerInterface::class);
|
||||
|
||||
$this->wcOrder = Mockery::mock(WC_Order::class);
|
||||
when('wc_get_order')->justReturn($this->wcOrder);
|
||||
when('get_option')->justReturn([
|
||||
'title' => 'foo',
|
||||
'description' => 'bar',
|
||||
]);
|
||||
|
||||
$this->testee = new OXXOGateway(
|
||||
$this->orderEndpoint,
|
||||
$this->purchaseUnitFactory,
|
||||
$this->shippingPreferenceFactory,
|
||||
'oxxo.svg',
|
||||
$this->logger
|
||||
);
|
||||
}
|
||||
|
||||
public function testProcessPaymentSuccess()
|
||||
{
|
||||
$this->wcOrder->shouldReceive('get_billing_first_name')->andReturn('John');
|
||||
$this->wcOrder->shouldReceive('get_billing_last_name')->andReturn('Doe');
|
||||
$this->wcOrder->shouldReceive('get_billing_email')->andReturn('foo@bar.com');
|
||||
$this->wcOrder->shouldReceive('get_billing_country')->andReturn('MX');
|
||||
|
||||
list($purchaseUnit, $shippingPreference) = $this->setStubs();
|
||||
|
||||
$linkHref = 'https://sandbox.paypal.com/payment/oxxo?token=ABC123';
|
||||
$this->orderEndpoint
|
||||
->shouldReceive('confirm_payment_source')
|
||||
->with('1', [
|
||||
'oxxo' => [
|
||||
'name' => 'John Doe',
|
||||
'email' => 'foo@bar.com',
|
||||
'country_code' => 'MX',
|
||||
]
|
||||
]
|
||||
)->andReturn((object)[
|
||||
'links' => [
|
||||
(object)[
|
||||
'rel' => 'payer-action',
|
||||
'href' => $linkHref,
|
||||
],
|
||||
]
|
||||
]);
|
||||
|
||||
$order = Mockery::mock(Order::class);
|
||||
$order->shouldReceive('id')->andReturn('1');
|
||||
|
||||
$this->orderEndpoint
|
||||
->shouldReceive('create')
|
||||
->with([$purchaseUnit], $shippingPreference)
|
||||
->andReturn($order);
|
||||
|
||||
$this->wcOrder
|
||||
->shouldReceive('add_meta_data')
|
||||
->with('ppcp_oxxo_payer_action', $linkHref)
|
||||
->andReturn(true);
|
||||
$this->wcOrder->shouldReceive('save_meta_data');
|
||||
|
||||
$woocommerce = Mockery::mock(\WooCommerce::class);
|
||||
$cart = Mockery::mock(\WC_Cart::class);
|
||||
when('WC')->justReturn($woocommerce);
|
||||
$woocommerce->cart = $cart;
|
||||
$cart->shouldReceive('empty_cart');
|
||||
|
||||
$result = $this->testee->process_payment(1);
|
||||
$this->assertEquals('success', $result['result']);
|
||||
}
|
||||
|
||||
public function testProcessPaymentFailure()
|
||||
{
|
||||
list($purchaseUnit, $shippingPreference) = $this->setStubs();
|
||||
|
||||
$this->orderEndpoint
|
||||
->shouldReceive('create')
|
||||
->with([$purchaseUnit], $shippingPreference)
|
||||
->andThrows(RuntimeException::class);
|
||||
|
||||
$this->logger->shouldReceive('error');
|
||||
when('wc_add_notice')->justReturn();
|
||||
when('wc_get_checkout_url')->justReturn();
|
||||
$this->wcOrder->shouldReceive('update_status');
|
||||
|
||||
$result = $this->testee->process_payment(1);
|
||||
$this->assertEquals('failure', $result['result']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function setStubs(): array
|
||||
{
|
||||
$purchaseUnit = Mockery::mock(PurchaseUnit::class);
|
||||
$this->purchaseUnitFactory
|
||||
->shouldReceive('from_wc_order')
|
||||
->with($this->wcOrder)
|
||||
->andReturn($purchaseUnit);
|
||||
|
||||
$shippingPreference = 'SOME_SHIPPING_PREFERENCE';
|
||||
$this->shippingPreferenceFactory
|
||||
->shouldReceive('from_state')
|
||||
->with($purchaseUnit, 'checkout')
|
||||
->andReturn($shippingPreference);
|
||||
return array($purchaseUnit, $shippingPreference);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
|||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
||||
use function Brain\Monkey\Functions\when;
|
||||
|
||||
|
@ -26,6 +27,7 @@ class PayUponInvoiceGatewayTest extends TestCase
|
|||
private $logger;
|
||||
private $testee;
|
||||
private $pui_helper;
|
||||
private $checkout_helper;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
|
@ -38,6 +40,7 @@ class PayUponInvoiceGatewayTest extends TestCase
|
|||
$this->logger = Mockery::mock(LoggerInterface::class);
|
||||
$this->transaction_url_provider = Mockery::mock(TransactionUrlProvider::class);
|
||||
$this->pui_helper = Mockery::mock(PayUponInvoiceHelper::class);
|
||||
$this->checkout_helper = Mockery::mock(CheckoutHelper::class);
|
||||
|
||||
$this->setInitStubs();
|
||||
|
||||
|
@ -48,7 +51,8 @@ class PayUponInvoiceGatewayTest extends TestCase
|
|||
$this->environment,
|
||||
$this->transaction_url_provider,
|
||||
$this->logger,
|
||||
$this->pui_helper
|
||||
$this->pui_helper,
|
||||
$this->checkout_helper
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use Psr\Log\NullLogger;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
|
@ -36,7 +30,6 @@ class WcGatewayTest extends TestCase
|
|||
private $settingsRenderer;
|
||||
private $funding_source_renderer;
|
||||
private $orderProcessor;
|
||||
private $authorizedOrdersProcessor;
|
||||
private $settings;
|
||||
private $refundProcessor;
|
||||
private $onboardingState;
|
||||
|
@ -45,8 +38,6 @@ class WcGatewayTest extends TestCase
|
|||
private $environment;
|
||||
private $paymentTokenRepository;
|
||||
private $logger;
|
||||
private $paymentsEndpoint;
|
||||
private $orderEndpoint;
|
||||
private $apiShopCountry;
|
||||
|
||||
public function setUp(): void {
|
||||
|
@ -58,7 +49,6 @@ class WcGatewayTest extends TestCase
|
|||
|
||||
$this->settingsRenderer = Mockery::mock(SettingsRenderer::class);
|
||||
$this->orderProcessor = Mockery::mock(OrderProcessor::class);
|
||||
$this->authorizedOrdersProcessor = Mockery::mock(AuthorizedPaymentsProcessor::class);
|
||||
$this->settings = Mockery::mock(Settings::class);
|
||||
$this->sessionHandler = Mockery::mock(SessionHandler::class);
|
||||
$this->refundProcessor = Mockery::mock(RefundProcessor::class);
|
||||
|
@ -68,8 +58,6 @@ class WcGatewayTest extends TestCase
|
|||
$this->environment = Mockery::mock(Environment::class);
|
||||
$this->paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$this->logger = Mockery::mock(LoggerInterface::class);
|
||||
$this->paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$this->orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
$this->funding_source_renderer = new FundingSourceRenderer($this->settings);
|
||||
$this->apiShopCountry = 'DE';
|
||||
|
||||
|
@ -84,6 +72,7 @@ class WcGatewayTest extends TestCase
|
|||
$this->settings->shouldReceive('has')->andReturnFalse();
|
||||
|
||||
$this->logger->shouldReceive('info');
|
||||
$this->logger->shouldReceive('error');
|
||||
}
|
||||
|
||||
private function createGateway()
|
||||
|
@ -92,7 +81,6 @@ class WcGatewayTest extends TestCase
|
|||
$this->settingsRenderer,
|
||||
$this->funding_source_renderer,
|
||||
$this->orderProcessor,
|
||||
$this->authorizedOrdersProcessor,
|
||||
$this->settings,
|
||||
$this->sessionHandler,
|
||||
$this->refundProcessor,
|
||||
|
@ -103,8 +91,6 @@ class WcGatewayTest extends TestCase
|
|||
$this->environment,
|
||||
$this->paymentTokenRepository,
|
||||
$this->logger,
|
||||
$this->paymentsEndpoint,
|
||||
$this->orderEndpoint,
|
||||
$this->apiShopCountry
|
||||
);
|
||||
}
|
||||
|
@ -169,8 +155,10 @@ class WcGatewayTest extends TestCase
|
|||
when('wc_get_checkout_url')
|
||||
->justReturn($redirectUrl);
|
||||
|
||||
expect('wc_add_notice')
|
||||
->with('Couldn\'t find order to process','error');
|
||||
$this->sessionHandler
|
||||
->shouldReceive('destroy_session_data');
|
||||
|
||||
expect('wc_add_notice');
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
|
@ -191,7 +179,6 @@ class WcGatewayTest extends TestCase
|
|||
->andReturnFalse();
|
||||
$this->orderProcessor
|
||||
->expects('last_error')
|
||||
->twice()
|
||||
->andReturn($lastError);
|
||||
$this->subscriptionHelper->shouldReceive('has_subscription')->with($orderId)->andReturn(true);
|
||||
$this->subscriptionHelper->shouldReceive('is_subscription_change_payment')->andReturn(true);
|
||||
|
@ -202,6 +189,8 @@ class WcGatewayTest extends TestCase
|
|||
expect('wc_get_order')
|
||||
->with($orderId)
|
||||
->andReturn($wcOrder);
|
||||
$this->sessionHandler
|
||||
->shouldReceive('destroy_session_data');
|
||||
expect('wc_add_notice')
|
||||
->with($lastError, 'error');
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
|
||||
use DateTime;
|
||||
use Mockery;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
|
||||
class PayUponInvoiceHelperTest extends TestCase
|
||||
|
@ -13,7 +14,7 @@ class PayUponInvoiceHelperTest extends TestCase
|
|||
*/
|
||||
public function testValidateBirthDate($input, $output)
|
||||
{
|
||||
$this->assertSame((new PayUponInvoiceHelper())->validate_birth_date($input), $output);
|
||||
$this->assertSame((new CheckoutHelper())->validate_birth_date($input), $output);
|
||||
}
|
||||
|
||||
public function datesProvider(): array{
|
||||
|
@ -26,6 +27,7 @@ class PayUponInvoiceHelperTest extends TestCase
|
|||
['1942-02-31', false],
|
||||
['01-01-1942', false],
|
||||
['1942-01-01', true],
|
||||
['0001-01-01', false],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
|
||||
|
||||
|
||||
use Mockery\MockInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
use WC_Order;
|
||||
|
@ -26,7 +27,11 @@ use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
|||
|
||||
class AuthorizedPaymentsProcessorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var WC_Order&MockInterface
|
||||
*/
|
||||
private $wcOrder;
|
||||
|
||||
private $paypalOrderId = 'abc';
|
||||
private $authorizationId = 'qwe';
|
||||
private $amount = 42.0;
|
||||
|
@ -37,7 +42,7 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
|||
private $paymentsEndpoint;
|
||||
private $notice;
|
||||
private $config;
|
||||
private $subscription_helperauthorization;
|
||||
private $captureId = '123qwe';
|
||||
private $testee;
|
||||
|
||||
public function setUp(): void {
|
||||
|
@ -79,7 +84,7 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
|||
$this->paymentsEndpoint
|
||||
->expects('capture')
|
||||
->with($this->authorizationId, equalTo(new Money($this->amount, $this->currency)))
|
||||
->andReturn($this->createCapture(CaptureStatus::COMPLETED));
|
||||
->andReturn($this->createCapture($this->captureId, CaptureStatus::COMPLETED));
|
||||
|
||||
$this->assertEquals(AuthorizedPaymentsProcessor::SUCCESSFUL, $this->testee->process($this->wcOrder));
|
||||
}
|
||||
|
@ -99,7 +104,7 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
|||
$this->paymentsEndpoint
|
||||
->expects('capture')
|
||||
->with($authorizations[2]->id(), equalTo(new Money($this->amount, $this->currency)))
|
||||
->andReturn($this->createCapture(CaptureStatus::COMPLETED));
|
||||
->andReturn($this->createCapture($this->captureId, CaptureStatus::COMPLETED));
|
||||
|
||||
$this->assertEquals(AuthorizedPaymentsProcessor::SUCCESSFUL, $this->testee->process($this->wcOrder));
|
||||
}
|
||||
|
@ -150,12 +155,13 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
|||
$this->paymentsEndpoint
|
||||
->expects('capture')
|
||||
->with($this->authorizationId, equalTo(new Money($this->amount, $this->currency)))
|
||||
->andReturn($this->createCapture(CaptureStatus::COMPLETED));
|
||||
->andReturn($this->createCapture($this->captureId, CaptureStatus::COMPLETED));
|
||||
|
||||
$this->wcOrder->shouldReceive('payment_complete')->andReturn(true);
|
||||
$this->wcOrder->expects('add_order_note');
|
||||
$this->wcOrder->expects('add_order_note')->twice();
|
||||
$this->wcOrder->expects('update_meta_data');
|
||||
$this->wcOrder->expects('save');
|
||||
$this->wcOrder->expects('set_transaction_id')->with($this->captureId);
|
||||
$this->wcOrder->shouldReceive('save')->atLeast()->times(1);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->testee->capture_authorized_payment($this->wcOrder)
|
||||
|
@ -248,8 +254,11 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
|||
return new Authorization($id, new AuthorizationStatus($status));
|
||||
}
|
||||
|
||||
private function createCapture(string $status): Capture {
|
||||
private function createCapture(string $id, string $status): Capture {
|
||||
$capture = Mockery::mock(Capture::class);
|
||||
$capture
|
||||
->shouldReceive('id')
|
||||
->andReturn($id);
|
||||
$capture
|
||||
->shouldReceive('status')
|
||||
->andReturn(new CaptureStatus($status));
|
||||
|
|
|
@ -68,8 +68,6 @@ class PurchaseUnitTest extends TestCase
|
|||
$pu = $this->puFactory->from_wc_order($wcOrder);
|
||||
$puData = $pu->to_array();
|
||||
|
||||
self::assertTrue(isset($puData['amount']['breakdown']));
|
||||
|
||||
self::assertEquals($expectedAmount, $puData['amount']);
|
||||
}
|
||||
|
||||
|
@ -83,8 +81,6 @@ class PurchaseUnitTest extends TestCase
|
|||
$pu = $this->puFactory->from_wc_cart($this->cart);
|
||||
$puData = $pu->to_array();
|
||||
|
||||
self::assertTrue(isset($puData['amount']['breakdown']));
|
||||
|
||||
self::assertEquals($expectedAmount, $puData['amount']);
|
||||
}
|
||||
|
||||
|
@ -334,6 +330,37 @@ class PurchaseUnitTest extends TestCase
|
|||
],
|
||||
]),
|
||||
];
|
||||
|
||||
yield 'no decimals currency' => [
|
||||
[
|
||||
'currency' => 'JPY',
|
||||
'items' => [
|
||||
['price' => 18.0, 'quantity' => 2],
|
||||
],
|
||||
'shipping' => ['total' => 5.0],
|
||||
'billing' => ['city' => 'city2'],
|
||||
],
|
||||
self::adaptAmountFormat([
|
||||
'value' => 66,
|
||||
'breakdown' => [
|
||||
'item_total' => 36,
|
||||
'tax_total' => 25, // 24.60
|
||||
'shipping' => 5,
|
||||
],
|
||||
], 'JPY'),
|
||||
];
|
||||
|
||||
yield [
|
||||
[
|
||||
'items' => [
|
||||
['price' => 5.345, 'quantity' => 2],
|
||||
],
|
||||
'billing' => ['city' => 'city0'],
|
||||
],
|
||||
self::adaptAmountFormat([
|
||||
'value' => 10.69,
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
public function cartData() {
|
||||
|
@ -390,6 +417,18 @@ class PurchaseUnitTest extends TestCase
|
|||
],
|
||||
], get_woocommerce_currency()),
|
||||
];
|
||||
|
||||
yield [
|
||||
[
|
||||
'products' => [
|
||||
['price' => 5.345, 'quantity' => 2],
|
||||
],
|
||||
'billing' => ['city' => 'city0'],
|
||||
],
|
||||
self::adaptAmountFormat([
|
||||
'value' => 10.69,
|
||||
], get_woocommerce_currency()),
|
||||
];
|
||||
}
|
||||
|
||||
private static function adaptAmountFormat(array $data, string $currency = null): array {
|
||||
|
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||
class WC_Payment_Gateway
|
||||
{
|
||||
|
||||
protected function get_option(string $key) : string {
|
||||
public function get_option(string $key, $empty_value = null) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
@ -19,4 +19,4 @@ class WC_Payment_Gateway
|
|||
public function process_admin_options() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,10 @@ declare(strict_types=1);
|
|||
|
||||
class WC_Payment_Gateway_CC
|
||||
{
|
||||
public function init_settings() {}
|
||||
public function process_admin_options() {}
|
||||
|
||||
protected function get_return_url($wcOrder) {
|
||||
return $wcOrder;
|
||||
}
|
||||
}
|
||||
|
|
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