Fix merge conflict

This commit is contained in:
dinamiko 2022-09-14 12:22:46 +02:00
commit e4e968a823
57 changed files with 6080 additions and 1624 deletions

View file

@ -12,8 +12,16 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
use Psr\Log\LoggerInterface;
use RuntimeException;
use stdClass;
use WC_Customer;
use WC_Order;
use WC_Order_Item_Fee;
use WC_Order_Item_Product;
use WC_Product;
use WC_Tax;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\RequestTrait;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
@ -92,18 +100,19 @@ class PayUponInvoiceOrderEndpoint {
*
* @param PurchaseUnit[] $items The purchase unit items for the order.
* @param PaymentSource $payment_source The payment source.
* @param WC_Order $wc_order The WC order.
* @return Order
* @throws RuntimeException When there is a problem with the payment source.
* @throws PayPalApiException When there is a problem creating the order.
*/
public function create( array $items, PaymentSource $payment_source ): Order {
public function create( array $items, PaymentSource $payment_source, WC_Order $wc_order ): Order {
$data = array(
'intent' => 'CAPTURE',
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
'purchase_units' => array_map(
static function ( PurchaseUnit $item ): array {
return $item->to_array();
return $item->to_array( false );
},
$items
),
@ -112,8 +121,7 @@ class PayUponInvoiceOrderEndpoint {
),
);
$data = $this->ensure_tax( $data );
$data = $this->ensure_tax_rate( $data );
$data = $this->ensure_taxes( $wc_order, $data );
$data = $this->ensure_shipping( $data, $payment_source->to_array() );
$bearer = $this->bearer->bearer();
@ -195,45 +203,6 @@ class PayUponInvoiceOrderEndpoint {
return $json;
}
/**
* Ensures items contains tax.
*
* @param array $data The data.
* @return array
*/
private function ensure_tax( array $data ): array {
$items_count = count( $data['purchase_units'][0]['items'] );
for ( $i = 0; $i < $items_count; $i++ ) {
if ( ! isset( $data['purchase_units'][0]['items'][ $i ]['tax'] ) ) {
$data['purchase_units'][0]['items'][ $i ]['tax'] = array(
'currency_code' => 'EUR',
'value' => '0.00',
);
}
}
return $data;
}
/**
* Ensures items contains tax rate.
*
* @param array $data The data.
* @return array
*/
private function ensure_tax_rate( array $data ): array {
$items_count = count( $data['purchase_units'][0]['items'] );
for ( $i = 0; $i < $items_count; $i++ ) {
if ( ! isset( $data['purchase_units'][0]['items'][ $i ]['tax_rate'] ) ) {
$data['purchase_units'][0]['items'][ $i ]['tax_rate'] = '0.00';
}
}
return $data;
}
/**
* Ensures purchase units contains shipping by using payment source data.
*
@ -255,4 +224,51 @@ class PayUponInvoiceOrderEndpoint {
return $data;
}
/**
* Ensure items contains taxes.
*
* @param WC_Order $wc_order The WC order.
* @param array $data The data.
* @return array
*/
private function ensure_taxes( WC_Order $wc_order, array $data ): array {
$tax_total = $data['purchase_units'][0]['amount']['breakdown']['tax_total']['value'];
$item_total = $data['purchase_units'][0]['amount']['breakdown']['item_total']['value'];
$shipping = $data['purchase_units'][0]['amount']['breakdown']['shipping']['value'];
$order_tax_total = $wc_order->get_total_tax();
$tax_rate = round( ( $order_tax_total / $item_total ) * 100, 1 );
$item_name = $data['purchase_units'][0]['items'][0]['name'];
$item_currency = $data['purchase_units'][0]['items'][0]['unit_amount']['currency_code'];
$item_description = $data['purchase_units'][0]['items'][0]['description'];
$item_sku = $data['purchase_units'][0]['items'][0]['sku'];
unset( $data['purchase_units'][0]['items'] );
$data['purchase_units'][0]['items'][0] = array(
'name' => $item_name,
'unit_amount' => array(
'currency_code' => $item_currency,
'value' => $item_total,
),
'quantity' => 1,
'description' => $item_description,
'sku' => $item_sku,
'category' => 'PHYSICAL_GOODS',
'tax' => array(
'currency_code' => 'EUR',
'value' => $tax_total,
),
'tax_rate' => number_format( $tax_rate, 2, '.', '' ),
);
$total_amount = $data['purchase_units'][0]['amount']['value'];
$breakdown_total = $item_total + $tax_total + $shipping;
$diff = round( $total_amount - $breakdown_total, 2 );
if ( $diff === -0.01 || $diff === 0.01 ) {
$data['purchase_units'][0]['amount']['value'] = number_format( $breakdown_total, 2, '.', '' );
}
return $data;
}
}

View file

@ -268,9 +268,11 @@ class PurchaseUnit {
/**
* Returns the object as array.
*
* @param bool $ditch_items_when_mismatch Whether ditch items when mismatch or not.
*
* @return array
*/
public function to_array(): array {
public function to_array( bool $ditch_items_when_mismatch = true ): array {
$purchase_unit = array(
'reference_id' => $this->reference_id(),
'amount' => $this->amount()->to_array(),
@ -282,7 +284,7 @@ class PurchaseUnit {
$this->items()
),
);
if ( $this->ditch_items_when_mismatch( $this->amount(), ...$this->items() ) ) {
if ( $ditch_items_when_mismatch && $this->ditch_items_when_mismatch( $this->amount(), ...$this->items() ) ) {
unset( $purchase_unit['items'] );
unset( $purchase_unit['amount']['breakdown'] );
}

View file

@ -140,4 +140,24 @@ class Token {
}
return true;
}
/**
* Checks if tracking is available in access token scope.
*
* @return bool Whether tracking features are enabled or not.
*/
public function is_tracking_available(): bool {
if ( ! isset( $this->json->scope ) ) {
return false;
}
if ( strpos(
$this->json->scope,
'https://uri.paypal.com/services/shipping/trackers/readwrite'
) !== false ) {
return true;
}
return false;
}
}

View file

@ -77,6 +77,18 @@ class DccApplies {
return $applies;
}
/**
* Returns whether WooCommerce Payments plugin is available for the store country.
*
* @return bool
*/
public function for_wc_payments(): bool {
$countries = array_keys( $this->allowed_country_currency_matrix );
array_push( $countries, 'AT', 'BE', 'HK', 'IE', 'NL', 'PL', 'PT', 'SG', 'CH' );
return in_array( $this->country, $countries, true );
}
/**
* Returns credit cards, which can be used.
*

View file

@ -1,5 +0,0 @@
{
"plugins": [
"babel-plugin-transform-object-rest-spread"
]
}

View file

@ -7,16 +7,15 @@
"deepmerge": "^4.2.2"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"babel-loader": "^8.1.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"@babel/core": "^7.19",
"@babel/preset-env": "^7.19",
"babel-loader": "^8.2",
"cross-env": "^7.0.3",
"file-loader": "^6.2.0",
"sass": "^1.42.1",
"sass-loader": "^12.1.0",
"webpack": "^5.55.0",
"webpack-cli": "^4.8.0"
"webpack": "^5.74",
"webpack-cli": "^4.10"
},
"scripts": {
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",

View file

@ -66,7 +66,7 @@ const bootstrap = () => {
errorHandler.clear();
if (messages.length) {
messages.forEach(s => errorHandler.message(s));
errorHandler.messages(messages);
} else {
errorHandler.message(PayPalCommerceGateway.labels.error.required.generic);
}

View file

@ -17,21 +17,48 @@ class ErrorHandler {
appendPreparedErrorMessageElement(errorMessageElement)
{
if(this.messagesList === null) {
this.prepareMessagesList();
if (this.messagesList === null) {
this._prepareMessagesList();
}
this.messagesList.replaceWith(errorMessageElement);
}
/**
* @param {String} text
* @param {Boolean} persist
*/
message(text, persist = false)
{
if(! typeof String || text.length === 0){
this._addMessage(text, persist);
this._scrollToMessages();
}
/**
* @param {Array} texts
* @param {Boolean} persist
*/
messages(texts, persist = false)
{
texts.forEach(t => this._addMessage(t, persist));
this._scrollToMessages();
}
/**
* @private
* @param {String} text
* @param {Boolean} persist
*/
_addMessage(text, persist = false)
{
if(! typeof String || text.length === 0) {
throw new Error('A new message text must be a non-empty string.');
}
if(this.messagesList === null){
this.prepareMessagesList();
if (this.messagesList === null){
this._prepareMessagesList();
}
if (persist) {
@ -40,15 +67,24 @@ class ErrorHandler {
this.wrapper.classList.remove('ppcp-persist');
}
let messageNode = this.prepareMessagesListItem(text);
let messageNode = this._prepareMessagesListItem(text);
this.messagesList.appendChild(messageNode);
jQuery.scroll_to_notices(jQuery('.woocommerce-notices-wrapper'))
}
prepareMessagesList()
/**
* @private
*/
_scrollToMessages()
{
if(this.messagesList === null){
jQuery.scroll_to_notices(jQuery('.woocommerce-notices-wrapper'));
}
/**
* @private
*/
_prepareMessagesList()
{
if (this.messagesList === null) {
this.messagesList = document.createElement('ul');
this.messagesList.setAttribute('class', 'woocommerce-error');
this.messagesList.setAttribute('role', 'alert');
@ -56,7 +92,10 @@ class ErrorHandler {
}
}
prepareMessagesListItem(message)
/**
* @private
*/
_prepareMessagesListItem(message)
{
const li = document.createElement('li');
li.innerHTML = message;
@ -64,13 +103,6 @@ class ErrorHandler {
return li;
}
sanitize(text)
{
const textarea = document.createElement('textarea');
textarea.innerHTML = text;
return textarea.value.replace('Error: ', '');
}
clear()
{
if (this.messagesList === null) {

View file

@ -233,14 +233,18 @@ class CreateOrderEndpoint implements EndpointInterface {
$this->set_bn_code( $data );
if ( 'checkout' === $data['context'] ) {
try {
$order = $this->create_paypal_order( $wc_order );
} catch ( Exception $exception ) {
$this->logger->error( 'Order creation failed: ' . $exception->getMessage() );
throw $exception;
}
if ( 'pay-now' === $data['context'] && get_option( 'woocommerce_terms_page_id', '' ) !== '' ) {
$this->validate_paynow_form( $data['form'] );
}
try {
$order = $this->create_paypal_order( $wc_order );
} catch ( Exception $exception ) {
$this->logger->error( 'Order creation failed: ' . $exception->getMessage() );
throw $exception;
}
if ( 'checkout' === $data['context'] ) {
if (
! $this->early_order_handler->should_create_early_order()
|| $this->registration_needed
@ -251,12 +255,6 @@ class CreateOrderEndpoint implements EndpointInterface {
$this->early_order_handler->register_for_order( $order );
}
if ( 'pay-now' === $data['context'] && get_option( 'woocommerce_terms_page_id', '' ) !== '' ) {
$this->validate_paynow_form( $data['form'] );
}
$order = $this->create_paypal_order( $wc_order );
if ( 'pay-now' === $data['context'] && is_a( $wc_order, \WC_Order::class ) ) {
$wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() );
$wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() );

File diff suppressed because it is too large Load diff

View file

@ -32,10 +32,22 @@ return array(
return new PPEC\SubscriptionsHandler( $ppcp_renewal_handler, $gateway );
},
'compat.ppec.settings_importer' => static function( $container ) : PPEC\SettingsImporter {
'compat.ppec.settings_importer' => static function( ContainerInterface $container ) : PPEC\SettingsImporter {
$settings = $container->get( 'wcgateway.settings' );
return new PPEC\SettingsImporter( $settings );
},
'compat.plugin-script-names' => static function( ContainerInterface $container ) : array {
return array(
'ppcp-smart-button',
'ppcp-oxxo',
'ppcp-pay-upon-invoice',
'ppcp-vaulting-myaccount-payments',
'ppcp-gateway-settings',
'ppcp-webhooks-status-page',
'ppcp-tracking',
);
},
);

View file

@ -33,12 +33,11 @@ class CompatModule implements ModuleInterface {
}
/**
* Run the compatibility module.
*
* @param ContainerInterface|null $c The Container.
* {@inheritDoc}
*/
public function run( ContainerInterface $c ): void {
$this->initialize_ppec_compat_layer( $c );
$this->fix_site_ground_optimizer_compatibility( $c );
}
/**
@ -52,10 +51,10 @@ class CompatModule implements ModuleInterface {
/**
* Sets up the PayPal Express Checkout compatibility layer.
*
* @param ContainerInterface|null $container The Container.
* @param ContainerInterface $container The Container.
* @return void
*/
private function initialize_ppec_compat_layer( $container ): void {
private function initialize_ppec_compat_layer( ContainerInterface $container ): void {
// Process PPEC subscription renewals through PayPal Payments.
$handler = $container->get( 'compat.ppec.subscriptions-handler' );
$handler->maybe_hook();
@ -76,4 +75,20 @@ class CompatModule implements ModuleInterface {
}
/**
* Fixes the compatibility issue for <a href="https://wordpress.org/plugins/sg-cachepress/">SiteGround Optimizer plugin</a>.
*
* @link https://wordpress.org/plugins/sg-cachepress/
*
* @param ContainerInterface $c The Container.
*/
protected function fix_site_ground_optimizer_compatibility( ContainerInterface $c ): void {
$ppcp_script_names = $c->get( 'compat.plugin-script-names' );
add_filter(
'sgo_js_minify_exclude',
function ( array $scripts ) use ( $ppcp_script_names ) {
return array_merge( $scripts, $ppcp_script_names );
}
);
}
}

View file

@ -55,6 +55,7 @@ ul.ppcp-onboarding-options, ul.ppcp-onboarding-options-sublist {
ul.ppcp-onboarding-options-sublist {
margin-left: 15px;
margin-top: 15px;
}
.ppcp-muted-text {
@ -168,3 +169,53 @@ ul.ppcp-onboarding-options-sublist {
height: 23px;
}
}
.ppcp-settings-page-header {
display: flex;
align-items: center;
max-width: 1200px;
margin-top: 10px;
}
.ppcp-settings-page-header img {
height: 30px;
}
.ppcp-settings-page-header h4 {
margin: 0 15px 0 5px;
}
.ppcp-settings-page-header .button, .ppcp-settings-page-header a {
margin: 0 5px;
}
.ppcp-right-align {
margin-left: auto;
}
.ppcp-settings-page-header a {
text-decoration: none;
}
@media (max-width: 1200px) {
.ppcp-settings-page-header {
display: block;
}
.ppcp-settings-page-header .ppcp-right-align {
display: block;
margin-left: 0;
}
.ppcp-settings-page-header .button, .ppcp-settings-page-header a {
margin: 5px 10px 5px 0;
}
.ppcp-settings-page-header .ppcp-inline-only {
display: none;
}
.ppcp-settings-page-header h4 {
margin-left: 0;
}
}

View file

@ -158,6 +158,8 @@ function ppcp_onboarding_productionCallback(...args) {
input.disabled = !cardsChk.checked;
});
document.querySelector('.ppcp-onboarding-cards-options').style.display = !cardsChk.checked ? 'none' : '';
const basicRb = document.querySelector('#ppcp-onboarding-dcc-basic');
const isExpress = !cardsChk.checked || basicRb.checked;
@ -245,6 +247,8 @@ function ppcp_onboarding_productionCallback(...args) {
}
);
sandboxSwitchElement.checked = ! sandboxSwitchElement.checked;
isDisconnecting = true;
document.querySelector('.woocommerce-save-button').click();

View file

@ -13,6 +13,7 @@ use WooCommerce\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint;
use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
* Class OnboardingAssets
@ -172,6 +173,6 @@ class OnboardingAssets {
* @return bool
*/
private function should_render_onboarding_script(): bool {
return PayPalGateway::ID === $this->page_id;
return PayPalGateway::ID === $this->page_id || Settings::CONNECTION_TAB_ID === $this->page_id;
}
}

View file

@ -56,6 +56,7 @@ class OnboardingOptionsRenderer {
* @param bool $is_shop_supports_dcc Whether the shop can use DCC (country, currency).
*/
public function render( bool $is_shop_supports_dcc ): string {
$checked = $is_shop_supports_dcc ? '' : 'checked';
return '
<ul class="ppcp-onboarding-options">
<li>
@ -64,9 +65,7 @@ class OnboardingOptionsRenderer {
</label>
</li>
<li>
<label><input type="checkbox" id="ppcp-onboarding-accept-cards" checked> ' .
__( 'Securely accept all major credit & debit cards on the strength of the PayPal network', 'woocommerce-paypal-payments' ) . '
</label>
<label><input type="checkbox" id="ppcp-onboarding-accept-cards" ' . $checked . '> ' . __( 'Securely accept all major credit & debit cards on the strength of the PayPal network', 'woocommerce-paypal-payments' ) . '</label>
</li>
<li>' . $this->render_dcc( $is_shop_supports_dcc ) . '</li>' .
$this->render_pui_option()
@ -103,6 +102,44 @@ class OnboardingOptionsRenderer {
$is_us_shop = 'US' === $this->country;
$basic_table_rows = array(
$this->render_table_row(
__( 'Credit & Debit Card form fields', 'woocommerce-paypal-payments' ),
__( 'Prebuilt user experience', 'woocommerce-paypal-payments' )
),
! $is_us_shop ? '' : $this->render_table_row(
__( 'Credit & Debit Card pricing', 'woocommerce-paypal-payments' ),
__( '3.49% + $0.49', 'woocommerce-paypal-payments' ),
'',
__( 'for US domestic transactions', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Seller Protection', 'woocommerce-paypal-payments' ),
__( 'Yes', 'woocommerce-paypal-payments' ),
__( 'No matter what you sell, Seller Protection can help you avoid chargebacks, reversals, and fees on eligible PayPal payment transactions — even when a customer has filed a dispute.', 'woocommerce-paypal-payments' ),
__( 'for eligible PayPal transactions', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Seller Account Type', 'woocommerce-paypal-payments' ),
__( 'Business or Casual', 'woocommerce-paypal-payments' ),
__( 'For Standard payments, Casual sellers may connect their Personal PayPal account in eligible countries to sell on WooCommerce. For Advanced payments, a Business PayPal account is required.', 'woocommerce-paypal-payments' )
),
);
$items[] = '
<li>
<label>
<input type="radio" id="ppcp-onboarding-dcc-basic" name="ppcp_onboarding_dcc" value="basic" checked ' .
( ! $is_shop_supports_dcc ? 'checked' : '' ) .
' data-screen-url="' . $this->get_screen_url( 'basic' ) . '"' .
'> ' .
__( 'Standard Card Processing', 'woocommerce-paypal-payments' ) . '
</label>
' . $this->render_tooltip( __( 'Card transactions are managed by PayPal, which simplifies compliance requirements for you.', 'woocommerce-paypal-payments' ) ) . '
<table>
' . implode( $basic_table_rows ) . '
</table>
</li>';
if ( $is_shop_supports_dcc ) {
$dcc_table_rows = array(
$this->render_table_row(
@ -146,9 +183,9 @@ class OnboardingOptionsRenderer {
$items[] = '
<li>
<label>
<input type="radio" id="ppcp-onboarding-dcc-acdc" name="ppcp_onboarding_dcc" value="acdc" checked ' .
<input type="radio" id="ppcp-onboarding-dcc-acdc" name="ppcp_onboarding_dcc" value="acdc" ' .
'data-screen-url="' . $this->get_screen_url( 'acdc' ) . '"> ' .
__( 'Advanced Card Processing', 'woocommerce-paypal-payments' ) . '
__( 'Advanced Card Processing', 'woocommerce-paypal-payments' ) . '
</label>
' . $this->render_tooltip( __( 'PayPal acts as the payment processor for card transactions. You can add optional features like Chargeback Protection for more security.', 'woocommerce-paypal-payments' ) ) . '
<table>
@ -157,53 +194,13 @@ class OnboardingOptionsRenderer {
</li>';
}
$basic_table_rows = array(
$this->render_table_row(
__( 'Credit & Debit Card form fields', 'woocommerce-paypal-payments' ),
__( 'Prebuilt user experience', 'woocommerce-paypal-payments' )
),
! $is_us_shop ? '' : $this->render_table_row(
__( 'Credit & Debit Card pricing', 'woocommerce-paypal-payments' ),
__( '3.49% + $0.49', 'woocommerce-paypal-payments' ),
'',
__( 'for US domestic transactions', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Seller Protection', 'woocommerce-paypal-payments' ),
__( 'Yes', 'woocommerce-paypal-payments' ),
__( 'No matter what you sell, Seller Protection can help you avoid chargebacks, reversals, and fees on eligible PayPal payment transactions — even when a customer has filed a dispute.', 'woocommerce-paypal-payments' ),
__( 'for eligible PayPal transactions', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Seller Account Type', 'woocommerce-paypal-payments' ),
__( 'Business or Casual', 'woocommerce-paypal-payments' ),
__( 'For Standard payments, Casual sellers may connect their Personal PayPal account in eligible countries to sell on WooCommerce. For Advanced payments, a Business PayPal account is required.', 'woocommerce-paypal-payments' )
),
);
$items[] = '
<li ' . ( ! $is_shop_supports_dcc ? 'style="display: none;"' : '' ) . '>
<label>
<input type="radio" id="ppcp-onboarding-dcc-basic" name="ppcp_onboarding_dcc" value="basic" ' .
( ! $is_shop_supports_dcc ? 'checked' : '' ) .
' data-screen-url="' . $this->get_screen_url( 'basic' ) . '"' .
'> ' .
__( 'Standard Card Processing', 'woocommerce-paypal-payments' ) . '
</label>
' . $this->render_tooltip( __( 'Card transactions are managed by PayPal, which simplifies compliance requirements for you.', 'woocommerce-paypal-payments' ) ) . '
<table>
' . implode( $basic_table_rows ) . '
</table>
</li>';
return '
<div class="ppcp-onboarding-cards-options">
<ul id="ppcp-onboarding-dcc-options" class="ppcp-onboarding-options-sublist">' .
implode( '', $items ) .
'
</ul>
<div class="ppcp-onboarding-cards-screen">' .
( $is_shop_supports_dcc ? '<img id="ppcp-onboarding-cards-screen-img" />' : '' ) . '
</div>
<div class="ppcp-onboarding-cards-screen"><img id="ppcp-onboarding-cards-screen-img" /></div>
</div>';
}

View file

@ -0,0 +1,2 @@
node_modules
/assets

View file

@ -0,0 +1,612 @@
<?php
/**
* The order tracking carriers.
*
* @package WooCommerce\PayPalCommerce\OrderTracking
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\OrderTracking;
use Psr\Container\ContainerInterface;
return array(
'global' => array(
'name' => 'Global',
'items' => array(
'B_TWO_C_EUROPE' => _x( 'B2C Europe', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CJ_LOGISTICS' => _x( 'CJ Logistics', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CORREOS_EXPRESS' => _x( 'Correos Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_ACTIVE_TRACING' => _x( 'DHL Active Tracing', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_BENELUX' => _x( 'DHL Benelux', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_GLOBAL_MAIL' => _x( 'DHL ecCommerce US', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_GLOBAL_MAIL_ASIA' => _x( 'DHL eCommerce Asia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL' => _x( 'DHL Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_GLOBAL_ECOMMERCE' => _x( 'DHL Global eCommerce', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_PACKET' => _x( 'DHL Packet', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD' => _x( 'DPD Global', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD_LOCAL' => _x( 'DPD Local', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD_LOCAL_REF' => _x( 'DPD Local Reference', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPE_EXPRESS' => _x( 'DPE Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPEX' => _x( 'DPEX Hong Kong', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DTDC_EXPRESS' => _x( 'DTDC Express Global', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ESHOPWORLD' => _x( 'EShopWorld', 'Name of carrier', 'woocommerce-paypal-payments' ),
'FEDEX' => _x( 'FedEx', 'Name of carrier', 'woocommerce-paypal-payments' ),
'FLYT_EXPRESS' => _x( 'FLYT Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GLS' => _x( 'GLS', 'Name of carrier', 'woocommerce-paypal-payments' ),
'IMX' => _x( 'IMX France', 'Name of carrier', 'woocommerce-paypal-payments' ),
'INT_SUER' => _x( 'International SEUR', 'Name of carrier', 'woocommerce-paypal-payments' ),
'LANDMARK_GLOBAL' => _x( 'Landmark Global', 'Name of carrier', 'woocommerce-paypal-payments' ),
'MATKAHUOLTO' => _x( 'Matkahuoloto', 'Name of carrier', 'woocommerce-paypal-payments' ),
'OMNIPARCEL' => _x( 'Omni Parcel', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ONE_WORLD' => _x( 'One World', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POSTI' => _x( 'Posti', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RABEN_GROUP' => _x( 'Raben Group', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SF_EXPRESS' => _x( 'SF EXPRESS', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SKYNET_Worldwide' => _x( 'SkyNet Worldwide Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SPREADEL' => _x( 'Spreadel', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT' => _x( 'TNT Global', 'Name of carrier', 'woocommerce-paypal-payments' ),
'UPS' => _x( 'UPS', 'Name of carrier', 'woocommerce-paypal-payments' ),
'UPS_MI' => _x( 'UPS Mail Innovations', 'Name of carrier', 'woocommerce-paypal-payments' ),
'WEBINTERPRET' => _x( 'WebInterpret', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'AG' => array(
'name' => _x( 'Antigua and Barbuda', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'CORREOS_AG' => _x( 'Correos Antigua and Barbuda', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'AR' => array(
'name' => _x( 'Argentina', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'EMIRATES_POST' => _x( 'Emirates Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'OCA_AR ' => _x( 'OCA Argentina', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'AU' => array(
'name' => _x( 'Australia', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ADSONE' => _x( 'Adsone', 'Name of carrier', 'woocommerce-paypal-payments' ),
'AUSTRALIA_POST' => _x( 'Australia Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TOLL_AU' => _x( 'Australia Toll', 'Name of carrier', 'woocommerce-paypal-payments' ),
'BONDS_COURIERS' => _x( 'Bonds Couriers', 'Name of carrier', 'woocommerce-paypal-payments' ),
'COURIERS_PLEASE' => _x( 'Couriers Please', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_AU' => _x( 'DHL Australia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DTDC_AU' => _x( 'DTDC Australia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'FASTWAY_AU' => _x( 'Fastway Australia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'HUNTER_EXPRESS ' => _x( 'Hunter Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SENDLE' => _x( 'Sendle', 'Name of carrier', 'woocommerce-paypal-payments' ),
'STARTRACK' => _x( 'Star Track', 'Name of carrier', 'woocommerce-paypal-payments' ),
'STARTRACK_EXPRESS' => _x( 'Star Track Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_AU ' => _x( 'TNT Australia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TOLL' => _x( 'Toll', 'Name of carrier', 'woocommerce-paypal-payments' ),
'UBI_LOGISTICS' => _x( 'UBI Logistics', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'AT' => array(
'name' => _x( 'Austria', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'AUSTRIAN_POST_EXPRESS' => _x( 'Austrian Post Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'AUSTRIAN_POST' => _x( 'Austrian Post Registered', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_AT' => _x( 'DHL Austria', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'BE' => array(
'name' => _x( 'Belgium', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'BPOST' => _x( 'bpost', 'Name of carrier', 'woocommerce-paypal-payments' ),
'BPOST_INT' => _x( 'bpost International', 'Name of carrier', 'woocommerce-paypal-payments' ),
'MONDIAL_BE' => _x( 'Mondial Belgium', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TAXIPOST' => _x( 'TaxiPost', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'BR' => array(
'name' => _x( 'Brazil', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'CORREOS_BR' => _x( 'Correos Brazil', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DIRECTLOG_BR' => _x( 'Directlog', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'BG' => array(
'name' => _x( 'Bulgaria', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'BULGARIAN_POST' => _x( 'Bulgarian Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'CA' => array(
'name' => _x( 'Canada', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'CANADA_POST' => _x( 'Canada Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CANPAR' => _x( 'Canpar', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GREYHOUND' => _x( 'Greyhound', 'Name of carrier', 'woocommerce-paypal-payments' ),
'LOOMIS' => _x( 'Loomis', 'Name of carrier', 'woocommerce-paypal-payments' ),
'PUROLATOR' => _x( 'Purolator', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'CL' => array(
'name' => _x( 'Chile', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'CORREOS_CL' => _x( 'Correos Chile', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'CN' => array(
'name' => _x( 'China', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'FOUR_PX_EXPRESS' => _x( 'Correos', 'Name of carrier', 'woocommerce-paypal-payments' ),
'AUPOST_CN' => _x( 'AUPOST CHINA', 'Name of carrier', 'woocommerce-paypal-payments' ),
'BQC_EXPRESS' => _x( 'BQC Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'BUYLOGIC' => _x( 'Buylogic', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CHINA_POST' => _x( 'China Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CNEXPS' => _x( 'CN Exps', 'Name of carrier', 'woocommerce-paypal-payments' ),
'EC_CN' => _x( 'EC China', 'Name of carrier', 'woocommerce-paypal-payments' ),
'EFS' => _x( 'EFS', 'Name of carrier', 'woocommerce-paypal-payments' ),
'EMPS_CN' => _x( 'EMPS China', 'Name of carrier', 'woocommerce-paypal-payments' ),
'EMS_CN' => _x( 'EMS China', 'Name of carrier', 'woocommerce-paypal-payments' ),
'HUAHAN_EXPRESS' => _x( 'Huahan Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SFC_EXPRESS' => _x( 'SFC Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_CN' => _x( 'TNT China', 'Name of carrier', 'woocommerce-paypal-payments' ),
'WINIT' => _x( 'WinIt', 'Name of carrier', 'woocommerce-paypal-payments' ),
'YANWEN_CN' => _x( 'Yanwen', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'CR' => array(
'name' => _x( 'Costa Rica', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'CORREOS_CR' => _x( 'Correos De Costa Rica', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'HR' => array(
'name' => _x( 'Croatia', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'HRVATSKA_HR' => _x( 'Hrvatska', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'CY' => array(
'name' => _x( 'Cyprus', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'CYPRUS_POST_CYP' => _x( 'Cyprus Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'CZ' => array(
'name' => _x( 'Czech Republic', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'CESKA_CZ' => _x( 'Ceska', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GLS_CZ' => _x( 'GLS Czech Republic', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'FR' => array(
'name' => _x( 'France', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'BERT' => _x( 'BERT TRANSPORT', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CHRONOPOST_FR' => _x( 'Chronopost France', 'Name of carrier', 'woocommerce-paypal-payments' ),
'COLIPOSTE' => _x( 'Coliposte', 'Name of carrier', 'woocommerce-paypal-payments' ),
'COLIS' => _x( 'Colis France', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_FR' => _x( 'DHL France', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD_FR' => _x( 'DPD France', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GEODIS' => _x( 'GEODIS - Distribution & Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GLS_FR' => _x( 'GLS France', 'Name of carrier', 'woocommerce-paypal-payments' ),
'LAPOSTE' => _x( 'LA Poste', 'Name of carrier', 'woocommerce-paypal-payments' ),
'MONDIAL' => _x( 'Mondial Relay', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RELAIS_COLIS_FR' => _x( 'Relais Colis', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TELIWAY' => _x( 'Teliway', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_FR' => _x( 'TNT France', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'DE' => array(
'name' => _x( 'Germany', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ASENDIA_DE' => _x( 'Asendia Germany', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DELTEC_DE' => _x( 'Deltec Germany', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DEUTSCHE_DE' => _x( 'Deutsche', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_DEUTSCHE_POST' => _x( 'DHL Deutsche Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD_DE' => _x( 'DPD Germany', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GLS_DE' => _x( 'GLS Germany', 'Name of carrier', 'woocommerce-paypal-payments' ),
'HERMES_DE' => _x( 'Hermes Germany', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_DE' => _x( 'TNT Germany', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'GR' => array(
'name' => _x( 'Greece', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ELTA_GR' => _x( 'ELTA Greece', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GENIKI_GR' => _x( 'Geniki Greece', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ACS_GR' => _x( 'GRC Greece', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'HK' => array(
'name' => _x( 'Hong Kong', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ASENDIA_HK' => _x( 'Asendia Hong Kong', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_HK' => _x( 'DHL Hong Kong', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD_HK' => _x( 'DPD Hong Kong', 'Name of carrier', 'woocommerce-paypal-payments' ),
'HK_POST' => _x( 'Hong Kong Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'KERRY_EXPRESS_HK' => _x( 'Kerry Express Hong Kong', 'Name of carrier', 'woocommerce-paypal-payments' ),
'LOGISTICSWORLDWIDE_HK' => _x( 'Logistics Worldwide Hong Kong', 'Name of carrier', 'woocommerce-paypal-payments' ),
'QUANTIUM' => _x( 'Quantium', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SEKOLOGISTICS' => _x( 'Seko Logistics', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TAQBIN_HK' => _x( 'TA-Q-BIN Parcel Hong Kong', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'HU' => array(
'name' => _x( 'Hungary', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'MAGYAR_HU' => _x( 'Magyar', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'IS' => array(
'name' => _x( 'Iceland', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'POSTUR_IS' => _x( 'Postur', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'IN' => array(
'name' => _x( 'India', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'BLUEDART' => _x( 'Bluedart', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DELHIVERY_IN' => _x( 'Delhivery', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DOTZOT' => _x( 'DotZot', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DTDC_IN' => _x( 'DTDC India', 'Name of carrier', 'woocommerce-paypal-payments' ),
'EKART' => _x( 'Ekart', 'Name of carrier', 'woocommerce-paypal-payments' ),
'INDIA_POST' => _x( 'India Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'PROFESSIONAL_COURIERS' => _x( 'Professional Couriers', 'Name of carrier', 'woocommerce-paypal-payments' ),
'REDEXPRESS' => _x( 'Red Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SWIFTAIR' => _x( 'Swift Air', 'Name of carrier', 'woocommerce-paypal-payments' ),
'XPRESSBEES' => _x( 'Xpress Bees', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'ID' => array(
'name' => _x( 'Indonesia', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'FIRST_LOGISITCS' => _x( 'First Logistics', 'Name of carrier', 'woocommerce-paypal-payments' ),
'JNE_IDN' => _x( 'JNE Indonesia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'LION_PARCEL' => _x( 'Lion Parcel', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NINJAVAN_ID' => _x( 'Ninjavan Indonesia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'PANDU' => _x( 'Pandu Logistics', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POS_ID' => _x( 'Pos Indonesia Domestic', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POS_INT' => _x( 'Pos Indonesia International', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RPX_ID' => _x( 'RPX Indonesia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RPX' => _x( 'RPX International', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TIKI_ID' => _x( 'Tiki', 'Name of carrier', 'woocommerce-paypal-payments' ),
'WAHANA_ID' => _x( 'Wahana', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'IE' => array(
'name' => _x( 'Ireland', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'AN_POST' => _x( 'AN POST Ireland', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD_IR' => _x( 'DPD Ireland', 'Name of carrier', 'woocommerce-paypal-payments' ),
'MASTERLINK' => _x( 'Masterlink', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TPG' => _x( 'TPG', 'Name of carrier', 'woocommerce-paypal-payments' ),
'WISELOADS' => _x( 'Wiseloads', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'IL' => array(
'name' => _x( 'Israel', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ISRAEL_POST' => _x( 'Israel Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'IT' => array(
'name' => _x( 'Italy', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'BRT_IT' => _x( 'BRT Bartolini', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_IT' => _x( 'DHL Italy', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DMM_NETWORK' => _x( 'DMM Network', 'Name of carrier', 'woocommerce-paypal-payments' ),
'FERCAM_IT' => _x( 'FERCAM Logistics & Transport', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GLS_IT' => _x( 'GLS Italy', 'Name of carrier', 'woocommerce-paypal-payments' ),
'HERMES_IT' => _x( 'Hermes Italy', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POSTE_ITALIANE' => _x( 'Poste Italiane', 'Name of carrier', 'woocommerce-paypal-payments' ),
'REGISTER_MAIL_IT' => _x( 'Register Mail IT', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SDA_IT' => _x( 'SDA Italy', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SGT_IT' => _x( 'SGT Corriere Espresso', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_CLICK_IT' => _x( 'TNT Click Italy', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_IT' => _x( 'TNT Italy', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'JP' => array(
'name' => _x( 'Japan', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'DHL_JP' => _x( 'DHL Japan', 'Name of carrier', 'woocommerce-paypal-payments' ),
'JP_POST' => _x( 'JP Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'JAPAN_POST' => _x( 'Japan Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POCZTEX' => _x( 'Pocztex', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SAGAWA' => _x( 'Sagawa', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SAGAWA_JP' => _x( 'Sagawa JP', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_JP' => _x( 'TNT Japan', 'Name of carrier', 'woocommerce-paypal-payments' ),
'YAMATO' => _x( 'Yamato Japan', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'KR' => array(
'name' => _x( 'Korea', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ECARGO' => _x( 'Ecargo', 'Name of carrier', 'woocommerce-paypal-payments' ),
'EPARCEL_KR' => _x( 'eParcel Korea', 'Name of carrier', 'woocommerce-paypal-payments' ),
'KOREA_POST' => _x( 'Korea Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'KOR_KOREA_POST' => _x( 'KOR Korea Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CJ_KR' => _x( 'Korea Thai CJ', 'Name of carrier', 'woocommerce-paypal-payments' ),
'LOGISTICSWORLDWIDE_KR' => _x( 'Logistics Worldwide Korea', 'Name of carrier', 'woocommerce-paypal-payments' ),
'PANTOS' => _x( 'Pantos', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RINCOS' => _x( 'Rincos', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ROCKET_PARCEL' => _x( 'Rocket Parcel International', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SRE_KOREA' => _x( 'SRE Korea', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'LT' => array(
'name' => _x( 'Lithuania', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'LIETUVOS_LT' => _x( 'Lietuvos Pastas', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'MY' => array(
'name' => _x( 'Malaysia', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'AIRPAK_MY' => _x( 'Airpak', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CITYLINK_MY' => _x( 'CityLink Malaysia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CJ_MY' => _x( 'CJ Malaysia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CJ_INT_MY' => _x( 'CJ Malaysia International', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CUCKOOEXPRESS' => _x( 'Cuckoo Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'JETSHIP_MY' => _x( 'Jet Ship Malaysia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'KANGAROO_MY' => _x( 'Kangaroo Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'LOGISTICSWORLDWIDE_MY' => _x( 'Logistics Worldwide Malaysia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'MALAYSIA_POST' => _x( 'Malaysia Post EMS / Pos Laju', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NATIONWIDE' => _x( 'Nationwide', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NINJAVAN_MY' => _x( 'Ninjavan Malaysia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SKYNET_MY' => _x( 'Skynet Malaysia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TAQBIN_MY' => _x( 'TA-Q-BIN Parcel Malaysia', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'MX' => array(
'name' => _x( 'Mexico', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'CORREOS_MX' => _x( 'Correos De Mexico', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ESTAFETA' => _x( 'Estafeta', 'Name of carrier', 'woocommerce-paypal-payments' ),
'AEROFLASH' => _x( 'Mexico Aeroflash', 'Name of carrier', 'woocommerce-paypal-payments' ),
'REDPACK' => _x( 'Mexico Redpack', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SENDA_MX' => _x( 'Mexico Senda Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'NL' => array(
'name' => _x( 'Netherlands', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'DHL_NL' => _x( 'DHL Netherlands', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_PARCEL_NL' => _x( 'DHL Parcel Netherlands', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GLS_NL' => _x( 'GLS Netherlands', 'Name of carrier', 'woocommerce-paypal-payments' ),
'KIALA' => _x( 'Kiala', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POSTNL' => _x( 'PostNL', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POSTNL_INT' => _x( 'PostNl International', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POSTNL_INT_3_S' => _x( 'PostNL International 3S', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_NL' => _x( 'TNT Netherlands', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TRANSMISSION' => _x( 'Transmission Netherlands', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'NZ' => array(
'name' => _x( 'New Zealand', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'COURIER_POST' => _x( 'Courier Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'FASTWAY_NZ' => _x( 'Fastway New Zealand', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NZ_POST' => _x( 'New Zealand Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TOLL_IPEC' => _x( 'Toll IPEC', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'NG' => array(
'name' => _x( 'Nigeria', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'COURIERPLUS' => _x( 'Courier Plus', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NIPOST_NG' => _x( 'NiPost', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'NO' => array(
'name' => _x( 'Norway', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'POSTEN_NORGE' => _x( 'Posten Norge', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'PH' => array(
'name' => _x( 'Philippines', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'TWO_GO' => _x( '2GO', 'Name of carrier', 'woocommerce-paypal-payments' ),
'AIR_21' => _x( 'Air 21', 'Name of carrier', 'woocommerce-paypal-payments' ),
'AIRSPEED' => _x( 'Airspeed', 'Name of carrier', 'woocommerce-paypal-payments' ),
'JAMEXPRESS_PH' => _x( 'Jam Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'LBC_PH' => _x( 'LBC Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NINJAVAN_PH' => _x( 'Ninjavan Philippines', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RAF_PH' => _x( 'RAF Philippines', 'Name of carrier', 'woocommerce-paypal-payments' ),
'XEND_EXPRESS_PH' => _x( 'Xend Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'PL' => array(
'name' => _x( 'Poland', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'DHL_PL' => _x( 'DHL Poland', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD_PL' => _x( 'DPD Poland', 'Name of carrier', 'woocommerce-paypal-payments' ),
'INPOST_PACZKOMATY' => _x( 'InPost Paczkomaty', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POCZTA_POLSKA' => _x( 'Poczta Polska', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SIODEMKA' => _x( 'Siodemka', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_PL' => _x( 'TNT Poland', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'PT' => array(
'name' => _x( 'Portugal', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ADICIONAL_PT' => _x( 'Adicional Logistics', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CHRONOPOST_PT' => _x( 'Chronopost Portugal', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CTT_PT' => _x( 'Portugal PTT', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SEUR_PT' => _x( 'Portugal Seur', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'RO' => array(
'name' => _x( 'Romania', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'DPD_RO' => _x( 'DPD Romania', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POSTA_RO' => _x( 'Postaromana', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'RU' => array(
'name' => _x( 'Russia', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'DPD_RU' => _x( 'DPD Russia', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RUSSIAN_POST' => _x( 'Russian Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'SA' => array(
'name' => _x( 'Saudi Arabia', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'DAWN_WING' => _x( 'Dawn Wing', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RAM' => _x( 'Ram', 'Name of carrier', 'woocommerce-paypal-payments' ),
'THE_COURIER_GUY' => _x( 'The Courier Guy', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'CS' => array(
'name' => _x( 'Serbia', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'POST_SERBIA_CS' => _x( 'Serbia Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'SG' => array(
'name' => _x( 'Singapore', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'DHL_SG' => _x( 'DHL Singapore', 'Name of carrier', 'woocommerce-paypal-payments' ),
'JETSHIP_SG' => _x( 'JetShip Singapore', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NINJAVAN_SG' => _x( 'Ninjavan Singapore', 'Name of carrier', 'woocommerce-paypal-payments' ),
'PARCELPOST_SG' => _x( 'Parcel Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SINGPOST' => _x( 'Singapore Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TAQBIN_SG' => _x( 'TA-Q-BIN Parcel Singapore', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'ZA' => array(
'name' => _x( 'South Africa', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'FASTWAY_ZA' => _x( 'Fastway South Africa', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'ES' => array(
'name' => _x( 'Spain', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ASM_ES' => _x( 'ASM', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CBL_LOGISTICA' => _x( 'CBL Logistics', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CORREOS_ES' => _x( 'Correos De Spain', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_ES ' => _x( 'DHL Spain', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_PARCEL_ES' => _x( 'DHL Parcel Spain', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GLS_ES' => _x( 'GLS Spain', 'Name of carrier', 'woocommerce-paypal-payments' ),
'INT_SEUR' => _x( 'International Suer', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ITIS' => _x( 'ITIS', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NACEX_ES' => _x( 'Nacex Spain', 'Name of carrier', 'woocommerce-paypal-payments' ),
'REDUR_ES' => _x( 'Redur Spain', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SEUR_ES' => _x( 'Spanish Seur', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_ES' => _x( 'TNT Spain', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'SE' => array(
'name' => _x( 'Sweden', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'DBSCHENKER_SE' => _x( 'DB Schenker Sweden', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DIRECTLINK_SE' => _x( 'DirectLink Sweden', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POSTNORD_LOGISTICS_GLOBAL' => _x( 'PostNord Logistics', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POSTNORD_LOGISTICS_DK' => _x( 'PostNord Logistics Denmark', 'Name of carrier', 'woocommerce-paypal-payments' ),
'POSTNORD_LOGISTICS_SE' => _x( 'PostNord Logistics Sweden', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'CH' => array(
'name' => _x( 'Switzerland', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'SWISS_POST' => _x( 'Swiss Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'TW' => array(
'name' => _x( 'Taiwan', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'CHUNGHWA_POST' => _x( 'Chunghwa Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TAIWAN_POST_TW' => _x( 'Taiwan Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'TH' => array(
'name' => _x( 'Thailand', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ACOMMMERCE' => _x( 'Acommerce', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ALPHAFAST' => _x( 'Alphafast', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CJ_TH' => _x( 'CJ Thailand', 'Name of carrier', 'woocommerce-paypal-payments' ),
'FASTRACK' => _x( 'FastTrack Thailand', 'Name of carrier', 'woocommerce-paypal-payments' ),
'KERRY_EXPRESS_TH' => _x( 'Kerry Express Thailand', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NIM_EXPRESS' => _x( 'NIM Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NINJAVAN_THAI' => _x( 'Ninjavan Thailand', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SENDIT' => _x( 'SendIt', 'Name of carrier', 'woocommerce-paypal-payments' ),
'THAILAND_POST' => _x( 'Thailand Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'TR' => array(
'name' => _x( 'Turkey', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'PTT_POST' => _x( 'PTT Posta', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'UA' => array(
'name' => _x( 'Ukraine', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'NOVA_POSHTA' => _x( 'Nova Poshta', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NOVA_POSHTA_INT' => _x( 'Nova Poshta International', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'AE' => array(
'name' => _x( 'United Arab Emirates', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'AXL' => _x( 'AXL Express & Logistics', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CONTINENTAL' => _x( 'Continental', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SKYNET_UAE' => _x( 'Skynet Worldwide Express UAE', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'GB' => array(
'name' => _x( 'United Kingdom', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'AIRBORNE_EXPRESS_UK' => _x( 'Airborne Express UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'AIRSURE' => _x( 'Airsure', 'Name of carrier', 'woocommerce-paypal-payments' ),
'APC_OVERNIGHT' => _x( 'APC Overnight', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ASENDIA_UK' => _x( 'Asendia UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'COLLECTPLUS' => _x( 'CollectPlus', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DELTEC_UK' => _x( 'Deltec UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DHL_UK' => _x( 'DHL UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD_DELISTRACK' => _x( 'DPD Delistrack', 'Name of carrier', 'woocommerce-paypal-payments' ),
'DPD_UK' => _x( 'DPD UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'FASTWAY_UK' => _x( 'Fastway UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'HERMESWORLD_UK' => _x( 'HermesWorld', 'Name of carrier', 'woocommerce-paypal-payments' ),
'INTERLINK' => _x( 'Interlink Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'MYHERMES' => _x( 'MyHermes UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'NIGHTLINE_UK' => _x( 'Nightline UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'PARCELFORCE' => _x( 'Parcel Force', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ROYAL_MAIL' => _x( 'Royal Mail', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RPD_2_MAN' => _x( 'RPD2man Deliveries', 'Name of carrier', 'woocommerce-paypal-payments' ),
'SKYNET_UK' => _x( 'Skynet Worldwide Express UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'TNT_UK' => _x( 'TNT UK', 'Name of carrier', 'woocommerce-paypal-payments' ),
'UK_MAIL' => _x( 'UK Mail', 'Name of carrier', 'woocommerce-paypal-payments' ),
'YODEL' => _x( 'Yodel', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'US' => array(
'name' => _x( 'United States', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'ABC_PACKAGE' => _x( 'ABC Package Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'AIRBORNE_EXPRESS' => _x( 'Airborne Express', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ASENDIA_US' => _x( 'Asendia USA', 'Name of carrier', 'woocommerce-paypal-payments' ),
'CPACKET' => _x( 'Cpacket', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ENSENDA' => _x( 'Ensenda USA', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ESTES' => _x( 'Estes', 'Name of carrier', 'woocommerce-paypal-payments' ),
'FASTWAY_US' => _x( 'Fastway USA', 'Name of carrier', 'woocommerce-paypal-payments' ),
'GLOBEGISTICS' => _x( 'Globegistics USA', 'Name of carrier', 'woocommerce-paypal-payments' ),
'INTERNATIONAL_BRIDGE' => _x( 'International Bridge', 'Name of carrier', 'woocommerce-paypal-payments' ),
'ONTRAC' => _x( 'OnTrac', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RL_US' => _x( 'RL Carriers', 'Name of carrier', 'woocommerce-paypal-payments' ),
'RRDONNELLEY' => _x( 'RR Donnelley', 'Name of carrier', 'woocommerce-paypal-payments' ),
'USPS' => _x( 'USPS', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
'VN' => array(
'name' => _x( 'Vietnam', 'Name of carrier country', 'woocommerce-paypal-payments' ),
'items' => array(
'KERRY_EXPRESS_VN' => _x( 'Kerry Express Vietnam', 'Name of carrier', 'woocommerce-paypal-payments' ),
'VIETNAM_POST' => _x( 'Vietnam Post', 'Name of carrier', 'woocommerce-paypal-payments' ),
'VNPOST_EMS' => _x( 'Vietnam Post EMS', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
);

View file

@ -0,0 +1,17 @@
{
"name": "woocommerce/ppcp-order-tracking",
"type": "dhii-mod",
"description": "Order tracking module for PPCP",
"license": "GPL-2.0",
"require": {
"php": "^7.1 | ^8.0",
"dhii/module-interface": "^0.3.0-alpha1"
},
"autoload": {
"psr-4": {
"WooCommerce\\PayPalCommerce\\OrderTracking\\": "src"
}
},
"minimum-stability": "dev",
"prefer-stable": true
}

View file

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

View file

@ -0,0 +1,16 @@
<?php
/**
* The order tracking module.
*
* @package WooCommerce\PayPalCommerce\OrderTracking
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\OrderTracking;
use Dhii\Modular\Module\ModuleInterface;
return static function (): ModuleInterface {
return new OrderTrackingModule();
};

View file

@ -0,0 +1,23 @@
{
"name": "ppcp-order-tracking",
"version": "1.0.0",
"license": "GPL-3.0-or-later",
"main": "resources/js/order-edit-page.js",
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"babel-loader": "^8.1.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"cross-env": "^7.0.3",
"file-loader": "^6.2.0",
"sass": "^1.42.1",
"sass-loader": "^12.1.0",
"webpack": "^5.55.0",
"webpack-cli": "^4.8.0"
},
"scripts": {
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
"watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch",
"dev": "cross-env BABEL_ENV=default webpack --watch"
}
}

View file

@ -0,0 +1,20 @@
#ppcp_order-tracking {
.tracking-info-message {
padding-left: 20px;
}
.error {
color: red;
font-weight: bold;
}
.success {
color: green;
font-weight: bold;
}
input,select {
width: 100%;
}
}

View file

@ -0,0 +1,49 @@
import {PaymentMethods} from "../../../ppcp-button/resources/js/modules/Helper/CheckoutMethodState";
document.addEventListener(
'DOMContentLoaded',
() => {
const config = PayPalCommerceGatewayOrderTrackingInfo;
if (!typeof (PayPalCommerceGatewayOrderTrackingInfo)) {
console.error('trackign cannot be set.');
return;
}
const transactionId = document.querySelector('.ppcp-tracking-transaction_id');
const trackingNumber = document.querySelector('.ppcp-tracking-tracking_number');
const status = document.querySelector('.ppcp-tracking-status');
const carrier = document.querySelector('.ppcp-tracking-carrier');
const orderId = document.querySelector('.ppcp-order_id');
const submitButton = document.querySelector('.submit_tracking_info');
submitButton.addEventListener('click', function (event) {
submitButton.setAttribute('disabled', 'disabled');
fetch(config.ajax.tracking_info.endpoint, {
method: 'POST',
body: JSON.stringify({
nonce: config.ajax.tracking_info.nonce,
transaction_id: transactionId ? transactionId.value : null,
tracking_number: trackingNumber ? trackingNumber.value : null,
status: status ? status.value : null,
carrier: carrier ? carrier.value : null,
order_id: orderId ? orderId.value : null,
action: submitButton ? submitButton.dataset.action : null,
})
}).then(function (res) {
return res.json();
}).then(function (data) {
if (!data.success) {
console.error(data);
throw Error(data.data.message);
}
jQuery( "<span class='success tracking-info-message'>" + data.data.message + "</span>" ).insertAfter(submitButton);
setTimeout(()=> jQuery('.tracking-info-message').remove(),3000);
submitButton.dataset.action = 'update';
submitButton.textContent = 'update';
submitButton.removeAttribute('disabled');
});
})
},
);

View file

@ -0,0 +1,82 @@
<?php
/**
* The order tracking module services.
*
* @package WooCommerce\PayPalCommerce\OrderTracking
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\OrderTracking;
use Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\OrderTracking\Assets\OrderEditPageAssets;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
return array(
'order-tracking.assets' => function( ContainerInterface $container ) : OrderEditPageAssets {
return new OrderEditPageAssets(
$container->get( 'order-tracking.module.url' ),
$container->get( 'ppcp.asset-version' )
);
},
'order-tracking.endpoint.controller' => static function ( ContainerInterface $container ) : OrderTrackingEndpoint {
return new OrderTrackingEndpoint(
$container->get( 'api.host' ),
$container->get( 'api.bearer' ),
$container->get( 'woocommerce.logger.woocommerce' ),
$container->get( 'button.request-data' )
);
},
'order-tracking.module.url' => static function ( ContainerInterface $container ): string {
/**
* The path cannot be false.
*
* @psalm-suppress PossiblyFalseArgument
*/
return plugins_url(
'/modules/ppcp-order-tracking/',
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
);
},
'order-tracking.meta-box.renderer' => static function ( ContainerInterface $container ): MetaBoxRenderer {
return new MetaBoxRenderer(
$container->get( 'order-tracking.endpoint.controller' ),
$container->get( 'order-tracking.allowed-shipping-statuses' ),
$container->get( 'order-tracking.available-carriers' )
);
},
'order-tracking.allowed-shipping-statuses' => static function ( ContainerInterface $container ): array {
return array( 'SHIPPED', 'ON_HOLD', 'DELIVERED', 'CANCELLED' );
},
'order-tracking.allowed-carriers' => static function ( ContainerInterface $container ): array {
return require __DIR__ . '/carriers.php';
},
'order-tracking.available-carriers' => static function ( ContainerInterface $container ): array {
$api_shop_country = $container->get( 'api.shop.country' );
$allowed_carriers = $container->get( 'order-tracking.allowed-carriers' );
$selected_country_carriers = $allowed_carriers[ $api_shop_country ] ?? array();
return array(
$api_shop_country => $selected_country_carriers ?? array(),
'global' => $allowed_carriers['global'] ?? array(),
'other' => array(
'name' => 'Other',
'items' => array(
'OTHER' => _x( 'Other', 'Name of carrier', 'woocommerce-paypal-payments' ),
),
),
);
},
'order-tracking.is-paypal-order-edit-page' => static function ( ContainerInterface $container ): bool {
$order_id = isset( $_GET['post'] ) ? (int) $_GET['post'] : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( empty( $order_id ) ) {
return false;
}
$meta = get_post_meta( $order_id, PayPalGateway::ORDER_ID_META_KEY, true );
return ! empty( $meta );
},
);

View file

@ -0,0 +1,100 @@
<?php
/**
* Register and configure assets for order edit page.
*
* @package WooCommerce\PayPalCommerce\OrderTracking\Assets
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\OrderTracking\Assets;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
/**
* Class OrderEditPageAssets
*/
class OrderEditPageAssets {
/**
* The URL to the module.
*
* @var string
*/
private $module_url;
/**
* The assets version.
*
* @var string
*/
private $version;
/**
* WebhooksStatusPageAssets constructor.
*
* @param string $module_url The URL to the module.
* @param string $version The assets version.
*/
public function __construct(
string $module_url,
string $version
) {
$this->module_url = $module_url;
$this->version = $version;
}
/**
* Registers the scripts and styles.
*
* @return void
*/
public function register(): void {
wp_register_style(
'ppcp-webhooks-order-edit-page-style',
untrailingslashit( $this->module_url ) . '/assets/css/order-edit-page.css',
array(),
$this->version
);
wp_register_script(
'ppcp-tracking',
untrailingslashit( $this->module_url ) . '/assets/js/order-edit-page.js',
array( 'jquery' ),
$this->version,
true
);
wp_localize_script(
'ppcp-tracking',
'PayPalCommerceGatewayOrderTrackingInfo',
$this->get_script_data()
);
}
/**
* Returns the data for the script.
*
* @return array a map of script data.
*/
public function get_script_data(): array {
return array(
'ajax' => array(
'tracking_info' => array(
'endpoint' => \WC_AJAX::get_endpoint( OrderTrackingEndpoint::ENDPOINT ),
'nonce' => wp_create_nonce( OrderTrackingEndpoint::nonce() ),
),
),
);
}
/**
* Enqueues the necessary scripts.
*
* @return void
*/
public function enqueue(): void {
wp_enqueue_style( 'ppcp-webhooks-order-edit-page-style' );
wp_enqueue_script( 'ppcp-tracking' );
}
}

View file

@ -0,0 +1,356 @@
<?php
/**
* The order tracking Endpoint.
*
* @package WooCommerce\PayPalCommerce\OrderTracking\Endpoint
*/
declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\OrderTracking\Endpoint;
use Exception;
use Psr\Log\LoggerInterface;
use WC_Order;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\RequestTrait;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
/**
* The OrderTrackingEndpoint.
*
* @psalm-type SupportedStatuses = 'SHIPPED'|'ON_HOLD'|'DELIVERED'|'CANCELLED'
* @psalm-type TrackingInfo = array{transaction_id: string, status: SupportedStatuses, tracking_number?: string, carrier?: string}
* @psalm-type RequestValues = array{transaction_id: string, status: SupportedStatuses, order_id: int, action: 'create'|'update', tracking_number?: string, carrier?: string}
* Class OrderTrackingEndpoint
*/
class OrderTrackingEndpoint {
use RequestTrait, TransactionIdHandlingTrait;
const ENDPOINT = 'ppc-tracking-info';
/**
* The RequestData.
*
* @var RequestData
*/
protected $request_data;
/**
* The Host URL.
*
* @var string
*/
private $host;
/**
* The bearer.
*
* @var Bearer
*/
private $bearer;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* PartnersEndpoint constructor.
*
* @param string $host The host.
* @param Bearer $bearer The bearer.
* @param LoggerInterface $logger The logger.
* @param RequestData $request_data The Request data.
*/
public function __construct(
string $host,
Bearer $bearer,
LoggerInterface $logger,
RequestData $request_data
) {
$this->host = $host;
$this->bearer = $bearer;
$this->logger = $logger;
$this->request_data = $request_data;
}
/**
* Handles the request.
*/
public function handle_request(): void {
try {
$data = $this->request_data->read_request( $this->nonce() );
$action = $data['action'];
$request_body = $this->extract_tracking_information( $data );
$order_id = (int) $data['order_id'];
$action === 'create' ? $this->add_tracking_information( $request_body, $order_id ) : $this->update_tracking_information( $data, $order_id );
$action_message = $action === 'create' ? 'created' : 'updated';
$message = sprintf(
// translators: %1$s is the action message (created or updated).
_x( 'successfully %1$s', 'tracking info success message', 'woocommerce-paypal-payments' ),
esc_html( $action_message )
);
wp_send_json_success( array( 'message' => $message ) );
} catch ( Exception $error ) {
wp_send_json_error( $error->getMessage(), 500 );
}
}
/**
* Creates the tracking information of a given order with the given data.
*
* @param array $data The tracking information to add.
* @psalm-param TrackingInfo $data
* @param int $order_id The order ID.
* @throws RuntimeException If problem creating.
*/
public function add_tracking_information( array $data, int $order_id ) : void {
$url = trailingslashit( $this->host ) . 'v1/shipping/trackers-batch';
$body = array(
'trackers' => array( $data ),
);
$args = array(
'method' => 'POST',
'headers' => $this->request_headers(),
'body' => wp_json_encode( $body ),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
'Could not create order tracking information.'
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
/**
* Need to ignore Method WP_Error::offsetGet does not exist
*
* @psalm-suppress UndefinedMethod
*/
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
sprintf(
'Failed to create order tracking information. PayPal API response: %1$s',
$error->getMessage()
),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
update_post_meta( $order_id, '_ppcp_paypal_tracking_number', $data['tracking_number'] ?? '' );
}
/**
* Gets the tracking information of a given order.
*
* @param int $wc_order_id The order ID.
* @return array|null The tracking information.
* @psalm-return TrackingInfo|null
* @throws RuntimeException If problem getting.
*/
public function get_tracking_information( int $wc_order_id ) : ?array {
$wc_order = wc_get_order( $wc_order_id );
if ( ! is_a( $wc_order, WC_Order::class ) ) {
throw new RuntimeException( 'wrong order ID' );
}
$transaction_id = $wc_order->get_transaction_id();
$tracking_number = get_post_meta( $wc_order_id, '_ppcp_paypal_tracking_number', true );
$url = trailingslashit( $this->host ) . 'v1/shipping/trackers/' . $this->find_tracker_id( $transaction_id, $tracking_number );
$args = array(
'method' => 'GET',
'headers' => $this->request_headers(),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
'Could not fetch the tracking information.'
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
/**
* Need to ignore Method WP_Error::offsetGet does not exist
*
* @psalm-suppress UndefinedMethod
*/
$data = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 !== $status_code ) {
return null;
}
return $this->extract_tracking_information( (array) $data );
}
/**
* Updates the tracking information of a given order with the given data.
*
* @param array $data The tracking information to update.
* @psalm-param TrackingInfo $data
* @param int $order_id The order ID.
* @throws RuntimeException If problem updating.
*/
public function update_tracking_information( array $data, int $order_id ) : void {
$tracking_info = $this->get_tracking_information( $order_id );
$transaction_id = $tracking_info['transaction_id'] ?? '';
$tracking_number = $tracking_info['tracking_number'] ?? '';
$url = trailingslashit( $this->host ) . 'v1/shipping/trackers/' . $this->find_tracker_id( $transaction_id, $tracking_number );
$args = array(
'method' => 'PUT',
'headers' => $this->request_headers(),
'body' => wp_json_encode( $data ),
);
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
'Could not update order tracking information.'
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
/**
* Need to ignore Method WP_Error::offsetGet does not exist
*
* @psalm-suppress UndefinedMethod
*/
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 204 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
sprintf(
'Failed to update the order tracking information. PayPal API response: %1$s',
$error->getMessage()
),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
update_post_meta( $order_id, '_ppcp_paypal_tracking_number', $data['tracking_number'] ?? '' );
}
/**
* The nonce.
*
* @return string
*/
public static function nonce(): string {
return self::ENDPOINT;
}
/**
* Extracts the needed tracking information from given data.
*
* @param array $data The request data map.
* @psalm-param RequestValues $data
* @return array A map of tracking information keys to values.
* @psalm-return TrackingInfo
* @throws RuntimeException If problem extracting.
*/
protected function extract_tracking_information( array $data ): array {
if ( empty( $data['transaction_id'] ) || empty( $data['status'] ) ) {
$this->logger->log( 'warning', 'Missing transaction_id or status.' );
throw new RuntimeException( 'Missing transaction_id or status.' );
}
$tracking_info = array(
'transaction_id' => $data['transaction_id'],
'status' => $data['status'],
);
if ( ! empty( $data['tracking_number'] ) ) {
$tracking_info['tracking_number'] = $data['tracking_number'];
}
if ( ! empty( $data['carrier'] ) ) {
$tracking_info['carrier'] = $data['carrier'];
}
return $tracking_info;
}
/**
* Creates the request headers.
*
* @return array The request headers.
*/
protected function request_headers(): array {
return array(
'Authorization' => 'Bearer ' . $this->bearer->bearer()->token(),
'Content-Type' => 'application/json',
);
}
/**
* Finds the tracker ID from given transaction ID and tracking number.
*
* @param string $transaction_id The transaction ID.
* @param string $tracking_number The tracking number.
* @return string The tracker ID.
*/
protected function find_tracker_id( string $transaction_id, string $tracking_number ): string {
return ! empty( $tracking_number ) ? "{$transaction_id}-{$tracking_number}" : "{$transaction_id}-NOTRACKER";
}
}

View file

@ -0,0 +1,131 @@
<?php
/**
* The order tracking MetaBox renderer.
*
* @package WooCommerce\PayPalCommerce\OrderTracking
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\OrderTracking;
use WC_Order;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
use WP_Post;
/**
* Class MetaBoxRenderer
*
* @psalm-type CarrierType = string
* @psalm-type CarrierItemCode = string
* @psalm-type CarrierItemName = string
* @psalm-type Carrier = array{name: string, items: array<CarrierItemCode, CarrierItemName>}
* @psalm-type Carriers = array<CarrierType, Carrier>
*/
class MetaBoxRenderer {
public const NAME_PREFIX = 'ppcp-tracking';
/**
* The OrderTrackingEndpoint.
*
* @var OrderTrackingEndpoint
*/
protected $order_tracking_endpoint;
/**
* Allowed shipping statuses.
*
* @var string[]
*/
protected $allowed_statuses;
/**
* Available shipping carriers.
*
* @var array
* @psalm-var Carriers
*/
protected $carriers;
/**
* MetaBoxRenderer constructor.
*
* @param OrderTrackingEndpoint $order_tracking_endpoint The OrderTrackingEndpoint.
* @param string[] $allowed_statuses Allowed shipping statuses.
* @param array $carriers Available shipping carriers.
* @psalm-param Carriers $carriers
*/
public function __construct(
OrderTrackingEndpoint $order_tracking_endpoint,
array $allowed_statuses,
array $carriers
) {
$this->order_tracking_endpoint = $order_tracking_endpoint;
$this->allowed_statuses = $allowed_statuses;
$this->carriers = $carriers;
}
/**
* Renders the order tracking MetaBox.
*
* @param WP_Post $post The post object.
*/
public function render( WP_Post $post ): void {
$wc_order = wc_get_order( $post->ID );
if ( ! is_a( $wc_order, WC_Order::class ) ) {
return;
}
$tracking_info = $this->order_tracking_endpoint->get_tracking_information( $wc_order->get_id() );
$tracking_is_not_added = empty( $tracking_info );
$transaction_id = $tracking_info['transaction_id'] ?? $wc_order->get_transaction_id() ?: '';
$tracking_number = $tracking_info['tracking_number'] ?? '';
$status_value = $tracking_info['status'] ?? 'SHIPPED';
$carrier_value = $tracking_info['carrier'] ?? '';
$carriers = (array) apply_filters( 'ppcp_tracking_carriers', $this->carriers );
$statuses = (array) apply_filters( 'ppcp_tracking_statuses', $this->allowed_statuses );
$action = $tracking_is_not_added ? 'create' : 'update';
?>
<p>
<label for="<?php echo esc_attr( self::NAME_PREFIX ); ?>-transaction_id"><?php echo esc_html__( 'Transaction ID', 'woocommerce-paypal-payments' ); ?></label>
<input type="text" disabled class="<?php echo esc_attr( self::NAME_PREFIX ); ?>-transaction_id" id="<?php echo esc_attr( self::NAME_PREFIX ); ?>-transaction_id" name="<?php echo esc_attr( self::NAME_PREFIX ); ?>[transaction_id]" value="<?php echo esc_html( $transaction_id ); ?>"/></p>
<p>
<label for="<?php echo esc_attr( self::NAME_PREFIX ); ?>-tracking_number"><?php echo esc_html__( 'Tracking Number', 'woocommerce-paypal-payments' ); ?></label>
<input type="text" class="<?php echo esc_attr( self::NAME_PREFIX ); ?>-tracking_number" id="<?php echo esc_attr( self::NAME_PREFIX ); ?>-tracking_number" name="<?php echo esc_attr( self::NAME_PREFIX ); ?>[tracking_number]" value="<?php echo esc_html( $tracking_number ); ?>"/></p>
<p>
<label for="<?php echo esc_attr( self::NAME_PREFIX ); ?>-status"><?php echo esc_html__( 'Status', 'woocommerce-paypal-payments' ); ?></label>
<select class="<?php echo esc_attr( self::NAME_PREFIX ); ?>-status" id="<?php echo esc_attr( self::NAME_PREFIX ); ?>-status" name="<?php echo esc_attr( self::NAME_PREFIX ); ?>[status]">
<?php foreach ( $statuses as $status ) : ?>
<option value="<?php echo esc_attr( $status ); ?>" <?php selected( $status_value, $status ); ?>><?php echo esc_html( $status ); ?></option>
<?php endforeach; ?>
</select>
</p>
<p>
<label for="ppcp-tracking-carrier"><?php echo esc_html__( 'Carrier', 'woocommerce-paypal-payments' ); ?></label>
<select class="ppcp-tracking-carrier" id="ppcp-tracking-carrier" name="ppcp-tracking[carrier]">
<option value=""><?php echo esc_html__( 'Select Carrier', 'woocommerce-paypal-payments' ); ?></option>
<?php
foreach ( $carriers as $carrier ) :
$country = $carrier['name'] ?? '';
$carrier_items = $carrier['items'] ?? array();
?>
<optgroup label="<?php echo esc_attr( $country ); ?>">
<?php foreach ( $carrier_items as $carrier_code => $carrier_name ) : ?>
<option value="<?php echo esc_attr( $carrier_code ); ?>" <?php selected( $carrier_value, $carrier_code ); ?>><?php echo esc_html( $carrier_name ); ?></option>
<?php endforeach; ?>
</optgroup>
<?php endforeach; ?>
</select>
</p>
<input type="hidden" class="ppcp-order_id" name="<?php echo esc_attr( self::NAME_PREFIX ); ?>[order_id]" value="<?php echo intval( $post->ID ); ?>"/>
<p>
<button type="button" class="button submit_tracking_info" data-action="<?php echo esc_attr( $action ); ?>"><?php echo esc_html( ucfirst( $action ) ); ?></button></p>
<?php
}
}

View file

@ -0,0 +1,149 @@
<?php
/**
* The order tracking module.
*
* @package WooCommerce\PayPalCommerce\OrderTracking
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\OrderTracking;
use Dhii\Container\ServiceProvider;
use Dhii\Modular\Module\ModuleInterface;
use Exception;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use WC_Order;
use WooCommerce\PayPalCommerce\OrderTracking\Assets\OrderEditPageAssets;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
/**
* Class OrderTrackingModule
*/
class OrderTrackingModule implements ModuleInterface {
/**
* {@inheritDoc}
*/
public function setup(): ServiceProviderInterface {
return new ServiceProvider(
require __DIR__ . '/../services.php',
require __DIR__ . '/../extensions.php'
);
}
/**
* {@inheritDoc}
*
* @param ContainerInterface $c A services container instance.
* @throws NotFoundException
*/
public function run( ContainerInterface $c ): void {
$settings = $c->get( 'wcgateway.settings' );
assert( $settings instanceof Settings );
$pui_helper = $c->get( 'wcgateway.pay-upon-invoice-helper' );
assert( $pui_helper instanceof PayUponInvoiceHelper );
if ( $pui_helper->is_pui_enabled() ) {
$settings->set( 'tracking_enabled', true );
$settings->persist();
}
$tracking_enabled = $settings->has( 'tracking_enabled' ) && $settings->get( 'tracking_enabled' );
if ( ! $tracking_enabled ) {
return;
}
$asset_loader = $c->get( 'order-tracking.assets' );
assert( $asset_loader instanceof OrderEditPageAssets );
$is_paypal_order_edit_page = $c->get( 'order-tracking.is-paypal-order-edit-page' );
$endpoint = $c->get( 'order-tracking.endpoint.controller' );
assert( $endpoint instanceof OrderTrackingEndpoint );
$logger = $c->get( 'woocommerce.logger.woocommerce' );
assert( $logger instanceof LoggerInterface );
add_action(
'init',
static function () use ( $asset_loader, $is_paypal_order_edit_page ) {
if ( ! $is_paypal_order_edit_page ) {
return;
}
$asset_loader->register();
}
);
add_action(
'admin_enqueue_scripts',
static function () use ( $asset_loader, $is_paypal_order_edit_page ) {
if ( ! $is_paypal_order_edit_page ) {
return;
}
$asset_loader->enqueue();
}
);
add_action(
'wc_ajax_' . OrderTrackingEndpoint::ENDPOINT,
array( $endpoint, 'handle_request' )
);
$meta_box_renderer = $c->get( 'order-tracking.meta-box.renderer' );
add_action(
'add_meta_boxes',
static function() use ( $meta_box_renderer, $is_paypal_order_edit_page ) {
if ( ! $is_paypal_order_edit_page ) {
return;
}
add_meta_box( 'ppcp_order-tracking', __( 'Tracking Information', 'woocommerce-paypal-payments' ), array( $meta_box_renderer, 'render' ), 'shop_order', 'side' );
},
10,
2
);
add_action(
'woocommerce_order_status_completed',
static function( int $order_id ) use ( $endpoint, $logger ) {
$tracking_information = $endpoint->get_tracking_information( $order_id );
if ( $tracking_information ) {
return;
}
$wc_order = wc_get_order( $order_id );
if ( ! is_a( $wc_order, WC_Order::class ) ) {
return;
}
$transaction_id = $wc_order->get_transaction_id();
if ( empty( $transaction_id ) ) {
return;
}
$tracking_data = array(
'transaction_id' => $transaction_id,
'status' => 'SHIPPED',
);
try {
$endpoint->add_tracking_information( $tracking_data, $order_id );
} catch ( Exception $exception ) {
$logger->error( "Couldn't create tracking information: " . $exception->getMessage() );
throw $exception;
}
}
);
}
}

View file

@ -0,0 +1,36 @@
const path = require('path');
const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
devtool: 'eval-source-map',
mode: isProduction ? 'production' : 'development',
target: 'web',
entry: {
'order-edit-page': path.resolve('./resources/js/order-edit-page.js'),
'order-edit-page-style': path.resolve('./resources/css/order-edit-page.scss'),
},
output: {
path: path.resolve(__dirname, 'assets/'),
filename: 'js/[name].js',
},
module: {
rules: [{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
{
loader: 'file-loader',
options: {
name: 'css/[name].css',
}
},
{loader:'sass-loader'}
]
}]
}
};

File diff suppressed because it is too large Load diff

View file

@ -72,6 +72,8 @@ class StatusReportModule implements ModuleInterface {
$had_ppec_plugin = PPECHelper::is_plugin_configured();
$is_tracking_available = $c->get( 'order-tracking.is-tracking-available' );
$items = array(
array(
'label' => esc_html__( 'Onboarded', 'woocommerce-paypal-payments' ),
@ -149,6 +151,12 @@ class StatusReportModule implements ModuleInterface {
$had_ppec_plugin
),
),
array(
'label' => esc_html__( 'Tracking enabled', 'woocommerce-paypal-payments' ),
'exported_label' => 'Tracking enabled',
'description' => esc_html__( 'Whether tracking is enabled on PayPal account or not.', 'woocommerce-paypal-payments' ),
'value' => $this->bool_to_html( $is_tracking_available ),
),
);
echo wp_kses_post(

View file

@ -0,0 +1,439 @@
<?php
/**
* The services of the Gateway module.
*
* @package WooCommerce\PayPalCommerce\WcGateway
*/
// phpcs:disable WordPress.Security.NonceVerification.Recommended
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway;
use Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
return function ( ContainerInterface $container, array $fields ): array {
$state = $container->get( 'onboarding.state' );
assert( $state instanceof State );
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
assert( $dcc_applies instanceof DccApplies );
$is_shop_supports_dcc = $dcc_applies->for_country_currency() || $dcc_applies->for_wc_payments();
$onboarding_options_renderer = $container->get( 'onboarding.render-options' );
assert( $onboarding_options_renderer instanceof OnboardingOptionsRenderer );
$module_url = $container->get( 'wcgateway.url' );
$connection_fields = array(
'ppcp_onboarading_header' => array(
'type' => 'ppcp-text',
'classes' => array( 'ppcp-onboarding-element' ),
'text' => '
<div class="ppcp-onboarding-header">
<div class="ppcp-onboarding-header-left">
<img alt="PayPal" src="' . esc_url( $module_url ) . 'assets/images/paypal.png"/>
<h2>The all-in-one checkout solution</h2>
</div>
<div class="ppcp-onboarding-header-right">
<div class="ppcp-onboarding-header-paypal-logos">
<img alt="PayPal" src="' . esc_url( $module_url ) . 'assets/images/paypal-button.svg"/>
<img alt="Venmo" src="' . esc_url( $module_url ) . 'assets/images/venmo.svg"/>
<img alt="Pay Later" src="' . esc_url( $module_url ) . 'assets/images/paylater.svg"/>
</div>
<div class="ppcp-onboarding-header-cards">
<img alt="Visa" src="' . esc_url( $module_url ) . 'assets/images/visa-dark.svg"/>
<img alt="Mastercard" src="' . esc_url( $module_url ) . 'assets/images/mastercard-dark.svg"/>
<img alt="American Express" src="' . esc_url( $module_url ) . 'assets/images/amex.svg"/>
<img alt="Discover" src="' . esc_url( $module_url ) . 'assets/images/discover.svg"/>
<img alt="iDEAL" src="' . esc_url( $module_url ) . 'assets/images/ideal-dark.svg"/>
<img alt="Sofort" src="' . esc_url( $module_url ) . 'assets/images/sofort.svg"/>
</div>
</div>
</div>',
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'credentials_production_heading' => array(
'heading' => __( 'API Credentials', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-heading',
'screens' => array(
State::STATE_ONBOARDED,
),
'state_from' => Environment::PRODUCTION,
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'credentials_sandbox_heading' => array(
'heading' => __( 'Sandbox API Credentials', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-heading',
'screens' => array(
State::STATE_ONBOARDED,
),
'state_from' => Environment::SANDBOX,
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Your account is connected to sandbox, no real charging takes place. To accept live payments, turn off sandbox mode and connect your live PayPal account.', 'woocommerce-paypal-payments' ),
),
'ppcp_onboarading_options' => array(
'type' => 'ppcp-text',
'classes' => array( 'ppcp-onboarding-element' ),
'text' => $onboarding_options_renderer->render( $is_shop_supports_dcc ),
'raw' => true,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
// We need to have a button for each option (ppcp, express)
// because currently the only documented way to use the PayPal onboarding JS library
// is to have the buttons before loading the script.
'ppcp_onboarding_production_ppcp' => array(
'type' => 'ppcp_onboarding',
'classes' => array( 'ppcp-onboarding-element' ),
'screens' => array(
State::STATE_START,
),
'state_from' => Environment::PRODUCTION,
'env' => Environment::PRODUCTION,
'products' => array( 'PPCP' ),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'ppcp_onboarding_production_express' => array(
'type' => 'ppcp_onboarding',
'classes' => array( 'ppcp-onboarding-element' ),
'screens' => array(
State::STATE_START,
),
'state_from' => Environment::PRODUCTION,
'env' => Environment::PRODUCTION,
'products' => array( 'EXPRESS_CHECKOUT' ),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'ppcp_onboarding_sandbox_ppcp' => array(
'type' => 'ppcp_onboarding',
'classes' => array( 'ppcp-onboarding-element' ),
'screens' => array(
State::STATE_START,
),
'state_from' => Environment::SANDBOX,
'env' => Environment::SANDBOX,
'products' => array( 'PPCP' ),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Prior to accepting live payments, you can test payments on your WooCommerce platform in a safe PayPal sandbox environment.', 'woocommerce-paypal-payments' ),
),
'ppcp_onboarding_sandbox_express' => array(
'type' => 'ppcp_onboarding',
'classes' => array( 'ppcp-onboarding-element' ),
'screens' => array(
State::STATE_START,
),
'state_from' => Environment::SANDBOX,
'env' => Environment::SANDBOX,
'products' => array( 'EXPRESS_CHECKOUT' ),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Prior to accepting live payments, you can test payments on your WooCommerce platform in a safe PayPal sandbox environment.', 'woocommerce-paypal-payments' ),
),
'ppcp_disconnect_production' => array(
'title' => __( 'Disconnect from PayPal', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-text',
'text' => sprintf(
'<p>%1$s <span class="dashicons dashicons-yes"></span></p><p><button type="button" class="button ppcp-disconnect production">%2$s</button></p>',
esc_html__( 'Status: Connected', 'woocommerce-paypal-payments' ),
esc_html__( 'Disconnect Account', 'woocommerce-paypal-payments' )
),
'screens' => array(
State::STATE_ONBOARDED,
),
'state_from' => Environment::PRODUCTION,
'env' => Environment::PRODUCTION,
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Click to reset current credentials and use another account.', 'woocommerce-paypal-payments' ),
),
'ppcp_disconnect_sandbox' => array(
'title' => __( 'Disconnect from PayPal Sandbox', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-text',
'text' => sprintf(
'<p>%1$s <span class="dashicons dashicons-yes"></span></p><p><button type="button" class="button ppcp-disconnect sandbox">%2$s</button></p>',
esc_html__( 'Status: Connected', 'woocommerce-paypal-payments' ),
esc_html__( 'Disconnect Account', 'woocommerce-paypal-payments' )
),
'screens' => array(
State::STATE_ONBOARDED,
),
'state_from' => Environment::SANDBOX,
'env' => Environment::SANDBOX,
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Click to reset current credentials and use another account.', 'woocommerce-paypal-payments' ),
),
'toggle_manual_input' => array(
'type' => 'ppcp-text',
'text' => '<button type="button" id="ppcp[toggle_manual_input]">' . __( 'Toggle to manual credential input', 'woocommerce-paypal-payments' ) . '</button>',
'classes' => array( 'ppcp-onboarding-element' ),
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'error_label' => array(
'type' => 'ppcp-text',
'text' => '<label class="error" id="ppcp-form-errors-label"></label>',
'classes' => array( 'hide', 'ppcp-always-shown-element' ),
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'sandbox_on' => array(
'title' => __( 'Sandbox', 'woocommerce-paypal-payments' ),
'classes' => array( 'ppcp-onboarding-element', 'ppcp-always-shown-element' ),
'type' => 'checkbox',
'label' => __( 'To test your WooCommerce installation, you can use the sandbox mode.', 'woocommerce-paypal-payments' ),
'default' => 0,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'merchant_email_production' => array(
'title' => __( 'Live Email address', 'woocommerce-paypal-payments' ),
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
'type' => 'text',
'required' => true,
'desc_tip' => true,
'description' => __( 'The email address of your PayPal account.', 'woocommerce-paypal-payments' ),
'default' => '',
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'merchant_id_production' => array(
'title' => __( 'Live Merchant Id', 'woocommerce-paypal-payments' ),
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
'type' => 'ppcp-text-input',
'desc_tip' => true,
'description' => __( 'The merchant id of your account ', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'client_id_production' => array(
'title' => __( 'Live Client Id', 'woocommerce-paypal-payments' ),
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
'type' => 'ppcp-text-input',
'desc_tip' => true,
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'client_secret_production' => array(
'title' => __( 'Live Secret Key', 'woocommerce-paypal-payments' ),
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
'type' => 'ppcp-password',
'desc_tip' => true,
'description' => __( 'The secret key of your api', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'merchant_email_sandbox' => array(
'title' => __( 'Sandbox Email address', 'woocommerce-paypal-payments' ),
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
'type' => 'text',
'required' => true,
'desc_tip' => true,
'description' => __( 'The email address of your PayPal account.', 'woocommerce-paypal-payments' ),
'default' => '',
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'merchant_id_sandbox' => array(
'title' => __( 'Sandbox Merchant Id', 'woocommerce-paypal-payments' ),
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
'type' => 'ppcp-text-input',
'desc_tip' => true,
'description' => __( 'The merchant id of your account ', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'client_id_sandbox' => array(
'title' => __( 'Sandbox Client Id', 'woocommerce-paypal-payments' ),
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
'type' => 'ppcp-text-input',
'desc_tip' => true,
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'client_secret_sandbox' => array(
'title' => __( 'Sandbox Secret Key', 'woocommerce-paypal-payments' ),
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
'type' => 'ppcp-password',
'desc_tip' => true,
'description' => __( 'The secret key of your api', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'credentials_feature_onboarding_heading' => array(
'heading' => __( 'Feature Onboarding', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-heading',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'See which features are available.', 'woocommerce-paypal-payments' ),
),
'ppcp_dcc_status' => array(
'title' => __( 'Advanced Credit and Debit Card Payments', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-text',
'text' => $container->get( 'wcgateway.settings.connection.dcc-status-text' ),
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'dcc' ),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'ppcp_pui_status' => array(
'title' => __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-text',
'text' => $container->get( 'wcgateway.settings.connection.pui-status-text' ),
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'pui_ready' ),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'tracking_enabled' => array(
'title' => __( 'Tracking', 'woocommerce-paypal-payments' ),
'type' => 'checkbox',
'desc_tip' => true,
'label' => $container->get( 'wcgateway.settings.tracking-label' ),
'description' => __( 'Allows to send shipment tracking numbers to PayPal for PayPal transactions.', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'input_class' => $container->get( 'wcgateway.settings.should-disable-tracking-checkbox' ) ? array( 'ppcp-disabled-checkbox' ) : array(),
),
'credentials_integration_configuration_heading' => array(
'heading' => __( 'Integration configuration', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-heading',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'See which features are available.', 'woocommerce-paypal-payments' ),
),
'prefix' => array(
'title' => __( 'Invoice prefix', 'woocommerce-paypal-payments' ),
'type' => 'text',
'desc_tip' => true,
'description' => __( 'If you use your PayPal account with more than one installation, please use a distinct prefix to separate those installations. Please use only English letters and "-", "_" characters.', 'woocommerce-paypal-payments' ),
'maxlength' => 15,
'custom_attributes' => array(
'pattern' => '[a-zA-Z_-]+',
),
'default' => ( static function (): string {
$site_url = get_site_url( get_current_blog_id() );
$hash = md5( $site_url );
$letters = preg_replace( '~\d~', '', $hash ) ?? '';
$prefix = substr( $letters, 0, 6 );
return $prefix ? $prefix . '-' : '';
} )(),
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
'logging_enabled' => array(
'title' => __( 'Logging', 'woocommerce-paypal-payments' ),
'type' => 'checkbox',
'desc_tip' => true,
'label' => __( 'Enable logging. ', 'woocommerce-paypal-payments' ) .
' <a href="' . admin_url( 'admin.php?page=wc-status&tab=logs' ) . '">' . __( 'View logs', 'woocommerce-paypal-payments' ) . '</a>',
'description' => __( 'Enable logging of unexpected behavior. This can also log private data and should only be enabled in a development or stage environment.', 'woocommerce-paypal-payments' ),
'default' => false,
'screens' => array(
State::STATE_START,
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
),
);
return array_merge( $fields, $connection_fields );
};

View file

@ -98,4 +98,6 @@ return array(
$source
);
},
'wcgateway.settings.fields' => require __DIR__ . '/connection-tab-settings.php',
);

File diff suppressed because it is too large Load diff

View file

@ -88,9 +88,12 @@ class DisableGateways {
* @return bool
*/
private function disable_all_gateways() : bool {
if ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) ) {
return true;
foreach ( WC()->payment_gateways->payment_gateways() as $gateway ) {
if ( PayPalGateway::ID === $gateway->id && $gateway->enabled !== 'yes' ) {
return true;
}
}
if ( ! $this->settings->has( 'merchant_email' ) || ! is_email( $this->settings->get( 'merchant_email' ) ) ) {
return true;
}

View file

@ -26,6 +26,7 @@ use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
use Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
@ -290,6 +291,9 @@ class PayPalGateway extends \WC_Payment_Gateway {
* @return string
*/
private function define_method_title(): string {
if ( $this->is_connection_tab() ) {
return __( 'Account Setup', 'woocommerce-paypal-payments' );
}
if ( $this->is_credit_card_tab() ) {
return __( 'PayPal Card Processing', 'woocommerce-paypal-payments' );
}
@ -312,6 +316,10 @@ class PayPalGateway extends \WC_Payment_Gateway {
* @return string
*/
private function define_method_description(): string {
if ( $this->is_connection_tab() ) {
return '';
}
if ( $this->is_credit_card_tab() ) {
return __(
'Accept debit and credit cards, and local payment methods.',
@ -374,6 +382,16 @@ class PayPalGateway extends \WC_Payment_Gateway {
&& WebhooksStatusPage::ID === $this->page_id;
}
/**
* Whether we are on the connection tab.
*
* @return bool true if is connection tab, otherwise false
*/
protected function is_connection_tab() : bool {
return is_admin()
&& Settings::CONNECTION_TAB_ID === $this->page_id;
}
/**
* Whether we are on the PayPal settings tab.
*

View file

@ -226,7 +226,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
$payment_source = $this->payment_source_factory->from_wc_order( $wc_order, $birth_date );
try {
$order = $this->order_endpoint->create( array( $purchase_unit ), $payment_source );
$order = $this->order_endpoint->create( array( $purchase_unit ), $payment_source, $wc_order );
$this->add_paypal_meta( $wc_order, $order, $this->environment );
as_schedule_single_action(

View file

@ -9,9 +9,9 @@ declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
use Throwable;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusProduct;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
@ -22,7 +22,7 @@ class DCCProductStatus {
/**
* Caches the status for the current load.
*
* @var string|null
* @var bool|null
*/
private $current_status_cache;
/**
@ -57,12 +57,12 @@ class DCCProductStatus {
* Whether the active/subscribed products support DCC.
*
* @return bool
* @throws \WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException Should a setting not be found.
*/
public function dcc_is_active() : bool {
if ( is_bool( $this->current_status_cache ) ) {
return $this->current_status_cache;
}
if ( $this->settings->has( 'products_dcc_enabled' ) && $this->settings->get( 'products_dcc_enabled' ) ) {
$this->current_status_cache = true;
return true;
@ -70,7 +70,7 @@ class DCCProductStatus {
try {
$seller_status = $this->partners_endpoint->seller_status();
} catch ( RuntimeException $error ) {
} catch ( Throwable $error ) {
$this->current_status_cache = false;
return false;
}

View file

@ -10,6 +10,8 @@ declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
use WC_Order;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
* Class PayUponInvoiceHelper
@ -23,13 +25,23 @@ class PayUponInvoiceHelper {
*/
protected $checkout_helper;
/**
* The settings.
*
* @var Settings
*/
protected $settings;
/**
* PayUponInvoiceHelper constructor.
*
* @param CheckoutHelper $checkout_helper The checkout helper.
* @param Settings $settings The Settings.
*/
public function __construct( CheckoutHelper $checkout_helper ) {
public function __construct( CheckoutHelper $checkout_helper, Settings $settings ) {
$this->checkout_helper = $checkout_helper;
$this->settings = $settings;
}
/**
@ -78,4 +90,14 @@ class PayUponInvoiceHelper {
return false;
}
/**
* Checks whether PUI is enabled.
*
* @return bool True if PUI is active, otherwise false.
* @throws NotFoundException If problem when checking the settings.
*/
public function is_pui_enabled(): bool {
return $this->settings->has( 'products_pui_enabled' ) && $this->settings->get( 'products_pui_enabled' );
}
}

View file

@ -9,11 +9,10 @@ declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
use Throwable;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusProduct;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
/**
* Class PayUponInvoiceProductStatus
@ -70,7 +69,7 @@ class PayUponInvoiceProductStatus {
try {
$seller_status = $this->partners_endpoint->seller_status();
} catch ( RuntimeException $error ) {
} catch ( Throwable $error ) {
$this->current_status_cache = false;
return false;
}

View file

@ -0,0 +1,82 @@
<?php
/**
* Renders the settings page header.
*
* @package WooCommerce\PayPalCommerce\WcGateway\Settings
*/
declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
/**
* Class HeaderRenderer
*/
class HeaderRenderer {
const KEY = 'ppcp-tab';
/**
* ID of the current PPCP gateway settings page, or empty if it is not such page.
*
* @var string
*/
private $page_id;
/**
* The URL to the module.
*
* @var string
*/
private $module_url;
/**
* HeaderRenderer constructor.
*
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
* @param string $module_url The URL to the module.
*/
public function __construct( string $page_id, string $module_url ) {
$this->page_id = $page_id;
$this->module_url = $module_url;
}
/**
* Whether the sections tab should be rendered.
*
* @return bool
*/
public function should_render() : bool {
return ! empty( $this->page_id );
}
/**
* Renders the Sections tab.
*/
public function render(): string {
if ( ! $this->should_render() ) {
return '';
}
return '
<div class="ppcp-settings-page-header">
<img alt="PayPal" src="' . esc_url( $this->module_url ) . 'assets/images/paypal.png"/>
<h4> <span class="ppcp-inline-only">-</span> ' . __( 'The all-in-one checkout solution for WooCommerce', 'woocommerce-paypal-payments' ) . '</h4>
<a class="button" target="_blank" href="https://woocommerce.com/document/woocommerce-paypal-payments/">'
. __( 'Documentation', 'woocommerce-paypal-payments' ) .
'</a>
<a class="button" target="_blank" href="https://woocommerce.com/document/woocommerce-paypal-payments/#get-help">'
. __( 'Get Help', 'woocommerce-paypal-payments' ) .
'</a>
<span class="ppcp-right-align">
<a target="_blank" href="https://woocommerce.com/feature-requests/woocommerce-paypal-payments/">'
. __( 'Request a feature', 'woocommerce-paypal-payments' ) .
'</a>
<a target="_blank" href="https://github.com/woocommerce/woocommerce-paypal-payments/issues/new?assignees=&labels=type%3A+bug&template=bug_report.md">'
. __( 'Submit a bug', 'woocommerce-paypal-payments' ) .
'</a>
</span>
</div>
';
}
}

View file

@ -33,10 +33,11 @@ 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,
Settings::CONNECTION_TAB_ID => Settings::CONNECTION_TAB_ID,
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 )
&& in_array( $gateway_page_id_map[ $current_page_id ], $allowed_gateways, true );

View file

@ -9,6 +9,7 @@ declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
@ -33,15 +34,24 @@ class SectionsRenderer {
*/
protected $sections;
/**
* The onboarding state.
*
* @var State
*/
private $state;
/**
* SectionsRenderer constructor.
*
* @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.
* @param State $state The onboarding state.
*/
public function __construct( string $page_id, array $sections ) {
public function __construct( string $page_id, array $sections, State $state ) {
$this->page_id = $page_id;
$this->sections = $sections;
$this->state = $state;
}
/**
@ -50,7 +60,9 @@ class SectionsRenderer {
* @return bool
*/
public function should_render() : bool {
return ! empty( $this->page_id );
return ! empty( $this->page_id ) &&
( $this->state->production_state() === State::STATE_ONBOARDED ||
$this->state->sandbox_state() === State::STATE_ONBOARDED );
}
/**
@ -65,7 +77,7 @@ class SectionsRenderer {
foreach ( $this->sections as $id => $label ) {
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . $id );
if ( in_array( $id, array( CreditCardGateway::ID, WebhooksStatusPage::ID ), true ) ) {
if ( in_array( $id, array( Settings::CONNECTION_TAB_ID, 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.

View file

@ -17,7 +17,8 @@ use Psr\Container\ContainerInterface;
*/
class Settings implements ContainerInterface {
const KEY = 'woocommerce-ppcp-settings';
const KEY = 'woocommerce-ppcp-settings';
const CONNECTION_TAB_ID = 'ppcp-connection';
/**
* The settings.

View file

@ -174,7 +174,7 @@ class SettingsListener {
/**
* The URL opened at the end of onboarding after saving the merchant ID/email.
*/
$redirect_url = apply_filters( 'woocommerce_paypal_payments_onboarding_redirect_url', admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway' ) );
$redirect_url = apply_filters( 'woocommerce_paypal_payments_onboarding_redirect_url', admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway&ppcp-tab=ppcp-connection' ) );
if ( ! $this->settings->has( 'client_id' ) || ! $this->settings->get( 'client_id' ) ) {
$redirect_url = add_query_arg( 'ppcp-onboarding-error', '1', $redirect_url );
}
@ -235,7 +235,7 @@ class SettingsListener {
*
* @throws \WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException When a setting was not found.
*/
public function listen() {
public function listen(): void {
if ( ! $this->is_valid_update_request() ) {
return;
@ -259,7 +259,7 @@ class SettingsListener {
$credentials_change_status = null; // Cannot detect on Card Processing page.
if ( PayPalGateway::ID === $this->page_id ) {
if ( PayPalGateway::ID === $this->page_id || Settings::CONNECTION_TAB_ID === $this->page_id ) {
$settings['enabled'] = isset( $_POST['woocommerce_ppcp-gateway_enabled'] )
&& 1 === absint( $_POST['woocommerce_ppcp-gateway_enabled'] );
@ -267,7 +267,6 @@ class SettingsListener {
}
// phpcs:enable phpcs:disable WordPress.Security.NonceVerification.Missing
// phpcs:enable phpcs:disable WordPress.Security.NonceVerification.Missing
if ( $credentials_change_status ) {
if ( self::CREDENTIALS_UNCHANGED !== $credentials_change_status ) {
$this->settings->set( 'products_dcc_enabled', null );
@ -473,4 +472,36 @@ class SettingsListener {
}
return true;
}
/**
* Prevent enabling tracking if it is not enabled for merchant account.
*/
public function listen_for_tracking_enabled(): void {
if ( State::STATE_ONBOARDED !== $this->state->current_state() ) {
return;
}
try {
$token = $this->bearer->bearer();
if ( ! $token->is_tracking_available() ) {
$this->settings->set( 'tracking_enabled', false );
$this->settings->persist();
return;
}
} catch ( RuntimeException $exception ) {
$this->settings->set( 'tracking_enabled', false );
$this->settings->persist();
add_action(
'admin_notices',
function () use ( $exception ) {
printf(
'<div class="notice notice-error"><p>%1$s</p><p>%2$s</p></div>',
esc_html__( 'Authentication with PayPal failed: ', 'woocommerce-paypal-payments' ) . esc_attr( $exception->getMessage() ),
wp_kses_post( __( 'Please verify your API Credentials and try again to connect your PayPal business account. Visit the <a href="https://docs.woocommerce.com/document/woocommerce-paypal-payments/" target="_blank">plugin documentation</a> for more information about the setup.', 'woocommerce-paypal-payments' ) )
);
}
);
}
}
}

View file

@ -33,6 +33,13 @@ class SettingsRenderer {
*/
protected $settings_status;
/**
* The api shop country.
*
* @var string
*/
protected $api_shop_country;
/**
* The settings.
*
@ -93,6 +100,7 @@ class SettingsRenderer {
* @param DCCProductStatus $dcc_product_status The product status.
* @param SettingsStatus $settings_status The Settings status helper.
* @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.
*/
public function __construct(
ContainerInterface $settings,
@ -102,7 +110,8 @@ class SettingsRenderer {
MessagesApply $messages_apply,
DCCProductStatus $dcc_product_status,
SettingsStatus $settings_status,
string $page_id
string $page_id,
string $api_shop_country
) {
$this->settings = $settings;
@ -113,6 +122,7 @@ class SettingsRenderer {
$this->dcc_product_status = $dcc_product_status;
$this->settings_status = $settings_status;
$this->page_id = $page_id;
$this->api_shop_country = $api_shop_country;
}
/**
@ -348,7 +358,7 @@ $data_rows_html
/**
* Renders the settings.
*/
public function render() {
public function render(): void {
$is_dcc = CreditCardGateway::ID === $this->page_id;
//phpcs:enable WordPress.Security.NonceVerification.Recommended
@ -381,14 +391,14 @@ $data_rows_html
continue;
}
if (
in_array( 'dcc', $config['requirements'], true )
&& ! $this->dcc_product_status->dcc_is_active()
in_array( 'messages', $config['requirements'], true )
&& ! $this->messages_apply->for_country()
) {
continue;
}
if (
in_array( 'messages', $config['requirements'], true )
&& ! $this->messages_apply->for_country()
in_array( 'pui_ready', $config['requirements'], true )
&& $this->api_shop_country !== 'DE'
) {
continue;
}

View file

@ -17,6 +17,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\WcGateway\Admin\FeesRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Admin\OrderTablePaymentStatusColumn;
use WooCommerce\PayPalCommerce\WcGateway\Admin\PaymentStatusOrderDetail;
@ -28,9 +29,12 @@ use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
use WooCommerce\PayPalCommerce\WcGateway\Notice\GatewayWithoutPayPalAdminNotice;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\HeaderRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
@ -65,11 +69,14 @@ class WCGatewayModule implements ModuleInterface {
add_action(
'woocommerce_sections_checkout',
function() use ( $c ) {
$header_renderer = $c->get( 'wcgateway.settings.header-renderer' );
assert( $header_renderer instanceof HeaderRenderer );
$section_renderer = $c->get( 'wcgateway.settings.sections-renderer' );
assert( $section_renderer instanceof SectionsRenderer );
// phpcs:ignore WordPress.Security.EscapeOutput
echo $section_renderer->render();
echo $header_renderer->render() . $section_renderer->render();
},
20
);
@ -297,15 +304,36 @@ class WCGatewayModule implements ModuleInterface {
$paypal_gateway_enabled = wc_string_to_bool( $paypal_gateway->get_option( 'enabled' ) );
$methods[] = $paypal_gateway;
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
$methods[] = $paypal_gateway;
/**
* The DCC Applies object.
*
* @var DccApplies $dcc_applies
*/
if ( $dcc_applies->for_country_currency() ) {
$onboarding_state = $container->get( 'onboarding.state' );
assert( $onboarding_state instanceof State );
$settings = $container->get( 'wcgateway.settings' );
assert( $settings instanceof ContainerInterface );
$is_our_page = $container->get( 'wcgateway.is-ppcp-settings-page' );
$is_gateways_list_page = $container->get( 'wcgateway.is-wc-gateways-list-page' );
if ( $onboarding_state->current_state() !== State::STATE_ONBOARDED ) {
return $methods;
}
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
assert( $dcc_applies instanceof DccApplies );
$dcc_product_status = $container->get( 'wcgateway.helper.dcc-product-status' );
assert( $dcc_product_status instanceof DCCProductStatus );
if ( $dcc_applies->for_country_currency() &&
// Show only if allowed in PayPal account, except when on our settings pages.
// Performing the full DCCProductStatus check only when on the gateway list page
// to avoid sending the API requests all the time.
( $is_our_page ||
( $is_gateways_list_page && $dcc_product_status->dcc_is_active() ) ||
( $settings->has( 'products_dcc_enabled' ) && $settings->get( 'products_dcc_enabled' ) )
)
) {
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
}
@ -313,11 +341,21 @@ class WCGatewayModule implements ModuleInterface {
$methods[] = $container->get( 'wcgateway.card-button-gateway' );
}
if ( 'DE' === $container->get( 'api.shop.country' ) ) {
$pui_product_status = $container->get( 'wcgateway.pay-upon-invoice-product-status' );
assert( $pui_product_status instanceof PayUponInvoiceProductStatus );
$shop_country = $container->get( 'api.shop.country' );
if ( 'DE' === $shop_country &&
( $is_our_page ||
( $is_gateways_list_page && $pui_product_status->pui_is_active() ) ||
( $settings->has( 'products_pui_enabled' ) && $settings->get( 'products_pui_enabled' ) )
)
) {
$methods[] = $container->get( 'wcgateway.pay-upon-invoice-gateway' );
}
if ( defined( 'PPCP_FLAG_OXXO' ) && PPCP_FLAG_OXXO === true ) {
if ( defined( 'PPCP_FLAG_OXXO' ) && PPCP_FLAG_OXXO === true && 'MX' === $shop_country ) {
$methods[] = $container->get( 'wcgateway.oxxo-gateway' );
}
@ -349,6 +387,7 @@ class WCGatewayModule implements ModuleInterface {
*/
$listener->listen_for_merchant_id();
$listener->listen_for_vaulting_enabled();
$listener->listen_for_tracking_enabled();
}
);