mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
Merge branch 'trunk' into PCP-808-1-9-1-test-1-improve-pui-gateway-availability-on-pay-for-order-page-with-unsupported-currency
This commit is contained in:
commit
cf1384f5bd
10 changed files with 92 additions and 34 deletions
26
.github/workflows/package.yml
vendored
26
.github/workflows/package.yml
vendored
|
@ -4,7 +4,11 @@ on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
packageVersion:
|
packageVersion:
|
||||||
description: 'Package Version'
|
description: 'Package version'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
filePrefix:
|
||||||
|
description: 'File prefix'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
@ -12,6 +16,10 @@ jobs:
|
||||||
package:
|
package:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
PACKAGE_VERSION: ${{ github.event.inputs.packageVersion }}
|
||||||
|
FILENAME: woocommerce-paypal-payments
|
||||||
|
|
||||||
name: Build package
|
name: Build package
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
@ -22,11 +30,13 @@ jobs:
|
||||||
php-version: 7.1
|
php-version: 7.1
|
||||||
tools: composer:v1
|
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
|
- name: Set plugin version header
|
||||||
env:
|
|
||||||
PACKAGE_VERSION: ${{ github.event.inputs.packageVersion }}
|
|
||||||
run: 'sed -Ei "s/Version: .*/Version: ${PACKAGE_VERSION}/g" woocommerce-paypal-payments.php'
|
run: 'sed -Ei "s/Version: .*/Version: ${PACKAGE_VERSION}/g" woocommerce-paypal-payments.php'
|
||||||
if: github.event.inputs.packageVersion
|
if: env.PACKAGE_VERSION
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: yarn build
|
run: yarn build
|
||||||
|
@ -34,8 +44,14 @@ jobs:
|
||||||
- name: Unzip # GH currently always zips, so if we upload a zip we get a zip inside a zip
|
- 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
|
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
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: woocommerce-paypal-payments
|
name: ${{ env.FILENAME }}
|
||||||
path: dist/
|
path: dist/
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
*** Changelog ***
|
*** Changelog ***
|
||||||
|
|
||||||
= 1.9.2 - TBD =
|
= 1.9.2 - 2022-08-09 =
|
||||||
* Fix - Do not allow birth date older than 100 years for PUI. #743
|
* 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 - 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 - Capture Virtual-Only Orders setting did not auto-capture subscription renewal payments. #626
|
||||||
|
|
|
@ -333,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>';
|
echo '</div><div>';
|
||||||
|
|
||||||
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
||||||
|
@ -376,6 +393,9 @@ class PayUponInvoice {
|
||||||
}
|
}
|
||||||
|
|
||||||
$national_number = filter_input( INPUT_POST, 'billing_phone', FILTER_SANITIZE_STRING );
|
$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 ) {
|
if ( $national_number ) {
|
||||||
$numeric_phone_number = preg_replace( '/[^0-9]/', '', $national_number );
|
$numeric_phone_number = preg_replace( '/[^0-9]/', '', $national_number );
|
||||||
if ( $numeric_phone_number && ! preg_match( '/^[0-9]{1,14}?$/', $numeric_phone_number ) ) {
|
if ( $numeric_phone_number && ! preg_match( '/^[0-9]{1,14}?$/', $numeric_phone_number ) ) {
|
||||||
|
|
|
@ -215,6 +215,12 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$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' ) );
|
$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 );
|
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||||
$payment_source = $this->payment_source_factory->from_wc_order( $wc_order, $birth_date );
|
$payment_source = $this->payment_source_factory->from_wc_order( $wc_order, $birth_date );
|
||||||
|
|
|
@ -24,8 +24,8 @@ class PaymentSourceFactory {
|
||||||
* @return PaymentSource
|
* @return PaymentSource
|
||||||
*/
|
*/
|
||||||
public function from_wc_order( WC_Order $order, string $birth_date ) {
|
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 = 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;
|
$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 ) {
|
if ( is_string( $phone_country_code ) && '' !== $phone_country_code ) {
|
||||||
|
@ -44,7 +44,7 @@ class PaymentSourceFactory {
|
||||||
$address['last_name'] ?? '',
|
$address['last_name'] ?? '',
|
||||||
$address['email'] ?? '',
|
$address['email'] ?? '',
|
||||||
$birth_date,
|
$birth_date,
|
||||||
preg_replace( '/[^0-9]/', '', $address['phone'] ) ?? '',
|
preg_replace( '/[^0-9]/', '', $phone ) ?? '',
|
||||||
$phone_country_code,
|
$phone_country_code,
|
||||||
$address['address_1'] ?? '',
|
$address['address_1'] ?? '',
|
||||||
$address['city'] ?? '',
|
$address['city'] ?? '',
|
||||||
|
|
|
@ -118,7 +118,7 @@ trait ProcessPaymentTrait {
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function format_exception( Throwable $exception ): string {
|
protected function format_exception( Throwable $exception ): string {
|
||||||
$output = $exception->getMessage() . ' ' . $exception->getFile() . ':' . $exception->getLine();
|
$output = $exception->getMessage() . ' ' . basename( $exception->getFile() ) . ':' . $exception->getLine();
|
||||||
$prev = $exception->getPrevious();
|
$prev = $exception->getPrevious();
|
||||||
if ( ! $prev ) {
|
if ( ! $prev ) {
|
||||||
return $output;
|
return $output;
|
||||||
|
|
|
@ -31,7 +31,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
||||||
*/
|
*/
|
||||||
class AuthorizedPaymentsProcessor {
|
class AuthorizedPaymentsProcessor {
|
||||||
|
|
||||||
use PaymentsStatusHandlingTrait;
|
use PaymentsStatusHandlingTrait, TransactionIdHandlingTrait;
|
||||||
|
|
||||||
const SUCCESSFUL = 'SUCCESSFUL';
|
const SUCCESSFUL = 'SUCCESSFUL';
|
||||||
const ALREADY_CAPTURED = 'ALREADY_CAPTURED';
|
const ALREADY_CAPTURED = 'ALREADY_CAPTURED';
|
||||||
|
@ -200,6 +200,9 @@ class AuthorizedPaymentsProcessor {
|
||||||
|
|
||||||
$this->handle_capture_status( $capture, $wc_order );
|
$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 ( self::SUCCESSFUL === $result_status ) {
|
||||||
if ( $capture->status()->is( CaptureStatus::COMPLETED ) ) {
|
if ( $capture->status()->is( CaptureStatus::COMPLETED ) ) {
|
||||||
$wc_order->add_order_note(
|
$wc_order->add_order_note(
|
||||||
|
|
|
@ -56,14 +56,12 @@ class SectionsRenderer {
|
||||||
/**
|
/**
|
||||||
* Renders the Sections tab.
|
* Renders the Sections tab.
|
||||||
*/
|
*/
|
||||||
public function render(): void {
|
public function render(): string {
|
||||||
if ( ! $this->should_render() ) {
|
if ( ! $this->should_render() ) {
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '<ul class="subsubsub">';
|
$html = '<nav class="nav-tab-wrapper woo-nav-tab-wrapper">';
|
||||||
|
|
||||||
$array_keys = array_keys( $this->sections );
|
|
||||||
|
|
||||||
foreach ( $this->sections as $id => $label ) {
|
foreach ( $this->sections as $id => $label ) {
|
||||||
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=' . $id );
|
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=' . $id );
|
||||||
|
@ -73,9 +71,11 @@ class SectionsRenderer {
|
||||||
// Other gateways render fields differently, and their pages are not expected to work when gateway is not available.
|
// 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 );
|
$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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,13 +66,12 @@ class WCGatewayModule implements ModuleInterface {
|
||||||
'woocommerce_sections_checkout',
|
'woocommerce_sections_checkout',
|
||||||
function() use ( $c ) {
|
function() use ( $c ) {
|
||||||
$section_renderer = $c->get( 'wcgateway.settings.sections-renderer' );
|
$section_renderer = $c->get( 'wcgateway.settings.sections-renderer' );
|
||||||
/**
|
assert( $section_renderer instanceof SectionsRenderer );
|
||||||
* The Section Renderer.
|
|
||||||
*
|
// phpcs:ignore WordPress.Security.EscapeOutput
|
||||||
* @var SectionsRenderer $section_renderer
|
echo $section_renderer->render();
|
||||||
*/
|
},
|
||||||
$section_renderer->render();
|
20
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
add_action(
|
add_action(
|
||||||
|
@ -292,7 +291,12 @@ class WCGatewayModule implements ModuleInterface {
|
||||||
add_filter(
|
add_filter(
|
||||||
'woocommerce_payment_gateways',
|
'woocommerce_payment_gateways',
|
||||||
static function ( $methods ) use ( $container ): array {
|
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' );
|
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -304,7 +308,7 @@ class WCGatewayModule implements ModuleInterface {
|
||||||
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
|
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $container->get( 'wcgateway.settings.allow_card_button_gateway' ) ) {
|
if ( $paypal_gateway_enabled && $container->get( 'wcgateway.settings.allow_card_button_gateway' ) ) {
|
||||||
$methods[] = $container->get( 'wcgateway.card-button-gateway' );
|
$methods[] = $container->get( 'wcgateway.card-button-gateway' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
|
namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
|
||||||
|
|
||||||
|
|
||||||
|
use Mockery\MockInterface;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
use Psr\Log\NullLogger;
|
use Psr\Log\NullLogger;
|
||||||
use WC_Order;
|
use WC_Order;
|
||||||
|
@ -26,7 +27,11 @@ use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
||||||
|
|
||||||
class AuthorizedPaymentsProcessorTest extends TestCase
|
class AuthorizedPaymentsProcessorTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var WC_Order&MockInterface
|
||||||
|
*/
|
||||||
private $wcOrder;
|
private $wcOrder;
|
||||||
|
|
||||||
private $paypalOrderId = 'abc';
|
private $paypalOrderId = 'abc';
|
||||||
private $authorizationId = 'qwe';
|
private $authorizationId = 'qwe';
|
||||||
private $amount = 42.0;
|
private $amount = 42.0;
|
||||||
|
@ -37,7 +42,7 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
||||||
private $paymentsEndpoint;
|
private $paymentsEndpoint;
|
||||||
private $notice;
|
private $notice;
|
||||||
private $config;
|
private $config;
|
||||||
private $subscription_helperauthorization;
|
private $captureId = '123qwe';
|
||||||
private $testee;
|
private $testee;
|
||||||
|
|
||||||
public function setUp(): void {
|
public function setUp(): void {
|
||||||
|
@ -79,7 +84,7 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
||||||
$this->paymentsEndpoint
|
$this->paymentsEndpoint
|
||||||
->expects('capture')
|
->expects('capture')
|
||||||
->with($this->authorizationId, equalTo(new Money($this->amount, $this->currency)))
|
->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));
|
$this->assertEquals(AuthorizedPaymentsProcessor::SUCCESSFUL, $this->testee->process($this->wcOrder));
|
||||||
}
|
}
|
||||||
|
@ -99,7 +104,7 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
||||||
$this->paymentsEndpoint
|
$this->paymentsEndpoint
|
||||||
->expects('capture')
|
->expects('capture')
|
||||||
->with($authorizations[2]->id(), equalTo(new Money($this->amount, $this->currency)))
|
->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));
|
$this->assertEquals(AuthorizedPaymentsProcessor::SUCCESSFUL, $this->testee->process($this->wcOrder));
|
||||||
}
|
}
|
||||||
|
@ -150,12 +155,13 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
||||||
$this->paymentsEndpoint
|
$this->paymentsEndpoint
|
||||||
->expects('capture')
|
->expects('capture')
|
||||||
->with($this->authorizationId, equalTo(new Money($this->amount, $this->currency)))
|
->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->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('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->assertTrue(
|
||||||
$this->testee->capture_authorized_payment($this->wcOrder)
|
$this->testee->capture_authorized_payment($this->wcOrder)
|
||||||
|
@ -248,8 +254,11 @@ class AuthorizedPaymentsProcessorTest extends TestCase
|
||||||
return new Authorization($id, new AuthorizationStatus($status));
|
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 = Mockery::mock(Capture::class);
|
||||||
|
$capture
|
||||||
|
->shouldReceive('id')
|
||||||
|
->andReturn($id);
|
||||||
$capture
|
$capture
|
||||||
->shouldReceive('status')
|
->shouldReceive('status')
|
||||||
->andReturn(new CaptureStatus($status));
|
->andReturn(new CaptureStatus($status));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue