Merge branch 'trunk' into PCP-2815-allow-shipping-callback-and-skipping-confirmation-page-from-any-express-button

# Conflicts:
#	modules/ppcp-wc-gateway/resources/css/common.scss
This commit is contained in:
Narek Zakarian 2024-05-14 18:13:14 +04:00
commit 7f112b7759
No known key found for this signature in database
GPG key ID: 07AFD7E7A9C164A7
48 changed files with 1074 additions and 218 deletions

1
.gitignore vendored
View file

@ -6,6 +6,7 @@ node_modules
yarn-error.log
modules/*/vendor/*
modules/*/assets/*
!modules/ppcp-wc-gateway/assets/images
*.zip
.env
.env.e2e

View file

@ -1,5 +1,12 @@
*** Changelog ***
= 2.7.1 - xxxx-xx-xx =
* Fix - Ensure package tracking data is sent to original PayPal transaction #2180
* Fix - Set the 'Woo_PPCP' as a default value for data-partner-attribution-id #2188
* Fix - Allow PUI Gateway for refund processor #2192
* Fix - Notice on newly created block cart checkout #2211
* Fix - Apple Pay button in the editor #2177
= 2.7.0 - 2024-04-30 =
* Fix - Zero sum subscriptions cause CANNOT_BE_ZERO_OR_NEGATIVE when using Vault v3 #2152
* Fix - Incorrect Pricing Issue with Variable Subscriptions in PayPal Subscriptions Mode #2156

View file

@ -155,11 +155,11 @@ class PayPalApiException extends RuntimeException {
return $json->message;
}
$improved_keys_messages = array(
'PAYMENT_DENIED' => __( 'PayPal rejected the payment. Please reach out to the PayPal support for more information.', 'woocommerce-paypal-payments' ),
'TRANSACTION_REFUSED' => __( 'The transaction has been refused by the payment processor. Please reach out to the PayPal support for more information.', 'woocommerce-paypal-payments' ),
'DUPLICATE_INVOICE_ID' => __( 'The transaction has been refused because the Invoice ID already exists. Please create a new order or reach out to the store owner.', 'woocommerce-paypal-payments' ),
'PAYER_CANNOT_PAY' => __( 'There was a problem processing this transaction. Please reach out to the store owner.', 'woocommerce-paypal-payments' ),
'PAYEE_ACCOUNT_RESTRICTED' => __( 'There was a problem processing this transaction. Please reach out to the store owner.', 'woocommerce-paypal-payments' ),
'PAYMENT_DENIED' => __( 'PayPal rejected the payment. Please reach out to the PayPal support for more information.', 'woocommerce-paypal-payments' ),
'TRANSACTION_REFUSED' => __( 'The transaction has been refused by the payment processor. Please reach out to the PayPal support for more information.', 'woocommerce-paypal-payments' ),
'DUPLICATE_INVOICE_ID' => __( 'The transaction has been refused because the Invoice ID already exists. Please create a new order or reach out to the store owner.', 'woocommerce-paypal-payments' ),
'PAYER_CANNOT_PAY' => __( 'There was a problem processing this transaction. Please reach out to the store owner.', 'woocommerce-paypal-payments' ),
'PAYEE_ACCOUNT_RESTRICTED' => __( 'There was a problem processing this transaction. Please reach out to the store owner.', 'woocommerce-paypal-payments' ),
'AGREEMENT_ALREADY_CANCELLED' => __( 'The requested agreement is already canceled. Please reach out to the PayPal support for more information.', 'woocommerce-paypal-payments' ),
);
$improved_errors = array_filter(

View file

@ -46,4 +46,10 @@
}
}
}
.ppcp-button-applepay {
apple-pay-button {
display: block;
}
}
}

View file

@ -0,0 +1,36 @@
import ApplepayButton from "./ApplepayButton";
class ApplepayManagerBlockEditor {
constructor(buttonConfig, ppcpConfig) {
this.buttonConfig = buttonConfig;
this.ppcpConfig = ppcpConfig;
this.applePayConfig = null;
}
init() {
(async () => {
await this.config();
})();
}
async config() {
try {
this.applePayConfig = await paypal.Applepay().config();
const button = new ApplepayButton(
this.ppcpConfig.context,
null,
this.buttonConfig,
this.ppcpConfig,
);
button.init(this.applePayConfig);
} catch (error) {
console.error('Failed to initialize Apple Pay:', error);
}
}
}
export default ApplepayManagerBlockEditor;

View file

@ -2,9 +2,10 @@ import {useEffect, useState} from '@wordpress/element';
import {registerExpressPaymentMethod} from '@woocommerce/blocks-registry';
import {loadPaypalScript} from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'
import {cartHasSubscriptionProducts} from '../../../ppcp-blocks/resources/js/Helper/Subscription'
import ApplepayManager from "./ApplepayManager";
import {loadCustomScript} from "@paypal/paypal-js";
import CheckoutHandler from "./Context/CheckoutHandler";
import ApplepayManager from "./ApplepayManager";
import ApplepayManagerBlockEditor from "./ApplepayManagerBlockEditor";
const ppcpData = wc.wcSettings.getSetting('ppcp-gateway_data');
const ppcpConfig = ppcpData.scriptData;
@ -16,13 +17,14 @@ if (typeof window.PayPalCommerceGateway === 'undefined') {
window.PayPalCommerceGateway = ppcpConfig;
}
const ApplePayComponent = () => {
const ApplePayComponent = ( props ) => {
const [bootstrapped, setBootstrapped] = useState(false);
const [paypalLoaded, setPaypalLoaded] = useState(false);
const [applePayLoaded, setApplePayLoaded] = useState(false);
const bootstrap = function () {
const manager = new ApplepayManager(buttonConfig, ppcpConfig);
const ManagerClass = props.isEditing ? ApplepayManagerBlockEditor : ApplepayManager;
const manager = new ManagerClass(buttonConfig, ppcpConfig);
manager.init();
};
@ -32,6 +34,8 @@ const ApplePayComponent = () => {
setApplePayLoaded(true);
});
ppcpConfig.url_params.components += ',applepay';
// Load PayPal
loadPaypalScript(ppcpConfig, () => {
setPaypalLoaded(true);
@ -46,7 +50,10 @@ const ApplePayComponent = () => {
}, [paypalLoaded, applePayLoaded]);
return (
<div id={buttonConfig.button.wrapper.replace('#', '')} className="ppcp-button-apm ppcp-button-applepay"></div>
<div
id={buttonConfig.button.wrapper.replace('#', '')}
className="ppcp-button-apm ppcp-button-applepay">
</div>
);
}

View file

@ -92,6 +92,7 @@ class ApplepayModule implements ModuleInterface {
}
$module->load_admin_assets( $c, $apple_payment_method );
$module->load_block_editor_assets( $c, $apple_payment_method );
},
1
);
@ -177,6 +178,13 @@ class ApplepayModule implements ModuleInterface {
}
}
);
add_action(
'enqueue_block_editor_assets',
function () use ( $c, $button ) {
$button->enqueue_admin_styles();
}
);
add_action(
'woocommerce_blocks_payment_method_type_registration',
function( PaymentMethodRegistry $payment_method_registry ) use ( $c ): void {
@ -207,6 +215,7 @@ class ApplepayModule implements ModuleInterface {
* @psalm-suppress UndefinedInterfaceMethod
*/
$button->enqueue_admin();
$button->enqueue_admin_styles();
}
);
@ -222,6 +231,28 @@ class ApplepayModule implements ModuleInterface {
);
}
/**
* Enqueues the editor assets.
*
* @param ContainerInterface $c The container.
* @param ApplePayButton $button The button.
* @return void
*/
public function load_block_editor_assets( ContainerInterface $c, ApplePayButton $button ): void {
// Enqueue backend scripts.
add_action(
'enqueue_block_editor_assets',
static function () use ( $c, $button ) {
/**
* Should add this to the ButtonInterface.
*
* @psalm-suppress UndefinedInterfaceMethod
*/
$button->enqueue_admin_styles();
}
);
}
/**
* Renders the Apple Pay buttons in the enabled places.
*

View file

@ -1044,17 +1044,9 @@ class ApplePayButton implements ButtonInterface {
}
/**
* Enqueues scripts/styles for admin.
* Enqueues scripts for admin.
*/
public function enqueue_admin(): void {
wp_register_style(
'wc-ppcp-applepay-admin',
untrailingslashit( $this->module_url ) . '/assets/css/styles.css',
array(),
$this->version
);
wp_enqueue_style( 'wc-ppcp-applepay-admin' );
wp_register_script(
'wc-ppcp-applepay-admin',
untrailingslashit( $this->module_url ) . '/assets/js/boot-admin.js',
@ -1071,6 +1063,19 @@ class ApplePayButton implements ButtonInterface {
);
}
/**
* Enqueues styles for admin.
*/
public function enqueue_admin_styles(): void {
wp_register_style(
'wc-ppcp-applepay-admin',
untrailingslashit( $this->module_url ) . '/assets/css/styles.css',
array(),
$this->version
);
wp_enqueue_style( 'wc-ppcp-applepay-admin' );
}
/**
* Returns the script data.
*

View file

@ -103,12 +103,18 @@ class BlocksPaymentMethod extends AbstractPaymentMethodType {
public function get_payment_method_data() {
$paypal_data = $this->paypal_payment_method->get_payment_method_data();
if ( is_admin() ) {
$script_data = $this->button->script_data_for_admin();
} else {
$script_data = $this->button->script_data();
}
return array(
'id' => $this->name,
'title' => $paypal_data['title'], // TODO : see if we should use another.
'description' => $paypal_data['description'], // TODO : see if we should use another.
'enabled' => $paypal_data['enabled'], // This button is enabled when PayPal buttons are.
'scriptData' => $this->button->script_data(),
'scriptData' => $script_data,
);
}
}

View file

@ -9,6 +9,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Axo;
use WooCommerce\PayPalCommerce\Axo\Helper\NoticeRenderer;
use WooCommerce\PayPalCommerce\Axo\Helper\PropertiesDictionary;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
@ -69,7 +70,7 @@ return array(
'type' => 'checkbox',
'label' => __( 'Enable Fastlane by PayPal', 'woocommerce-paypal-payments' )
. '<p class="description">'
. __( 'Help accelerate checkout for guests with PayPal\'s autofill solution.', 'woocommerce-paypal-payments' )
. __( 'Help accelerate the checkout process for guests with PayPal\'s autofill solution. When enabled, Fastlane is presented as the default payment method for guests.', 'woocommerce-paypal-payments' )
. '</p>',
'default' => 'yes',
'screens' => array( State::STATE_ONBOARDED ),
@ -82,7 +83,9 @@ return array(
->rule()
->condition_element( 'axo_enabled', '1' )
->action_visible( 'axo_gateway_title' )
->action_visible( 'axo_checkout_config_notice' )
->action_visible( 'axo_privacy' )
->action_visible( 'axo_name_on_card' )
->action_visible( 'axo_style_heading' )
->action_class( 'axo_enabled', 'active' )
->to_array(),
@ -94,6 +97,7 @@ return array(
->action_visible( 'axo_style_root_bg_color' )
->action_visible( 'axo_style_root_error_color' )
->action_visible( 'axo_style_root_font_family' )
->action_visible( 'axo_style_root_text_color_base' )
->action_visible( 'axo_style_root_font_size_base' )
->action_visible( 'axo_style_root_padding' )
->action_visible( 'axo_style_root_primary_color' )
@ -110,6 +114,18 @@ return array(
),
'classes' => array( 'ppcp-valign-label-middle', 'ppcp-align-label-center' ),
),
'axo_checkout_config_notice' => array(
'heading' => '',
'html' => $container->get( 'axo.checkout-config-notice' ),
'type' => 'ppcp-html',
'classes' => array( 'ppcp-field-indent' ),
'class' => array(),
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'dcc', 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_gateway_title' => array(
'title' => __( 'Gateway Title', 'woocommerce-paypal-payments' ),
'type' => 'text',
@ -133,7 +149,7 @@ return array(
'title' => __( 'Privacy', 'woocommerce-paypal-payments' ),
'type' => 'select',
'label' => __(
'Require customers to confirm express payments from the Cart and Express Checkout on the checkout page.
'This setting will control whether Fastlane branding is shown by email field.
<p class="description">PayPal powers this accelerated checkout solution from Fastlane. Since you\'ll share consumers\' email addresses with PayPal, please consult your legal advisors on the apropriate privacy setting for your business.</p>',
'woocommerce-paypal-payments'
),
@ -151,6 +167,17 @@ return array(
'gateway' => array( 'dcc', 'axo' ),
'requirements' => array( 'axo' ),
),
'axo_name_on_card' => array(
'title' => __( 'Display Name on Card', 'woocommerce-paypal-payments' ),
'type' => 'checkbox',
'default' => 'yes',
'classes' => array( 'ppcp-field-indent' ),
'class' => array(),
'label' => __( 'Enable this to display the "Name on Card" field for new Fastlane buyers.', 'woocommerce-paypal-payments' ),
'screens' => array( State::STATE_ONBOARDED ),
'gateway' => array( 'dcc', 'axo' ),
'requirements' => array( 'axo' ),
),
'axo_style_heading' => array(
'heading' => __( 'Advanced Style Settings (optional)', 'woocommerce-paypal-payments' ),
'heading_html' => sprintf(
@ -200,52 +227,9 @@ return array(
'axo_style_root_bg_color' => array(
'title' => __( 'Background Color', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '#ffffff',
'classes' => array( 'ppcp-field-indent' ),
'default' => '#ffffff',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_style_root_error_color' => array(
'title' => __( 'Error Color', 'woocommerce-paypal-payments' ),
'type' => 'text',
'classes' => array( 'ppcp-field-indent' ),
'default' => '#d9360b',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_style_root_font_family' => array(
'title' => __( 'Font Family', 'woocommerce-paypal-payments' ),
'type' => 'text',
'classes' => array( 'ppcp-field-indent' ),
'default' => 'PayPal Open',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_style_root_font_size_base' => array(
'title' => __( 'Font Size Base', 'woocommerce-paypal-payments' ),
'type' => 'text',
'classes' => array( 'ppcp-field-indent' ),
'default' => '16px',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_style_root_padding' => array(
'title' => __( 'Padding', 'woocommerce-paypal-payments' ),
'type' => 'text',
'classes' => array( 'ppcp-field-indent' ),
'default' => '4px',
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
@ -255,8 +239,69 @@ return array(
'axo_style_root_primary_color' => array(
'title' => __( 'Primary Color', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '#0057F',
'classes' => array( 'ppcp-field-indent' ),
'default' => '#0057ff',
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_style_root_error_color' => array(
'title' => __( 'Error Color', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '#D9360B',
'classes' => array( 'ppcp-field-indent' ),
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_style_root_font_family' => array(
'title' => __( 'Font Family', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => 'PayPal-Open',
'classes' => array( 'ppcp-field-indent' ),
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_style_root_text_color_base' => array(
'title' => __( 'Text Color Base', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '#010B0D',
'classes' => array( 'ppcp-field-indent' ),
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_style_root_font_size_base' => array(
'title' => __( 'Font Size Base', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '16px',
'classes' => array( 'ppcp-field-indent' ),
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array( 'axo' ),
'gateway' => array( 'dcc', 'axo' ),
),
'axo_style_root_padding' => array(
'title' => __( 'Padding', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '4px',
'classes' => array( 'ppcp-field-indent' ),
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
@ -278,8 +323,9 @@ return array(
'axo_style_input_bg_color' => array(
'title' => __( 'Background Color', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '#ffffff',
'classes' => array( 'ppcp-field-indent' ),
'default' => '#ffffff',
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
@ -289,8 +335,9 @@ return array(
'axo_style_input_border_radius' => array(
'title' => __( 'Border Radius', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '0.25em',
'classes' => array( 'ppcp-field-indent' ),
'default' => '0.25em',
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
@ -300,8 +347,9 @@ return array(
'axo_style_input_border_color' => array(
'title' => __( 'Border Color', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '#DADDDD',
'classes' => array( 'ppcp-field-indent' ),
'default' => '#dadddd',
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
@ -311,8 +359,9 @@ return array(
'axo_style_input_border_width' => array(
'title' => __( 'Border Width', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '1px',
'classes' => array( 'ppcp-field-indent' ),
'default' => '1px',
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
@ -322,8 +371,9 @@ return array(
'axo_style_input_text_color_base' => array(
'title' => __( 'Text Color Base', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '#010B0D',
'classes' => array( 'ppcp-field-indent' ),
'default' => '#010b0d',
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),
@ -333,8 +383,9 @@ return array(
'axo_style_input_focus_border_color' => array(
'title' => __( 'Focus Border Color', 'woocommerce-paypal-payments' ),
'type' => 'text',
'placeholder' => '#0057FF',
'classes' => array( 'ppcp-field-indent' ),
'default' => '#0057ff',
'default' => '',
'screens' => array(
State::STATE_ONBOARDED,
),

View file

@ -1,13 +1,3 @@
.ppcp-axo-card-icons {
padding: 4px 0 16px 25px;
.ppcp-card-icon {
float: left !important;
max-height: 25px;
}
}
.ppcp-axo-watermark-container {
max-width: 200px;
margin-top: 10px;
@ -17,7 +7,7 @@
padding: 1rem 0;
background-color: #ffffff;
&.hidden {
&.axo-hidden {
display: none;
}
}
@ -53,3 +43,14 @@
margin: var(--global-md-spacing) 0 1em;
padding: 0.6em 1em;
}
#payment .payment_methods li label[for="payment_method_ppcp-axo-gateway"] {
img {
float: none;
vertical-align: middle;
}
.ppcp-card-icon {
max-height: 25px;
}
}

View file

@ -34,8 +34,12 @@ class AxoManager {
card: null,
};
this.states = this.axoConfig.woocommerce.states;
this.el = new DomElementCollection();
this.emailInput = document.querySelector(this.el.fieldBillingEmail.selector + ' input');
this.styles = {
root: {
backgroundColorPrimary: '#ffffff'
@ -46,7 +50,7 @@ class AxoManager {
this.registerEventHandlers();
this.shippingView = new ShippingView(this.el.shippingAddressContainer.selector, this.el);
this.shippingView = new ShippingView(this.el.shippingAddressContainer.selector, this.el, this.states );
this.billingView = new BillingView(this.el.billingAddressContainer.selector, this.el);
this.cardView = new CardView(this.el.paymentContainer.selector + '-details', this.el, this);
@ -160,6 +164,29 @@ class AxoManager {
this.$('form.woocommerce-checkout input').on('keydown', async (ev) => {
if(ev.key === 'Enter' && getCurrentPaymentMethod() === 'ppcp-axo-gateway' ) {
ev.preventDefault();
log('Enter key attempt');
log('emailInput', this.emailInput.value);
log('this.lastEmailCheckedIdentity', this.lastEmailCheckedIdentity);
if (this.emailInput && this.lastEmailCheckedIdentity !== this.emailInput.value) {
await this.onChangeEmail();
}
}
});
// Clear last email checked identity when email field is focused.
this.$('#billing_email_field input').on('focus', (ev) => {
log('Clear the last email checked:', this.lastEmailCheckedIdentity);
this.lastEmailCheckedIdentity = '';
});
// Listening to status update event
document.addEventListener('axo_status_updated', (ev) => {
const termsField = document.querySelector("[name='terms-field']");
if(termsField) {
const status = ev.detail;
const shouldHide = status.active && status.validEmail === false && status.hasProfile === false;
termsField.parentElement.style.display = shouldHide ? 'none' : 'block';
}
});
}
@ -347,6 +374,8 @@ class AxoManager {
log('Status updated', JSON.parse(JSON.stringify(this.status)));
document.dispatchEvent(new CustomEvent("axo_status_updated", {detail: this.status}));
this.rerender();
}
@ -355,8 +384,10 @@ class AxoManager {
this.initFastlane();
this.setStatus('active', true);
const emailInput = document.querySelector(this.el.fieldBillingEmail.selector + ' input');
if (emailInput && this.lastEmailCheckedIdentity !== emailInput.value) {
log('Attempt on activation');
log('emailInput', this.emailInput.value);
log('this.lastEmailCheckedIdentity', this.lastEmailCheckedIdentity);
if (this.emailInput && this.lastEmailCheckedIdentity !== this.emailInput.value) {
this.onChangeEmail();
}
}
@ -396,7 +427,6 @@ class AxoManager {
// Watermark container
const wc = this.el.watermarkContainer;
if (!document.querySelector(wc.selector)) {
this.emailInput = document.querySelector(this.el.fieldBillingEmail.selector + ' input');
this.emailInput.insertAdjacentHTML('afterend', `
<div class="${wc.className}" id="${wc.id}"></div>
`);
@ -407,7 +437,7 @@ class AxoManager {
if (!document.querySelector(pc.selector)) {
const gatewayPaymentContainer = document.querySelector('.payment_method_ppcp-axo-gateway');
gatewayPaymentContainer.insertAdjacentHTML('beforeend', `
<div id="${pc.id}" class="${pc.className} hidden">
<div id="${pc.id}" class="${pc.className} axo-hidden">
<div id="${pc.id}-form" class="${pc.className}-form"></div>
<div id="${pc.id}-details" class="${pc.className}-details"></div>
</div>
@ -431,7 +461,6 @@ class AxoManager {
// Move email to the AXO container.
let emailRow = document.querySelector(this.el.fieldBillingEmail.selector);
wrapperElement.prepend(emailRow);
emailRow.querySelector('input').focus();
}
}
@ -463,9 +492,9 @@ class AxoManager {
this.el.gatewayRadioButton.trigger('change');
}
async renderWatermark() {
async renderWatermark(includeAdditionalInfo = true) {
(await this.fastlane.FastlaneWatermarkComponent({
includeAdditionalInfo: true
includeAdditionalInfo
})).render(this.el.watermarkContainer.selector);
}
@ -476,12 +505,18 @@ class AxoManager {
// TODO
} else {
this.emailInput = document.querySelector(this.el.fieldBillingEmail.selector + ' input');
this.emailInput.addEventListener('change', async ()=> {
this.onChangeEmail();
log('Change event attempt');
log('emailInput', this.emailInput.value);
log('this.lastEmailCheckedIdentity', this.lastEmailCheckedIdentity);
if (this.emailInput && this.lastEmailCheckedIdentity !== this.emailInput.value) {
this.onChangeEmail();
}
});
log('Last, this.emailInput.value attempt');
log('emailInput', this.emailInput.value);
log('this.lastEmailCheckedIdentity', this.lastEmailCheckedIdentity);
if (this.emailInput.value) {
this.onChangeEmail();
}
@ -548,13 +583,25 @@ class AxoManager {
if (authResponse.authenticationState === 'succeeded') {
log(JSON.stringify(authResponse));
// Add addresses
this.setShipping(authResponse.profileData.shippingAddress);
this.setBilling({
address: authResponse.profileData.card.paymentSource.card.billingAddress,
phoneNumber: authResponse.profileData.shippingAddress.phoneNumber.nationalNumber ?? ''
});
this.setCard(authResponse.profileData.card);
const shippingData = authResponse.profileData.shippingAddress;
if(shippingData) {
this.setShipping(shippingData);
}
const cardBillingAddress = authResponse.profileData?.card?.paymentSource?.card?.billingAddress;
if(cardBillingAddress) {
this.setCard(authResponse.profileData.card);
const billingData = {
address: cardBillingAddress,
};
const phoneNumber = authResponse.profileData?.shippingAddress?.phoneNumber?.nationalNumber ?? '';
if(phoneNumber) {
billingData.phoneNumber = phoneNumber
}
this.setBilling(billingData);
}
this.setStatus('validEmail', true);
this.setStatus('hasProfile', true);
@ -562,11 +609,23 @@ class AxoManager {
this.hideGatewaySelection = true;
this.$('.wc_payment_methods label').hide();
await this.renderWatermark(false);
this.rerender();
} else {
// authentication failed or canceled by the customer
// set status as guest customer
log("Authentication Failed")
this.setStatus('validEmail', true);
this.setStatus('hasProfile', false);
await this.renderWatermark(true);
this.cardComponent = (await this.fastlane.FastlaneCardComponent(
this.cardComponentData()
)).render(this.el.paymentContainer.selector + '-form');
}
} else {
@ -577,6 +636,8 @@ class AxoManager {
this.setStatus('validEmail', true);
this.setStatus('hasProfile', false);
await this.renderWatermark(true);
this.cardComponent = (await this.fastlane.FastlaneCardComponent(
this.cardComponentData()
)).render(this.el.paymentContainer.selector + '-form');
@ -620,6 +681,8 @@ class AxoManager {
this.shippingView.toSubmitData(data);
this.cardView.toSubmitData(data);
this.ensureBillingPhoneNumber(data);
this.submit(this.data.card.id, data);
} else { // Gary flow
@ -641,8 +704,11 @@ class AxoManager {
cardComponentData() {
return {
fields: {
cardholderName: {} // optionally pass this to show the card holder name
}
cardholderName: {
enabled: this.axoConfig.name_on_card === '1'
}
},
styles: this.deleteKeysWithEmptyString(this.axoConfig.style_options)
}
}
@ -654,8 +720,8 @@ class AxoManager {
billingAddress: {
addressLine1: this.billingView.inputValue('street1'),
addressLine2: this.billingView.inputValue('street2'),
adminArea1: this.billingView.inputValue('city'),
adminArea2: this.billingView.inputValue('stateCode'),
adminArea1: this.billingView.inputValue('stateCode'),
adminArea2: this.billingView.inputValue('city'),
postalCode: this.billingView.inputValue('postCode'),
countryCode: this.billingView.inputValue('countryCode'),
}
@ -693,6 +759,9 @@ class AxoManager {
formData.set(key, data[key]);
});
// Set type of user (Ryan) to be received on WC gateway process payment request.
formData.set('fastlane_member', true);
fetch(wc_checkout_params.checkout_url, { // TODO: maybe create a new endpoint to process_payment.
method: "POST",
body: formData
@ -743,6 +812,34 @@ class AxoManager {
return this.axoConfig?.widgets?.email === 'use_widget';
}
deleteKeysWithEmptyString = (obj) => {
for(let key of Object.keys(obj)){
if (obj[key] === ''){
delete obj[key];
}
else if (typeof obj[key] === 'object'){
obj[key] = this.deleteKeysWithEmptyString(obj[key]);
if (Object.keys(obj[key]).length === 0 ) delete obj[key];
}
}
return Array.isArray(obj) ? obj.filter(val => val) : obj;
}
ensureBillingPhoneNumber(data) {
if (data.billing_phone === '') {
let phone = '';
const cc = this.data?.shipping?.phoneNumber?.countryCode;
const number = this.data?.shipping?.phoneNumber?.nationalNumber;
if (cc) {
phone = `+${cc} `;
}
phone += number;
data.billing_phone = phone;
}
}
}
export default AxoManager;

View file

@ -32,10 +32,13 @@ class CardView {
const expiry = data.value('expiry').split('-');
const cardIcons = {
'VISA': 'visa-dark.svg',
'MASTER_CARD': 'mastercard-dark.svg',
'VISA': 'visa-light.svg',
'MASTER_CARD': 'mastercard-light.svg',
'AMEX': 'amex.svg',
'DISCOVER': 'discover.svg',
'DINERS': 'dinersclub-light.svg',
'JCB': 'jcb-light.svg',
'UNIONPAY': 'unionpay-light.svg',
};
return `
@ -49,7 +52,7 @@ class CardView {
<img
class="ppcp-card-icon"
title="${data.value('brand')}"
src="/wp-content/plugins/woocommerce-paypal-payments/modules/ppcp-wc-gateway/assets/images/${cardIcons[data.value('brand')]}"
src="${window.wc_ppcp_axo.module_url}/assets/images/axo/${cardIcons[data.value('brand')]}"
alt="${data.value('brand')}"
>
</div>

View file

@ -2,9 +2,9 @@ import FormFieldGroup from "../Components/FormFieldGroup";
class ShippingView {
constructor(selector, elements) {
constructor(selector, elements, states) {
this.el = elements;
this.states = states;
this.group = new FormFieldGroup({
baseSelector: '.woocommerce-checkout',
contentSelector: selector,
@ -34,6 +34,24 @@ class ShippingView {
</div>
`;
}
const countryCode = data.value('countryCode');
const stateCode = data.value('stateCode');
const stateName = (this.states[countryCode] && this.states[countryCode][stateCode]) ? this.states[countryCode][stateCode] : stateCode;
if(
this.hasEmptyValues(data, stateName)
) {
return `
<div style="margin-bottom: 20px;">
<div class="axo-checkout-header-section">
<h3>Shipping</h3>
<a href="javascript:void(0)" ${this.el.changeShippingAddressLink.attributes}>Edit</a>
</div>
<div>Please fill in your shipping details.</div>
</div>
`;
}
return `
<div style="margin-bottom: 20px;">
<div class="axo-checkout-header-section">
@ -45,9 +63,8 @@ class ShippingView {
<div>${data.value('firstName')} ${data.value('lastName')}</div>
<div>${data.value('street1')}</div>
<div>${data.value('street2')}</div>
<div>${data.value('postCode')} ${data.value('city')}</div>
<div>${valueOfSelect('#shipping_state', data.value('stateCode'))}</div>
<div>${valueOfSelect('#shipping_country', data.value('countryCode'))}</div>
<div>${data.value('city')}, ${stateName} ${data.value('postCode')}</div>
<div>${valueOfSelect('#billing_country', countryCode)}</div>
<div>${data.value('phone')}</div>
</div>
`;
@ -115,6 +132,15 @@ class ShippingView {
});
}
hasEmptyValues(data, stateName) {
return !data.value('email')
|| !data.value('firstName')
|| !data.value('lastName')
|| !data.value('street1')
|| !data.value('city')
|| !stateName;
}
isActive() {
return this.group.active;
}

View file

@ -13,6 +13,7 @@ use WooCommerce\PayPalCommerce\Axo\Assets\AxoManager;
use WooCommerce\PayPalCommerce\Axo\Gateway\AxoGateway;
use WooCommerce\PayPalCommerce\Axo\Helper\ApmApplies;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Helper\CartCheckoutDetector;
return array(
@ -68,6 +69,7 @@ return array(
$container->get( 'wcgateway.url' ),
$container->get( 'wcgateway.order-processor' ),
$container->get( 'axo.card_icons' ),
$container->get( 'axo.card_icons.axo' ),
$container->get( 'api.endpoint.order' ),
$container->get( 'api.factory.purchase-unit' ),
$container->get( 'api.factory.shipping-preference' ),
@ -98,6 +100,39 @@ return array(
);
},
'axo.card_icons.axo' => static function ( ContainerInterface $container ): array {
return array(
array(
'title' => 'Visa',
'file' => 'visa-light.svg',
),
array(
'title' => 'MasterCard',
'file' => 'mastercard-light.svg',
),
array(
'title' => 'Amex',
'file' => 'amex-light.svg',
),
array(
'title' => 'Discover',
'file' => 'discover-light.svg',
),
array(
'title' => 'Diners Club',
'file' => 'dinersclub-light.svg',
),
array(
'title' => 'JCB',
'file' => 'jcb-light.svg',
),
array(
'title' => 'UnionPay',
'file' => 'unionpay-light.svg',
),
);
},
/**
* The matrix which countries and currency combinations can be used for AXO.
*/
@ -115,4 +150,47 @@ return array(
);
},
'axo.checkout-config-notice' => static function ( ContainerInterface $container ) : string {
$checkout_page_link = esc_url( get_edit_post_link( wc_get_page_id( 'checkout' ) ) ?? '' );
$block_checkout_docs_link = __(
'https://woocommerce.com/document/cart-checkout-blocks-status/#reverting-to-the-cart-and-checkout-shortcodes',
'woocommerce-paypal-payments'
);
if ( CartCheckoutDetector::has_elementor_checkout() ) {
$notice_content = sprintf(
/* translators: %1$s: URL to the Checkout edit page. %2$s: URL to the block checkout docs. */
__(
'<span class="highlight">Warning:</span> The <a href="%1$s">Checkout page</a> of your store currently uses the <code>Elementor Checkout widget</code>. To enable Fastlane and accelerate payments, the page must include either the <code>Classic Checkout</code> or the <code>[woocommerce_checkout]</code> shortcode. See <a href="%2$s">this page</a> for instructions on how to switch to the classic layout.',
'woocommerce-paypal-payments'
),
esc_url( $checkout_page_link ),
esc_url( $block_checkout_docs_link )
);
} elseif ( CartCheckoutDetector::has_block_checkout() ) {
$notice_content = sprintf(
/* translators: %1$s: URL to the Checkout edit page. %2$s: URL to the block checkout docs. */
__(
'<span class="highlight">Warning:</span> The <a href="%1$s">Checkout page</a> of your store currently uses the WooCommerce <code>Checkout</code> block. To enable Fastlane and accelerate payments, the page must include either the <code>Classic Checkout</code> or the <code>[woocommerce_checkout]</code> shortcode. See <a href="%2$s">this page</a> for instructions on how to switch to the classic layout.',
'woocommerce-paypal-payments'
),
esc_url( $checkout_page_link ),
esc_url( $block_checkout_docs_link )
);
} elseif ( ! CartCheckoutDetector::has_classic_checkout() ) {
$notice_content = sprintf(
/* translators: %1$s: URL to the Checkout edit page. %2$s: URL to the block checkout docs. */
__(
'<span class="highlight">Warning:</span> The <a href="%1$s">Checkout page</a> of your store does not seem to be properly configured or uses an incompatible <code>third-party Checkout</code> solution. To enable Fastlane and accelerate payments, the page must include either the <code>Classic Checkout</code> or the <code>[woocommerce_checkout]</code> shortcode. See <a href="%2$s">this page</a> for instructions on how to switch to the classic layout.',
'woocommerce-paypal-payments'
),
esc_url( $checkout_page_link ),
esc_url( $block_checkout_docs_link )
);
} else {
return '';
}
return '<div class="ppcp-notice ppcp-notice-warning"><p>' . $notice_content . '</p></div>';
},
);

View file

@ -151,13 +151,13 @@ class AxoManager {
*/
private function script_data() {
return array(
'environment' => array(
'environment' => array(
'is_sandbox' => $this->environment->current_environment() === 'sandbox',
),
'widgets' => array(
'widgets' => array(
'email' => 'render',
),
'insights' => array(
'insights' => array(
'enabled' => true,
'client_id' => ( $this->settings->has( 'client_id' ) ? $this->settings->get( 'client_id' ) : null ),
'session_id' =>
@ -171,6 +171,33 @@ class AxoManager {
'value' => WC()->cart->get_total( 'numeric' ),
),
),
'style_options' => array(
'root' => array(
'backgroundColor' => $this->settings->has( 'axo_style_root_bg_color' ) ? $this->settings->get( 'axo_style_root_bg_color' ) : '',
'errorColor' => $this->settings->has( 'axo_style_root_error_color' ) ? $this->settings->get( 'axo_style_root_error_color' ) : '',
'fontFamily' => $this->settings->has( 'axo_style_root_font_family' ) ? $this->settings->get( 'axo_style_root_font_family' ) : '',
'textColorBase' => $this->settings->has( 'axo_style_root_text_color_base' ) ? $this->settings->get( 'axo_style_root_text_color_base' ) : '',
'fontSizeBase' => $this->settings->has( 'axo_style_root_font_size_base' ) ? $this->settings->get( 'axo_style_root_font_size_base' ) : '',
'padding' => $this->settings->has( 'axo_style_root_padding' ) ? $this->settings->get( 'axo_style_root_padding' ) : '',
'primaryColor' => $this->settings->has( 'axo_style_root_primary_color' ) ? $this->settings->get( 'axo_style_root_primary_color' ) : '',
),
'input' => array(
'backgroundColor' => $this->settings->has( 'axo_style_input_bg_color' ) ? $this->settings->get( 'axo_style_input_bg_color' ) : '',
'borderRadius' => $this->settings->has( 'axo_style_input_border_radius' ) ? $this->settings->get( 'axo_style_input_border_radius' ) : '',
'borderColor' => $this->settings->has( 'axo_style_input_border_color' ) ? $this->settings->get( 'axo_style_input_border_color' ) : '',
'borderWidth' => $this->settings->has( 'axo_style_input_border_width' ) ? $this->settings->get( 'axo_style_input_border_width' ) : '',
'textColorBase' => $this->settings->has( 'axo_style_input_text_color_base' ) ? $this->settings->get( 'axo_style_input_text_color_base' ) : '',
'focusBorderColor' => $this->settings->has( 'axo_style_input_focus_border_color' ) ? $this->settings->get( 'axo_style_input_focus_border_color' ) : '',
),
),
'name_on_card' => $this->settings->has( 'axo_name_on_card' ) ? $this->settings->get( 'axo_name_on_card' ) : '',
'woocommerce' => array(
'states' => array(
'US' => WC()->countries->get_states( 'US' ),
'CA' => WC()->countries->get_states( 'CA' ),
),
),
'module_url' => untrailingslashit( $this->module_url ),
);
}

View file

@ -14,12 +14,16 @@ use WooCommerce\PayPalCommerce\ApiClient\Authentication\SdkClientToken;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Axo\Assets\AxoManager;
use WooCommerce\PayPalCommerce\Axo\Gateway\AxoGateway;
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Helper\CartCheckoutDetector;
/**
* Class AxoModule
@ -77,9 +81,36 @@ class AxoModule implements ModuleInterface {
9
);
// Hides credit card gateway on checkout when using Fastlane.
add_filter(
'woocommerce_available_payment_gateways',
/**
* Param types removed to avoid third-party issues.
*
* @psalm-suppress MissingClosureParamType
*/
function ( $methods ) use ( $c ): array {
if ( ! is_array( $methods ) || ! $c->get( 'axo.eligible' ) ) {
return $methods;
}
$settings = $c->get( 'wcgateway.settings' );
assert( $settings instanceof Settings );
if ( apply_filters(
'woocommerce_paypal_payments_axo_hide_credit_card_gateway',
$this->hide_credit_card_when_using_fastlane( $methods, $settings )
) ) {
unset( $methods[ CreditCardGateway::ID ] );
}
return $methods;
}
);
add_action(
'init',
static function () use ( $c, $module ) {
function () use ( $c, $module ) {
// Check if the module is applicable, correct country, currency, ... etc.
if ( ! $c->get( 'axo.eligible' ) ) {
@ -169,6 +200,19 @@ class AxoModule implements ModuleInterface {
2
);
// Set Axo as the default payment method on checkout for guest customers.
add_action(
'template_redirect',
function () use ( $c ) {
$settings = $c->get( 'wcgateway.settings' );
assert( $settings instanceof Settings );
if ( $this->should_render_fastlane( $settings ) ) {
WC()->session->set( 'chosen_payment_method', AxoGateway::ID );
}
}
);
},
1
);
@ -221,4 +265,31 @@ class AxoModule implements ModuleInterface {
*/
public function getKey() {
}
/**
* Condition to evaluate if Credit Card gateway should be hidden.
*
* @param array $methods WC payment methods.
* @param Settings $settings The settings.
* @return bool
*/
private function hide_credit_card_when_using_fastlane( array $methods, Settings $settings ): bool {
return $this->should_render_fastlane( $settings ) && isset( $methods[ CreditCardGateway::ID ] );
}
/**
* Condition to evaluate if Fastlane should be rendered.
*
* Fastlane should only render on the classic checkout, when Fastlane is enabled in the settings and also only for guest customers.
*
* @param Settings $settings The settings.
* @return bool
*/
private function should_render_fastlane( Settings $settings ): bool {
$is_axo_enabled = $settings->has( 'axo_enabled' ) && $settings->get( 'axo_enabled' ) ?? false;
return ! is_user_logged_in()
&& CartCheckoutDetector::has_classic_checkout()
&& $is_axo_enabled;
}
}

View file

@ -70,6 +70,13 @@ class AxoGateway extends WC_Payment_Gateway {
*/
protected $card_icons;
/**
* The AXO card icons.
*
* @var array
*/
protected $card_icons_axo;
/**
* The order endpoint.
*
@ -120,6 +127,7 @@ class AxoGateway extends WC_Payment_Gateway {
* @param string $wcgateway_module_url The WcGateway module URL.
* @param OrderProcessor $order_processor The Order processor.
* @param array $card_icons The card icons.
* @param array $card_icons_axo The card icons.
* @param OrderEndpoint $order_endpoint The order endpoint.
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping preference factory.
@ -133,6 +141,7 @@ class AxoGateway extends WC_Payment_Gateway {
string $wcgateway_module_url,
OrderProcessor $order_processor,
array $card_icons,
array $card_icons_axo,
OrderEndpoint $order_endpoint,
PurchaseUnitFactory $purchase_unit_factory,
ShippingPreferenceFactory $shipping_preference_factory,
@ -147,9 +156,10 @@ class AxoGateway extends WC_Payment_Gateway {
$this->wcgateway_module_url = $wcgateway_module_url;
$this->order_processor = $order_processor;
$this->card_icons = $card_icons;
$this->card_icons_axo = $card_icons_axo;
$this->method_title = __( 'Fastlane Debit & Credit Cards', 'woocommerce-paypal-payments' );
$this->method_description = __( 'PayPal Fastlane offers an accelerated checkout experience that recognizes guest shoppers and autofills their details so they can pay in seconds.', 'woocommerce-paypal-payments' );
$this->method_description = __( 'Fastlane accelerates the checkout experience for guest shoppers and autofills their details so they can pay in seconds. When enabled, Fastlane is presented as the default payment method for guests.', 'woocommerce-paypal-payments' );
$is_axo_enabled = $this->ppcp_settings->has( 'axo_enabled' ) && $this->ppcp_settings->get( 'axo_enabled' );
$this->update_option( 'enabled', $is_axo_enabled ? 'yes' : 'no' );
@ -208,10 +218,13 @@ class AxoGateway extends WC_Payment_Gateway {
public function process_payment( $order_id ) {
$wc_order = wc_get_order( $order_id );
$payment_method_title = __( 'Credit Card (via Fastlane by PayPal)', 'woocommerce-paypal-payments' );
$wc_order->set_payment_method_title( $payment_method_title );
$wc_order->save();
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$fastlane_member = wc_clean( wp_unslash( $_POST['fastlane_member'] ?? '' ) );
if ( $fastlane_member ) {
$payment_method_title = __( 'Debit & Credit Cards (via Fastlane by PayPal)', 'woocommerce-paypal-payments' );
$wc_order->set_payment_method_title( $payment_method_title );
$wc_order->save();
}
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
@ -282,22 +295,30 @@ class AxoGateway extends WC_Payment_Gateway {
* @return string
*/
public function get_icon() {
$icon = parent::get_icon();
$icon = parent::get_icon();
$icons = $this->card_icons;
$icons_src = esc_url( $this->wcgateway_module_url ) . 'assets/images/';
if ( $this->card_icons_axo ) {
$icons = $this->card_icons_axo;
$icons_src = esc_url( $this->wcgateway_module_url ) . 'assets/images/axo/';
}
if ( empty( $this->card_icons ) ) {
return $icon;
}
$images = array();
foreach ( $this->card_icons as $card ) {
foreach ( $icons as $card ) {
$images[] = '<img
class="ppcp-card-icon"
title="' . $card['title'] . '"
src="' . esc_url( $this->wcgateway_module_url ) . 'assets/images/' . $card['file'] . '"
src="' . $icons_src . $card['file'] . '"
> ';
}
return '<div class="ppcp-axo-card-icons">' . implode( '', $images ) . '</div>';
return implode( '', $images );
}
/**

View file

@ -1533,7 +1533,7 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
private function bn_code_for_context( string $context ): string {
$codes = $this->bn_codes();
return ( isset( $codes[ $context ] ) ) ? $codes[ $context ] : '';
return ( isset( $codes[ $context ] ) ) ? $codes[ $context ] : 'Woo_PPCP';
}
/**

View file

@ -9,7 +9,7 @@ document.addEventListener(
const includeAllItemsCheckbox = document.getElementById('include-all-items');
const shipmentsWrapper = '#ppcp_order-tracking .ppcp-tracking-column.shipments';
const transactionId = document.querySelector('.ppcp-tracking-transaction_id');
const captureId = document.querySelector('.ppcp-tracking-capture_id');
const orderId = document.querySelector('.ppcp-tracking-order_id');
const carrier = document.querySelector('.ppcp-tracking-carrier');
const carrierNameOther = document.querySelector('.ppcp-tracking-carrier_name_other');
@ -86,7 +86,7 @@ document.addEventListener(
credentials: 'same-origin',
body: JSON.stringify({
nonce: config.ajax.tracking_info.nonce,
transaction_id: transactionId ? transactionId.value : null,
capture_id: captureId ? captureId.value : null,
tracking_number: trackingNumber ? trackingNumber.value : null,
status: status ? status.value : null,
carrier: carrier ? carrier.value : null,
@ -113,6 +113,7 @@ document.addEventListener(
if (noShipemntsContainer) {
noShipemntsContainer.parentNode.removeChild(noShipemntsContainer);
}
trackingNumber.value = ''
});
})
}
@ -135,7 +136,7 @@ document.addEventListener(
credentials: 'same-origin',
body: JSON.stringify({
nonce: config.ajax.tracking_info.nonce,
transaction_id: transactionId ? transactionId.value : null,
capture_id: captureId ? captureId.value : null,
tracking_number: shipmentTrackingNumber ? shipmentTrackingNumber.value : null,
status: shipmentStatus ? shipmentStatus.value : null,
carrier: shipmentCarrier ? shipmentCarrier.value : null,

View file

@ -23,13 +23,14 @@ use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentFactoryInterface;
use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentInterface;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
use function WooCommerce\PayPalCommerce\Api\ppcp_get_paypal_order;
/**
* The OrderTrackingEndpoint.
*
* @psalm-type SupportedStatuses = 'SHIPPED'|'ON_HOLD'|'DELIVERED'|'CANCELLED'
* @psalm-type TrackingInfo = array{
* transaction_id: string,
* capture_id: string,
* status: SupportedStatuses,
* tracking_number: string,
* carrier: string,
@ -222,7 +223,7 @@ class OrderTrackingEndpoint {
*/
public function update_tracking_information( ShipmentInterface $shipment, int $order_id ) : void {
$host = trailingslashit( $this->host );
$tracker_id = $this->find_tracker_id( $shipment->transaction_id(), $shipment->tracking_number() );
$tracker_id = $this->find_tracker_id( $shipment->capture_id(), $shipment->tracking_number() );
$url = "{$host}v1/shipping/trackers/{$tracker_id}";
$shipment_data = $shipment->to_array();
@ -272,9 +273,11 @@ class OrderTrackingEndpoint {
return null;
}
$host = trailingslashit( $this->host );
$tracker_id = $this->find_tracker_id( $wc_order->get_transaction_id(), $tracking_number );
$url = "{$host}v1/shipping/trackers/{$tracker_id}";
$host = trailingslashit( $this->host );
$paypal_order = ppcp_get_paypal_order( $wc_order );
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order ) ?? '';
$tracker_id = $this->find_tracker_id( $capture_id, $tracking_number );
$url = "{$host}v1/shipping/trackers/{$tracker_id}";
$args = array(
'method' => 'GET',
@ -319,9 +322,10 @@ class OrderTrackingEndpoint {
return array();
}
$host = trailingslashit( $this->host );
$transaction_id = $wc_order->get_transaction_id();
$url = "{$host}v1/shipping/trackers?transaction_id={$transaction_id}";
$host = trailingslashit( $this->host );
$paypal_order = ppcp_get_paypal_order( $wc_order );
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
$url = "{$host}v1/shipping/trackers?transaction_id={$capture_id}";
$args = array(
'method' => 'GET',
@ -382,7 +386,7 @@ class OrderTrackingEndpoint {
$carrier = $data['carrier'] ?? '';
$tracking_info = array(
'transaction_id' => $data['transaction_id'] ?? '',
'capture_id' => $data['capture_id'] ?? '',
'status' => $data['status'] ?? '',
'tracking_number' => $data['tracking_number'] ?? '',
'carrier' => $carrier,
@ -395,7 +399,7 @@ class OrderTrackingEndpoint {
return $this->shipment_factory->create_shipment(
$wc_order_id,
$tracking_info['transaction_id'],
$tracking_info['capture_id'],
$tracking_info['tracking_number'],
$tracking_info['status'],
$tracking_info['carrier'],
@ -418,7 +422,7 @@ class OrderTrackingEndpoint {
$carrier = $request_values['carrier'] ?? '';
$data_to_check = array(
'transaction_id' => $request_values['transaction_id'] ?? '',
'capture_id' => $request_values['capture_id'] ?? '',
'status' => $request_values['status'] ?? '',
'tracking_number' => $request_values['tracking_number'] ?? '',
'carrier' => $carrier,
@ -458,14 +462,14 @@ class OrderTrackingEndpoint {
}
/**
* Finds the tracker ID from given transaction ID and tracking number.
* Finds the tracker ID from given capture ID and tracking number.
*
* @param string $transaction_id The transaction ID.
* @param string $capture_id The capture 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";
protected function find_tracker_id( string $capture_id, string $tracking_number ): string {
return ! empty( $tracking_number ) ? "{$capture_id}-{$tracking_number}" : "{$capture_id}-NOTRACKER";
}
/**
@ -503,21 +507,18 @@ class OrderTrackingEndpoint {
$host = trailingslashit( $this->host );
$shipment_data = $shipment->to_array();
$old_api_data = $shipment_data;
unset( $old_api_data['items'] );
$request_shipment_data = array( 'trackers' => array( $old_api_data ) );
if ( $this->should_use_new_api ) {
unset( $shipment_data['transaction_id'] );
$shipment_data['capture_id'] = $shipment->transaction_id();
$request_shipment_data = $shipment_data;
if ( ! $this->should_use_new_api ) {
unset( $shipment_data['capture_id'] );
unset( $shipment_data['items'] );
$shipment_data['transaction_id'] = $shipment->capture_id();
$shipment_data = array( 'trackers' => array( $shipment_data ) );
}
$url = $this->should_use_new_api ? "{$host}v2/checkout/orders/{$paypal_order_id}/track" : "{$host}v1/shipping/trackers";
$args = array(
'method' => 'POST',
'headers' => $this->request_headers(),
'body' => wp_json_encode( (array) apply_filters( 'woocommerce_paypal_payments_tracking_data_before_sending', $request_shipment_data, $wc_order->get_id() ) ),
'body' => wp_json_encode( (array) apply_filters( 'woocommerce_paypal_payments_tracking_data_before_sending', $shipment_data, $wc_order->get_id() ) ),
);
return array(

View file

@ -17,12 +17,16 @@ use Vendidero\Germanized\Shipments\Shipment;
use Vendidero\Germanized\Shipments\ShipmentItem;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentFactoryInterface;
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
use function WooCommerce\PayPalCommerce\Api\ppcp_get_paypal_order;
/**
* Class GermanizedShipmentIntegration.
*/
class GermanizedShipmentIntegration implements Integration {
use TransactionIdHandlingTrait;
/**
* The shipment factory.
*
@ -79,8 +83,9 @@ class GermanizedShipmentIntegration implements Integration {
return;
}
$paypal_order = ppcp_get_paypal_order( $wc_order );
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
$wc_order_id = $wc_order->get_id();
$transaction_id = $wc_order->get_transaction_id();
$tracking_number = $shipment->get_tracking_id();
$carrier = $shipment->get_shipping_provider();
@ -91,14 +96,14 @@ class GermanizedShipmentIntegration implements Integration {
$shipment->get_items()
);
if ( ! $tracking_number || ! $carrier || ! $transaction_id ) {
if ( ! $tracking_number || ! $carrier || ! $capture_id ) {
return;
}
try {
$ppcp_shipment = $this->shipment_factory->create_shipment(
$wc_order_id,
$transaction_id,
$capture_id,
$tracking_number,
'SHIPPED',
'OTHER',

View file

@ -15,12 +15,16 @@ use WC_Order;
use WooCommerce\PayPalCommerce\Compat\Integration;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentFactoryInterface;
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
use function WooCommerce\PayPalCommerce\Api\ppcp_get_paypal_order;
/**
* Class ShipStationIntegration.
*/
class ShipStationIntegration implements Integration {
use TransactionIdHandlingTrait;
/**
* The shipment factory.
*
@ -80,19 +84,20 @@ class ShipStationIntegration implements Integration {
return;
}
$paypal_order = ppcp_get_paypal_order( $wc_order );
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
$order_id = $wc_order->get_id();
$transaction_id = $wc_order->get_transaction_id();
$tracking_number = $data['tracking_number'] ?? '';
$carrier = $data['carrier'] ?? '';
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $transaction_id ) {
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
return;
}
try {
$ppcp_shipment = $this->shipment_factory->create_shipment(
$order_id,
$transaction_id,
$capture_id,
$tracking_number,
'SHIPPED',
'OTHER',

View file

@ -15,14 +15,18 @@ use WC_Order;
use WooCommerce\PayPalCommerce\Compat\Integration;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentFactoryInterface;
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
use WP_REST_Request;
use WP_REST_Response;
use function WooCommerce\PayPalCommerce\Api\ppcp_get_paypal_order;
/**
* Class ShipmentTrackingIntegration.
*/
class ShipmentTrackingIntegration implements Integration {
use TransactionIdHandlingTrait;
/**
* The shipment factory.
*
@ -81,17 +85,18 @@ class ShipmentTrackingIntegration implements Integration {
return;
}
$transaction_id = $wc_order->get_transaction_id();
$paypal_order = ppcp_get_paypal_order( $wc_order );
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
$tracking_number = wc_clean( wp_unslash( $_POST['tracking_number'] ?? '' ) );
$carrier = wc_clean( wp_unslash( $_POST['tracking_provider'] ?? '' ) );
$carrier_other = wc_clean( wp_unslash( $_POST['custom_tracking_provider'] ?? '' ) );
$carrier = $carrier ?: $carrier_other ?: '';
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $transaction_id ) {
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
return;
}
$this->sync_tracking( $order_id, $transaction_id, $tracking_number, $carrier );
$this->sync_tracking( $order_id, $capture_id, $tracking_number, $carrier );
}
);
@ -116,17 +121,18 @@ class ShipmentTrackingIntegration implements Integration {
return $response;
}
$transaction_id = $wc_order->get_transaction_id();
$paypal_order = ppcp_get_paypal_order( $wc_order );
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
$tracking_number = $tracking_item['tracking_number'] ?? '';
$carrier = $tracking_item['tracking_provider'] ?? '';
$carrier_other = $tracking_item['custom_tracking_provider'] ?? '';
$carrier = $carrier ?: $carrier_other ?: '';
if ( ! $tracking_number || ! $carrier || ! $transaction_id ) {
if ( ! $tracking_number || ! $carrier || ! $capture_id ) {
return $response;
}
$this->sync_tracking( $order_id, $transaction_id, $tracking_number, $carrier );
$this->sync_tracking( $order_id, $capture_id, $tracking_number, $carrier );
return $response;
},
@ -139,21 +145,21 @@ class ShipmentTrackingIntegration implements Integration {
* Syncs (add | update) the PayPal tracking with given info.
*
* @param int $wc_order_id The WC order ID.
* @param string $transaction_id The transaction ID.
* @param string $capture_id The capture ID.
* @param string $tracking_number The tracking number.
* @param string $carrier The shipment carrier.
* @return void
*/
protected function sync_tracking(
int $wc_order_id,
string $transaction_id,
string $capture_id,
string $tracking_number,
string $carrier
) {
try {
$ppcp_shipment = $this->shipment_factory->create_shipment(
$wc_order_id,
$transaction_id,
$capture_id,
$tracking_number,
'SHIPPED',
'OTHER',

View file

@ -16,16 +16,18 @@ use WooCommerce\PayPalCommerce\Compat\Integration;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentFactoryInterface;
use WooCommerce\PayPalCommerce\OrderTracking\TrackingAvailabilityTrait;
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
use WP_HTTP_Response;
use WP_REST_Request;
use WP_REST_Server;
use function WooCommerce\PayPalCommerce\Api\ppcp_get_paypal_order;
/**
* Class WcShippingTaxIntegration.
*/
class WcShippingTaxIntegration implements Integration {
use TrackingAvailabilityTrait;
use TrackingAvailabilityTrait, TransactionIdHandlingTrait;
/**
* The shipment factory.
@ -99,15 +101,16 @@ class WcShippingTaxIntegration implements Integration {
continue;
}
$transaction_id = $wc_order->get_transaction_id();
$carrier = $label['carrier_id'] ?? $label['service_name'] ?? '';
$items = array_map( 'intval', $label['product_ids'] ?? array() );
$paypal_order = ppcp_get_paypal_order( $wc_order );
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
$carrier = $label['carrier_id'] ?? $label['service_name'] ?? '';
$items = array_map( 'intval', $label['product_ids'] ?? array() );
if ( ! $carrier || ! $transaction_id ) {
if ( ! $carrier || ! $capture_id ) {
continue;
}
$this->sync_tracking( $order_id, $transaction_id, $tracking_number, $carrier, $items );
$this->sync_tracking( $order_id, $capture_id, $tracking_number, $carrier, $items );
}
return $response;
@ -122,7 +125,7 @@ class WcShippingTaxIntegration implements Integration {
* Syncs (add | update) the PayPal tracking with given info.
*
* @param int $wc_order_id The WC order ID.
* @param string $transaction_id The transaction ID.
* @param string $capture_id The capture ID.
* @param string $tracking_number The tracking number.
* @param string $carrier The shipment carrier.
* @param int[] $items The list of line items IDs.
@ -130,7 +133,7 @@ class WcShippingTaxIntegration implements Integration {
*/
protected function sync_tracking(
int $wc_order_id,
string $transaction_id,
string $capture_id,
string $tracking_number,
string $carrier,
array $items
@ -138,7 +141,7 @@ class WcShippingTaxIntegration implements Integration {
try {
$ppcp_shipment = $this->shipment_factory->create_shipment(
$wc_order_id,
$transaction_id,
$capture_id,
$tracking_number,
'SHIPPED',
'OTHER',

View file

@ -15,12 +15,16 @@ use WC_Order;
use WooCommerce\PayPalCommerce\Compat\Integration;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentFactoryInterface;
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
use function WooCommerce\PayPalCommerce\Api\ppcp_get_paypal_order;
/**
* Class YithShipmentIntegration.
*/
class YithShipmentIntegration implements Integration {
use TransactionIdHandlingTrait;
/**
* The shipment factory.
*
@ -76,20 +80,21 @@ class YithShipmentIntegration implements Integration {
return;
}
$transaction_id = $wc_order->get_transaction_id();
$paypal_order = ppcp_get_paypal_order( $wc_order );
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order );
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$tracking_number = wc_clean( wp_unslash( $_POST['ywot_tracking_code'] ?? '' ) );
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$carrier = wc_clean( wp_unslash( $_POST['ywot_carrier_name'] ?? '' ) );
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $transaction_id ) {
if ( ! $tracking_number || ! is_string( $tracking_number ) || ! $carrier || ! is_string( $carrier ) || ! $capture_id ) {
return;
}
try {
$ppcp_shipment = $this->shipment_factory->create_shipment(
$order_id,
$transaction_id,
$capture_id,
$tracking_number,
'SHIPPED',
'OTHER',

View file

@ -9,11 +9,15 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\OrderTracking;
use Exception;
use WC_Order;
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentInterface;
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
use WP_Post;
use function WooCommerce\PayPalCommerce\Api\ppcp_get_paypal_order;
/**
* Class MetaBoxRenderer
*
@ -25,6 +29,8 @@ use WP_Post;
*/
class MetaBoxRenderer {
use TransactionIdHandlingTrait;
/**
* Allowed shipping statuses.
*
@ -87,7 +93,13 @@ class MetaBoxRenderer {
return;
}
$transaction_id = $wc_order->get_transaction_id() ?: '';
$paypal_order = ppcp_get_paypal_order( $wc_order );
$capture_id = $this->get_paypal_order_transaction_id( $paypal_order ) ?? '';
if ( ! $capture_id ) {
return;
}
$order_items = $wc_order->get_items();
$order_item_count = ! empty( $order_items ) ? count( $order_items ) : 0;
@ -102,8 +114,8 @@ class MetaBoxRenderer {
<div class="ppcp-tracking-column">
<h3><?php echo esc_html__( 'Share Package Tracking Data with PayPal', 'woocommerce-paypal-payments' ); ?></h3>
<p>
<label for="ppcp-tracking-transaction_id"><?php echo esc_html__( 'Transaction ID', 'woocommerce-paypal-payments' ); ?></label>
<input type="text" disabled class="ppcp-tracking-transaction_id disabled" id="ppcp-tracking-transaction_id" name="ppcp-tracking[transaction_id]" value="<?php echo esc_attr( $transaction_id ); ?>" />
<label for="ppcp-tracking-capture_id"><?php echo esc_html__( 'Capture ID', 'woocommerce-paypal-payments' ); ?></label>
<input type="text" disabled class="ppcp-tracking-capture_id disabled" id="ppcp-tracking-capture_id" name="ppcp-tracking[capture_id]" value="<?php echo esc_attr( $capture_id ); ?>" />
</p>
<?php if ( $order_item_count > 1 && $this->should_use_new_api ) : ?>
<p>

View file

@ -32,11 +32,11 @@ class Shipment implements ShipmentInterface {
private $wc_order_id;
/**
* The transaction ID.
* The capture ID.
*
* @var string
*/
protected $transaction_id;
protected $capture_id;
/**
* The tracking number.
@ -76,7 +76,7 @@ class Shipment implements ShipmentInterface {
* Shipment constructor.
*
* @param int $wc_order_id The WC order ID.
* @param string $transaction_id The transaction ID.
* @param string $capture_id The capture ID.
* @param string $tracking_number The tracking number.
* @param string $status The shipment status.
* @param string $carrier The shipment carrier.
@ -85,7 +85,7 @@ class Shipment implements ShipmentInterface {
*/
public function __construct(
int $wc_order_id,
string $transaction_id,
string $capture_id,
string $tracking_number,
string $status,
string $carrier,
@ -97,15 +97,15 @@ class Shipment implements ShipmentInterface {
$this->carrier = $carrier;
$this->carrier_name_other = $carrier_name_other;
$this->line_items = $line_items;
$this->transaction_id = $transaction_id;
$this->capture_id = $capture_id;
$this->wc_order_id = $wc_order_id;
}
/**
* {@inheritDoc}
*/
public function transaction_id(): string {
return $this->transaction_id;
public function capture_id(): string {
return $this->capture_id;
}
/**
@ -228,7 +228,7 @@ class Shipment implements ShipmentInterface {
*/
public function to_array(): array {
$shipment = array(
'transaction_id' => $this->transaction_id(),
'capture_id' => $this->capture_id(),
'tracking_number' => $this->tracking_number(),
'status' => $this->status(),
'carrier' => $this->carrier(),

View file

@ -19,13 +19,13 @@ class ShipmentFactory implements ShipmentFactoryInterface {
*/
public function create_shipment(
int $wc_order_id,
string $transaction_id,
string $capture_id,
string $tracking_number,
string $status,
string $carrier,
string $carrier_name_other,
array $line_items
): ShipmentInterface {
return new Shipment( $wc_order_id, $transaction_id, $tracking_number, $status, $carrier, $carrier_name_other, $line_items );
return new Shipment( $wc_order_id, $capture_id, $tracking_number, $status, $carrier, $carrier_name_other, $line_items );
}
}

View file

@ -20,7 +20,7 @@ interface ShipmentFactoryInterface {
* Returns the new shipment instance.
*
* @param int $wc_order_id The WC order ID.
* @param string $transaction_id The transaction ID.
* @param string $capture_id The capture ID.
* @param string $tracking_number The tracking number.
* @param string $status The shipment status.
* @param string $carrier The shipment carrier.
@ -32,7 +32,7 @@ interface ShipmentFactoryInterface {
*/
public function create_shipment(
int $wc_order_id,
string $transaction_id,
string $capture_id,
string $tracking_number,
string $status,
string $carrier,

View file

@ -24,7 +24,7 @@ namespace WooCommerce\PayPalCommerce\OrderTracking\Shipment;
* tax_rate?: string
* }
* @psalm-type shipmentMap = array{
* transaction_id: string,
* capture_id: string,
* tracking_number: string,
* status: string,
* carrier: string,
@ -35,11 +35,11 @@ namespace WooCommerce\PayPalCommerce\OrderTracking\Shipment;
interface ShipmentInterface {
/**
* The transaction ID.
* The capture ID.
*
* @return string
*/
public function transaction_id(): string;
public function capture_id(): string;
/**
* The tracking number.

View file

@ -119,13 +119,7 @@ class PayLaterWCBlocksRenderer {
$processor->set_attribute( 'data-pp-placement', esc_attr( $this->placement ) );
}
$updated_html = $processor->get_updated_html();
return sprintf(
'<div %1$s>%2$s</div>',
wp_kses_data( get_block_wrapper_attributes() ),
$updated_html
);
return $processor->get_updated_html();
}
}
}

View file

@ -0,0 +1,7 @@
<svg width="133px" height="84px" xmlns="http://www.w3.org/2000/svg" viewBox="10.113 80.237 512 353.098">
<path d="M522.113 403.067c0 16.716-13.55 30.267-30.265 30.267H40.378c-16.715.001-30.265-13.551-30.265-30.267V110.503c0-16.715 13.55-30.266 30.265-30.266h451.47c16.716 0 30.265 13.551 30.265 30.266z" style="fill:#306fc5" />
<path d="M31.63 403.067V110.503c0-16.715 13.552-30.266 30.267-30.266h-21.52c-16.714 0-30.264 13.55-30.264 30.266v292.565c0 16.716 13.55 30.267 30.265 30.267h21.52c-16.715 0-30.268-13.552-30.268-30.268" style="opacity:.15;fill:#202121" />
<path d="M74.59 220.748h15.298l-7.647-19.47zM155.946 286.107v9.041h25.729v9.737h-25.729v10.433h28.509l13.211-14.606-12.515-14.605zM356.898 201.278l-8.345 19.47h15.995zM230.348 320.875v-39.634l-18.08 19.471zM264.42 292.368c-.696-4.172-3.48-6.261-7.654-6.261h-14.599v12.516h15.299c4.171.001 6.954-2.084 6.954-6.255M313.09 297.236c1.391-.697 2.089-2.785 2.089-4.867.696-2.779-.698-4.172-2.089-4.868-1.387-.696-3.476-.696-5.559-.696h-13.91v11.127h13.909c2.083 0 4.172 0 5.56-.696" style="fill:#fff" transform="translate(10.113 .786)" />
<path d="M413.217 183.198v8.344l-4.169-8.344H376.37v8.344l-4.174-8.344h-44.502c-7.648 0-13.909 1.392-19.469 4.173v-4.173h-31.289v4.173c-3.476-2.78-7.648-4.173-13.211-4.173h-111.95l-7.652 17.384-7.647-17.384h-35.462v8.344l-3.477-8.344H66.942l-13.909 32.68-15.991 35.462-.294.697h36.201l.252-.697 4.174-10.428h9.039l4.172 11.125h40.326v-8.344l3.479 8.343h20.163l3.475-8.343v8.344h96.654v-18.08h1.394c1.389 0 1.389 0 1.389 2.087v15.297h50.065v-4.172c4.172 2.089 10.426 4.172 18.771 4.172h20.863l4.172-11.123h9.732l4.172 11.123h40.328v-10.428l6.261 10.428h32.68v-68.143h-31.293m-235.716 58.411h-11.126v-38.245l-.696 1.595v-.019l-16.176 36.669h-10.248l-16.687-38.245v38.245h-23.64l-4.867-10.43H70.417l-4.868 10.43H53.326l20.57-48.675h17.382l19.469 46.587v-46.587h18.422l.328.697h.024l8.773 19.094 6.3 14.306.223-.721 13.906-33.375H177.5v48.674zm47.98-38.245h-27.119v9.039h26.423v9.734h-26.423v9.738h27.119v10.427h-38.939v-49.367h38.939zm49.595 17.93c.018.016.041.027.063.042.263.278.488.557.68.824 1.332 1.746 2.409 4.343 2.463 8.151l.011.197c0 .038.007.071.007.11l-.002.06c.016.383.026.774.026 1.197v9.735h-10.428v-5.565c0-2.781 0-6.954-2.089-9.735a6.3 6.3 0 0 0-2.046-1.398c-1.042-.675-3.017-.686-6.295-.686h-12.52v17.384h-11.818v-48.675h26.425c6.254 0 10.428 0 13.906 2.086 3.407 2.046 5.465 5.439 5.543 10.812-.161 7.4-4.911 11.46-8.326 12.829 0 0 2.32.467 4.4 2.632m23.415 20.315h-11.822v-48.675h11.822zm135.592 0h-15.3l-22.25-36.855v30.595l-.073-.072v6.362h-11.747v-.029h-11.822l-4.172-10.43H344.38l-4.172 11.123h-13.211c-5.559 0-12.517-1.389-16.687-5.561-4.172-4.172-6.256-9.735-6.256-18.773 0-6.953 1.389-13.911 6.256-19.472 3.474-4.175 9.735-5.562 17.382-5.562h11.128v10.429h-11.128c-4.172 0-6.254.693-9.041 2.783-2.082 2.085-3.474 6.256-3.474 11.123 0 5.564.696 9.04 3.474 11.821 2.091 2.089 4.87 2.785 8.346 2.785h4.867l15.991-38.243h17.385l19.472 46.587v-46.586h17.382l20.161 34.07v-34.07h11.826v47.977h.002z" style="fill:#fff" transform="translate(10.113 .786)" />
<path d="M265.161 213.207c.203-.217.387-.463.543-.745.63-.997 1.352-2.793.963-5.244a4 4 0 0 0-.105-.634c-.013-.056-.011-.105-.026-.161l-.007.001c-.346-1.191-1.229-1.923-2.11-2.367-1.394-.693-3.48-.693-5.565-.693h-13.909v11.127h13.909c2.085 0 4.172 0 5.565-.697.209-.106.395-.25.574-.413l.002.009c.001-.001.072-.075.166-.183M475.105 311.144c0-4.867-1.389-9.736-3.474-13.212v-31.289h-.032v-2.089h-33.483c-4.336 0-9.598 4.171-9.598 4.171v-4.171h-31.984c-4.87 0-11.124 1.392-13.909 4.171v-4.171h-57.016v4.17c-4.169-3.474-11.824-4.171-15.298-4.171h-37.549v4.17c-3.476-3.474-11.824-4.171-15.998-4.171H215.05l-9.737 10.431-9.04-10.431h-62.578v70.233h61.19l10.054-10.057 8.715 10.057h38.942v-15.992h3.479c4.863 0 11.124 0 15.991-2.089v18.776h31.291V317.4h1.387c2.089 0 2.089 0 2.089 2.086v15.994h94.563c6.263 0 12.517-1.394 15.993-4.175v4.175h29.902c6.254 0 12.517-.695 16.689-3.478 6.402-3.841 10.437-10.64 11.037-18.749.028-.24.063-.48.085-.721l-.041-.039c.026-.45.044-.895.044-1.349m-219.029-4.171h-13.91v18.077h-22.855l-13.302-15.299-.046.051-.65-.748-15.297 15.996h-44.501v-48.673h45.197l12.348 13.525 2.596 2.832.352-.365 14.604-15.991h36.852c7.152 0 15.161 1.765 18.196 9.042.365 1.441.577 3.043.577 4.863 0 13.906-9.735 16.69-20.161 16.69m69.533-.697c1.389 2.081 2.085 4.867 2.085 9.041v9.732h-11.819v-6.256c0-2.786 0-7.65-2.089-9.739-1.387-2.081-4.172-2.081-8.341-2.081H292.93v18.077h-11.82v-49.369h26.421c5.559 0 10.426 0 13.909 2.084 3.474 2.088 6.254 5.565 6.254 11.128 0 7.647-4.865 11.819-8.343 13.212 3.478 1.385 5.563 2.78 6.258 4.171m47.98-20.169h-27.122v9.04h26.424v9.737h-26.424v9.736h27.122v10.429H334.65V275.68h38.939zm29.202 38.943h-22.252v-10.429h22.252c2.082 0 3.476 0 4.87-1.392.696-.697 1.387-2.085 1.387-3.477 0-1.394-.691-2.778-1.387-3.475-.698-.695-2.091-1.391-4.176-1.391-11.126-.696-24.337 0-24.337-15.296 0-6.954 4.172-14.604 16.689-14.604h22.945v11.819h-21.554c-2.085 0-3.478 0-4.87.696-1.387.697-1.387 2.089-1.387 3.478 0 2.087 1.387 2.783 2.778 3.473 1.394.697 2.783.697 4.172.697h6.259c6.259 0 10.43 1.391 13.211 4.173 2.087 2.087 3.478 5.564 3.478 10.43 0 10.427-6.258 15.298-18.078 15.298m59.799-4.871c-2.778 2.785-7.648 4.871-14.604 4.871H425.74v-10.429h22.245c2.087 0 3.481 0 4.87-1.392.693-.697 1.391-2.085 1.391-3.477 0-1.394-.698-2.778-1.391-3.475-.696-.695-2.085-1.391-4.172-1.391-11.122-.696-24.337 0-24.337-15.295 0-6.609 3.781-12.579 13.106-14.352a26 26 0 0 1 3.583-.253h22.948v11.819h-21.557000000000002c-2.087 0-3.476 0-4.865.696-.7.697-1.396 2.089-1.396 3.478 0 2.087.696 2.783 2.785 3.473 1.389.697 2.78.697 4.172.697h6.256c3.039 0 5.337.375 7.44 1.114 1.926.697 8.302 3.549 9.728 10.994.124.78.215 1.594.215 2.495q0 6.26-4.171 10.427" style="fill:#fff" transform="translate(10.113 .786)" />
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -0,0 +1,7 @@
<svg width="133px" height="84px" xmlns="http://www.w3.org/2000/svg" viewBox="0 79.451 512 353.098">
<path d="M512 402.282c0 16.716-13.55 30.267-30.265 30.267H30.265C13.55 432.549 0 418.996 0 402.282V109.717c0-16.716 13.55-30.266 30.265-30.266h451.469c16.716 0 30.265 13.551 30.265 30.266z" style="fill:#0069aa" />
<path d="M0 308.18h512v72.01H0z" style="fill:#34495e" />
<path d="M21.517 402.282V109.717c0-16.716 13.552-30.266 30.267-30.266h-21.52C13.55 79.451 0 93.003 0 109.717v292.565c0 16.716 13.55 30.267 30.265 30.267h21.52c-16.715 0-30.268-13.553-30.268-30.267" style="opacity:.15;fill:#202121" />
<path d="M368.996 182.984h-98.728c-4.611 0-8.348-3.736-8.348-8.348s3.736-8.348 8.348-8.348h98.728c4.611 0 8.348 3.736 8.348 8.348s-3.738 8.348-8.348 8.348M452.289 217.645H270.267a8.347 8.347 0 0 1-8.348-8.348 8.347 8.347 0 0 1 8.348-8.348h182.022a8.348 8.348 0 1 1 0 16.696M81.528 194.061c0 16.135 9.889 29.666 23.942 34.869v-69.739c-14.052 5.203-23.942 18.735-23.942 34.87M155.952 194.061c0-16.135-9.887-29.666-23.944-34.869v69.739c14.057-5.204 23.944-19.258 23.944-34.87" style="fill:#fff" />
<path d="M186.791 140.596a2 2 0 0 1-.13-.141 78 78 0 0 0-2.691-1.579 69.7 69.7 0 0 0-26.729-8.878c-2.511-.469-5.024-.474-7.533-.474h-31.227c-35.913 0-65.059 26.544-65.059 65.059 0 15.612 5.727 30.185 15.615 41.114l.86.866c11.933 13.497 29.5 22.034 49.1 22.034h30.185c35.394 0 67.659-28.625 67.659-64.013-.317-23.618-12.575-42.731-30.05-53.988m-67.545 113.352c-33.074 0-59.887-26.813-59.887-59.887 0-33.075 26.813-59.888 59.887-59.888 33.076 0 59.89 26.813 59.89 59.888-.002 33.073-26.814 59.887-59.89 59.887" style="fill:#fff" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,6 @@
<svg width="133px" height="84px" xmlns="http://www.w3.org/2000/svg" viewBox="0 79.451 512 353.098">
<path d="M512 402.282c0 16.716-13.55 30.267-30.265 30.267H30.265C13.55 432.549 0 418.996 0 402.282V109.717c0-16.716 13.55-30.266 30.265-30.266h451.469c16.716 0 30.265 13.551 30.265 30.266z" style="fill:#34495e" />
<path d="M21.517 402.282V109.717c0-16.716 13.552-30.266 30.267-30.266h-21.52C13.55 79.451 0 93.003 0 109.717v292.565c0 16.716 13.55 30.267 30.265 30.267h21.52c-16.715 0-30.268-13.553-30.268-30.267" style="opacity:.15;fill:#202121" />
<path d="M309.389 255.801c.041-9.636-3.572-19.286-10.843-26.558-7.287-7.287-16.961-10.897-26.617-10.839q-.068-.002-.139-.003c-20.968 0-37.6 16.628-37.6 37.602 0 20.767 16.837 37.599 37.6 37.599 20.974 0 37.604-16.631 37.604-37.599 0-.069-.005-.134-.005-.202" style="fill:#f26e21" />
<path d="M227.198 271.909c-5.62 5.626-10.807 7.824-16.394 7.943-13.611-.122-23.618-10.202-23.618-24.573 0-7.234 2.739-13.163 7.078-18.228 4.069-3.863 9.311-6.359 15.339-6.359 6.507 0 11.571 2.169 17.352 7.954v-16.631c-5.78-2.891-10.846-4.338-17.352-4.338-9.192.657-17.859 4.371-24.507 10.203-1.916 1.724-3.752 3.627-5.309 5.805-4.856 6.294-7.791 14.001-7.791 22.32 0 20.967 16.637 36.875 37.606 36.875.102 0 .203-.009.302-.01.141.002.28.01.42.01 5.784 0 10.85-1.443 17.357-4.336zc-.244.244.242.471 0 .702zM356.863 228.033l-16.376 40.262-18.802-47.729h-15.183l29.646 73.035h7.954l31.094-73.035h-15.183zM380.983 252.384v39.051h39.769999999999996v-11.574h-25.308v-19.519h24.588v-12.297h-24.588v-15.184h25.308v-12.295h-39.77zM54.135 220.566H33.884v70.869h20.25c10.845 0 18.798-2.895 25.306-7.957 7.953-6.508 13.017-16.629 13.017-27.474.001-20.976-15.187-35.438-38.322-35.438m16.63 53.514c-4.339 3.614-10.124 5.781-18.802 5.781h-4.339V232.86h3.615c8.678 0 14.463 1.446 18.803 5.783 5.061 4.336 7.955 10.848 7.955 17.358.723 6.508-2.169 13.736-7.232 18.079M98.97 220.56h13.739v70.867H98.97zM147.415 248.045c-8.676-2.892-10.848-5.063-10.848-8.677 0-4.339 4.339-7.954 10.124-7.954 4.339 0 7.954 1.447 11.57 5.786l7.233-9.4c-5.787-5.064-13.015-7.953-20.97-7.953-12.296 0-22.42 8.678-22.42 20.244 0 10.126 4.343 14.464 17.357 19.526 5.785 2.166 7.955 2.892 9.404 4.338 2.887 1.444 4.336 4.339 4.336 7.228 0 5.786-4.336 10.126-10.848 10.126-6.514 0-12.294-3.615-15.187-9.401l-8.678 8.678c6.511 9.4 14.465 13.738 24.589 13.738 14.461 0 24.58-9.4 24.58-23.141.002-12.29-4.333-17.352-20.242-23.138M459.804 261.783c10.843-2.166 16.63-9.4 16.63-20.244 0-13.014-9.402-20.973-25.308-20.973h-20.972v70.869h13.739V263.23h2.172l19.519 28.205h16.634zm-11.574-8.678h-4.336v-21.691h4.336c8.678 0 13.742 3.614 13.742 10.85 0 7.228-5.063 10.841-13.742 10.841" style="fill:#e7e8e3" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,71 @@
<svg width="133px" height="84px" xmlns="http://www.w3.org/2000/svg" viewBox="153.586 -73.942 27 18">
<defs>
<linearGradient id="b" x1="0" x2="27.435" y1=".417" y2="16.595" gradientUnits="userSpaceOnUse">
<stop offset=".273" stop-color="#fff" />
<stop offset=".778" stop-color="#F0F0F0" />
<stop offset="1" stop-color="#DFDFDF" />
</linearGradient>
<linearGradient id="e" x1="5.625" x2="10.345" y1="9.061" y2="9.061" gradientUnits="userSpaceOnUse">
<stop stop-color="#2F3063" />
<stop offset="1" stop-color="#1B6CA8" />
</linearGradient>
<linearGradient id="g" x1="10.831" x2="15.536" y1="9.061" y2="9.061" gradientUnits="userSpaceOnUse">
<stop stop-color="#642E32" />
<stop offset="1" stop-color="#D92243" />
</linearGradient>
<linearGradient id="i" x1="17.061" x2="18.684" y1="9.798" y2="9.798" gradientUnits="userSpaceOnUse">
<stop stop-color="#137847" />
<stop offset="1" stop-color="#5FB345" />
</linearGradient>
<linearGradient id="k" x1="17.055" x2="18.547" y1="8.26" y2="8.26" gradientUnits="userSpaceOnUse">
<stop stop-color="#137847" />
<stop offset="1" stop-color="#5FB345" />
</linearGradient>
<linearGradient id="m" x1="16.091" x2="20.812" y1="9.061" y2="9.061" gradientUnits="userSpaceOnUse">
<stop stop-color="#137847" />
<stop offset="1" stop-color="#5FB345" />
</linearGradient>
<radialGradient id="c" cx="0" cy="0" r="1" gradientTransform="rotate(87.248 2.062 10.987)scale(11.7135 17.5748)" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" />
<stop offset="1" stop-color="#E9E9E9" />
</radialGradient>
<clipPath id="a">
<rect width="27" height="18" fill="#fff" rx="2" />
</clipPath>
</defs>
<g clip-path="url(#a)" transform="translate(153.586 -73.942)">
<path fill="#fff" d="M0 0h27v18H0z" />
<path fill="url(#b)" d="M0 0h27v18H0z" />
<path fill="url(#c)" d="M0 0h27v18H0z" />
<mask id="d" width="6" height="12" x="5" y="3" maskUnits="userSpaceOnUse" style="mask-type:alpha">
<path fill="#fff" d="M10.345 3.375v9.527c0 1.112-1.03 1.844-1.821 1.844H5.64l-.001-3.986c.298.076.9.188 1.343.21 1.743.087 2.887-.176 2.975-1.467V7.249H8.291l.003 2.307c-.072.62-.539.867-1.292.815-.344-.025-1.2-.296-1.377-.407l.015.009v-4.97c.111-.861.903-1.592 1.778-1.627l.064-.001z" />
</mask>
<g mask="url(#d)">
<path fill="url(#e)" fill-rule="evenodd" d="M5.64 14.746h15.321V3.375H5.641z" clip-rule="evenodd" />
</g>
<mask id="f" width="6" height="12" x="10" y="3" maskUnits="userSpaceOnUse" style="mask-type:alpha">
<path fill="#fff" d="M12.683 3.375c-.967 0-1.85.866-1.85 1.837v2.514c.58-.45 1.514-.67 2.704-.58.677.052 1.178.146 1.451.226v.798c-.3-.149-.895-.37-1.39-.406-1.122-.08-1.711.442-1.711 1.286 0 .76.455 1.409 1.706 1.323.412-.03 1.1-.268 1.391-.406l.004.774a7.3 7.3 0 0 1-1.77.254c-1.11.01-1.891-.225-2.386-.604v4.355h2.889c.788 0 1.815-.732 1.815-1.844V3.375z" />
</mask>
<g mask="url(#f)">
<path fill="url(#g)" fill-rule="evenodd" d="M12.683 3.375c-.967 0-1.85.866-1.85 1.837v2.514c.58-.45 1.514-.67 2.704-.58.677.052 1.178.146 1.451.226v.798c-.3-.149-.895-.37-1.39-.406-1.122-.08-1.711.442-1.711 1.286 0 .76.455 1.409 1.706 1.323.412-.03 1.1-.268 1.391-.406l.004.774a7.3 7.3 0 0 1-1.77.254c-1.11.01-1.891-.225-2.386-.604v4.355h2.889c.788 0 1.815-.732 1.815-1.844V3.375z" clip-rule="evenodd" />
</g>
<mask id="h" width="2" height="2" x="17" y="9" maskUnits="userSpaceOnUse" style="mask-type:alpha">
<path fill="#fff" d="M18.19 9.287c-.315.003-1.003-.003-1.128 0l-.001 1.02 1.128.003c.219 0 .495-.19.495-.52a.5.5 0 0 0-.493-.503" />
</mask>
<g mask="url(#h)">
<path fill="url(#i)" fill-rule="evenodd" d="M18.19 9.287c-.315.003-1.003-.003-1.128 0l-.001 1.02 1.128.003c.219 0 .495-.19.495-.52a.5.5 0 0 0-.493-.503" clip-rule="evenodd" />
</g>
<mask id="j" width="2" height="2" x="17" y="7" maskUnits="userSpaceOnUse" style="mask-type:alpha">
<path fill="#fff" d="M18.547 8.276c0-.297-.218-.498-.449-.492-.325.007-.911-.009-1.04.003l-.003.943 1.066.008a.46.46 0 0 0 .426-.462" />
</mask>
<g mask="url(#j)">
<path fill="url(#k)" fill-rule="evenodd" d="M18.547 8.276c0-.297-.218-.498-.449-.492-.325.007-.911-.009-1.04.003l-.003.943 1.066.008a.46.46 0 0 0 .426-.462" clip-rule="evenodd" />
</g>
<mask id="l" width="5" height="12" x="16" y="3" maskUnits="userSpaceOnUse" style="mask-type:alpha">
<path fill="#fff" d="M17.95 3.375c-.97 0-1.857.866-1.857 1.837v2.021h2.756c.549 0 1.195.232 1.195.892 0 .354-.19.755-.877.885v.015c.4 0 1.096.232 1.096.932 0 .723-.751.924-1.153.924l-3.018.003v3.862h2.9c.79 0 1.82-.732 1.82-1.844V3.375z" />
</mask>
<g mask="url(#l)">
<path fill="url(#m)" fill-rule="evenodd" d="M17.95 3.375c-.97 0-1.857.866-1.857 1.837v2.021h2.756c.549 0 1.195.232 1.195.892 0 .354-.19.755-.877.885v.015c.4 0 1.096.232 1.096.932 0 .723-.751.924-1.153.924l-3.018.003v3.862h2.9c.79 0 1.82-.732 1.82-1.844V3.375z" clip-rule="evenodd" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -0,0 +1,31 @@
<svg width="133px" height="84px" xmlns="http://www.w3.org/2000/svg" viewBox="2.745 2.516 27 18">
<defs>
<clipPath id="a">
<rect width="27" height="18" fill="#fff" rx="2" />
</clipPath>
<clipPath id="d">
<path fill="#fff" d="M7.085 4.078h12.83v9.844H7.086z" />
</clipPath>
<radialGradient id="c" cx="0" cy="0" r="1" gradientTransform="rotate(87.248 2.062 10.987)scale(11.7135 17.5748)" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" />
<stop offset="1" stop-color="#E9E9E9" />
</radialGradient>
<linearGradient id="b" x1="0" x2="27.435" y1=".417" y2="16.595" gradientUnits="userSpaceOnUse">
<stop offset=".273" stop-color="#fff" />
<stop offset=".778" stop-color="#F0F0F0" />
<stop offset="1" stop-color="#DFDFDF" />
</linearGradient>
</defs>
<g clip-path="url(#a)" transform="translate(2.745 2.516)">
<path fill="#fff" d="M0 0h27v18H0z" />
<path fill="url(#b)" d="M0 0h27v18H0z" />
<path fill="url(#c)" d="M0 0h27v18H0z" />
<g clip-path="url(#d)">
<path fill="#231F20" d="M19.663 13.788v.026h.023l.013-.004.004-.004.001-.005-.001-.005-.004-.005-.013-.003zm.024-.018q.016 0 .028.009a.03.03 0 0 1 .01.022.03.03 0 0 1-.008.02.04.04 0 0 1-.023.01l.033.035h-.025l-.03-.035h-.01v.035h-.02v-.095zm-.007.13a.08.08 0 0 0 .057-.024.08.08 0 0 0 0-.113.1.1 0 0 0-.025-.018.086.086 0 0 0-.064 0 .1.1 0 0 0-.026.018.081.081 0 0 0 0 .114.08.08 0 0 0 .058.023m0-.184a.11.11 0 0 1 .098.064.1.1 0 0 1-.022.113.106.106 0 0 1-.075.03.1.1 0 0 1-.077-.03.11.11 0 0 1-.022-.114.1.1 0 0 1 .022-.033.108.108 0 0 1 .076-.03m-9.823-.37c0-.182.121-.332.32-.332.189 0 .316.144.316.333s-.127.332-.317.332c-.198 0-.32-.15-.32-.332m.852 0v-.519h-.229v.127a.4.4 0 0 0-.332-.152.524.524 0 0 0-.527.545c0 .317.232.545.527.545.15 0 .26-.058.332-.152v.126h.23zm7.737 0c0-.182.121-.332.32-.332.189 0 .317.144.317.333s-.128.332-.318.332c-.198 0-.32-.15-.32-.332m.853 0v-.935h-.23v.543a.4.4 0 0 0-.332-.152.524.524 0 0 0-.527.545c0 .317.232.545.527.545.15 0 .26-.058.333-.152v.126h.229zm-5.748-.342c.148 0 .242.09.267.252h-.547c.025-.15.117-.252.28-.252m.005-.203c-.309 0-.525.222-.525.546 0 .33.225.545.54.545.159 0 .304-.04.432-.146l-.113-.167a.5.5 0 0 1-.306.109c-.147 0-.282-.068-.315-.255h.782q.004-.041.005-.087c-.003-.323-.206-.545-.5-.545m2.764.545c0-.182.121-.332.32-.332.189 0 .317.144.317.332 0 .19-.128.333-.317.333-.199 0-.32-.15-.32-.333m.852 0v-.519h-.228v.127a.4.4 0 0 0-.333-.152.524.524 0 0 0-.527.545c0 .317.232.545.527.545.15 0 .26-.058.333-.152v.126h.229zm-2.145 0c0 .315.222.546.562.546a.56.56 0 0 0 .378-.124l-.11-.183a.47.47 0 0 1-.275.094c-.183-.002-.318-.133-.318-.333s.135-.33.318-.332q.148.001.275.094l.11-.183a.56.56 0 0 0-.378-.124c-.34 0-.562.23-.562.545m2.952-.545a.31.31 0 0 0-.278.152v-.126h-.227v1.039h.23v-.582c0-.172.074-.268.224-.268q.075 0 .143.027l.07-.213a.5.5 0 0 0-.162-.029m-6.138.109a.8.8 0 0 0-.429-.109c-.267 0-.439.126-.439.333 0 .169.128.274.364.306l.108.015c.125.018.185.05.185.109 0 .08-.084.126-.24.126a.57.57 0 0 1-.35-.109l-.108.176a.77.77 0 0 0 .456.135c.304 0 .48-.141.48-.339 0-.182-.139-.278-.368-.31l-.108-.016c-.099-.012-.178-.032-.178-.102 0-.076.075-.121.2-.121.135 0 .265.05.329.089zm2.955-.108a.31.31 0 0 0-.278.152v-.127h-.227v1.039h.23v-.582c0-.172.074-.268.224-.268q.075 0 .143.027l.07-.213a.5.5 0 0 0-.162-.029m-1.954.025h-.375v-.315h-.231v.315h-.214v.207h.214v.473c0 .241.095.385.366.385.1 0 .213-.03.286-.08l-.066-.194a.4.4 0 0 1-.203.059c-.114 0-.152-.07-.152-.174v-.469h.375zm-3.423 1.039v-.652c0-.245-.159-.41-.415-.412a.41.41 0 0 0-.37.184.39.39 0 0 0-.348-.184.35.35 0 0 0-.308.154v-.129h-.23v1.039h.232v-.576c0-.18.101-.276.258-.276.152 0 .229.098.229.274v.578h.231v-.576c0-.18.106-.276.258-.276.156 0 .23.098.23.274v.578z" />
<path fill="#F79410" d="M19.793 10.412v-.152h-.04l-.046.104-.047-.104h-.04v.152h.029v-.114l.043.098h.03l.043-.099v.115zm-.254 0v-.126h.051v-.025h-.131v.025h.051v.126z" />
<path fill="#FF5F00" d="M15.236 11.063h-3.47V4.914h3.47z" />
<path fill="#EB001B" d="M11.986 7.988c0-1.247.592-2.358 1.515-3.074a4 4 0 0 0-2.451-.836c-2.19 0-3.965 1.75-3.965 3.91S8.86 11.9 11.05 11.9a4 4 0 0 0 2.45-.836 3.89 3.89 0 0 1-1.514-3.075" />
<path fill="#F79E1B" d="M19.917 7.989c0 2.16-1.775 3.91-3.965 3.91a4 4 0 0 1-2.451-.835 3.88 3.88 0 0 0 1.515-3.075A3.88 3.88 0 0 0 13.5 4.914a4 4 0 0 1 2.45-.836c2.19 0 3.966 1.751 3.966 3.91" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.7 KiB

View file

@ -0,0 +1,11 @@
<svg width="133px" height="84px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 18">
<defs>
<clipPath id="a">
<rect width="27" height="18" fill="#fff" rx="2" />
</clipPath>
</defs>
<g clip-path="url(#a)">
<path fill="#001C64" d="M0 0h27v18H0z" />
<path fill="#fff" fill-rule="evenodd" d="M13.597 7.56c-.01.844.75 1.314 1.322 1.594.587.287.784.471.782.728-.004.393-.469.566-.903.573-.759.012-1.2-.206-1.55-.37l-.273 1.283c.352.162 1.003.304 1.678.311 1.586 0 2.622-.786 2.627-2.004.007-1.545-2.129-1.63-2.114-2.32.005-.21.204-.434.64-.49.216-.029.813-.05 1.488.261l.265-1.241a4 4 0 0 0-1.412-.26c-1.491 0-2.541.796-2.55 1.935m6.512-1.828a.69.69 0 0 0-.642.43l-2.265 5.425h1.585l.315-.874h1.936l.182.874h1.396l-1.219-5.855zm.221 1.582.458 2.199h-1.252zm-8.653-1.582-1.249 5.855h1.51l1.248-5.855zm-2.233 0L7.873 9.717 7.237 6.33c-.074-.378-.369-.597-.696-.597H3.973l-.035.17c.527.115 1.126.3 1.489.498.222.121.285.227.358.514l1.203 4.673h1.596l2.445-5.855z" clip-rule="evenodd" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1,009 B

View file

@ -56,13 +56,22 @@ $background-ident-color: #fbfbfb;
}
}
.ppcp-important {
background: white;
padding: 5px 5px 5px 15px;
border-left: 2px solid #dba617;
.ppcp-notice {
background: #fff;
border: 1px solid #c3c4c7;
border-left-width: 4px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
margin: 5px 15px 2px;
padding: 1px 12px;
}
span {
.ppcp-notice-warning {
border-left-color: #dba617;
.highlight {
background: transparent;
color: #dba617;
font-weight: 600;
}
}
@ -87,6 +96,18 @@ $background-ident-color: #fbfbfb;
th, &.ppcp-settings-field-heading td {
padding-left: 40px;
padding-right: 40px;
}
.ppcp-notice {
margin-left: 40px;
margin-right: 10px;
padding: 1px 12px;
p {
margin: .5em 0;
padding: 2px;
}
}
th, td {

View file

@ -803,6 +803,15 @@ return array(
'elo' => _x( 'Elo', 'Name of credit card', 'woocommerce-paypal-payments' ),
'hiper' => _x( 'Hiper', 'Name of credit card', 'woocommerce-paypal-payments' ),
),
'options_axo' => array(
'visa-light' => _x( 'Visa (light)', 'Name of credit card', 'woocommerce-paypal-payments' ),
'mastercard-light' => _x( 'Mastercard (light)', 'Name of credit card', 'woocommerce-paypal-payments' ),
'amex-light' => _x( 'Amex (light)', 'Name of credit card', 'woocommerce-paypal-payments' ),
'discover-light' => _x( 'Discover (light)', 'Name of credit card', 'woocommerce-paypal-payments' ),
'dinersclub-light' => _x( 'Diners Club (light)', 'Name of credit card', 'woocommerce-paypal-payments' ),
'jcb-light' => _x( 'JCB (light)', 'Name of credit card', 'woocommerce-paypal-payments' ),
'unionpay-light' => _x( 'UnionPay (light)', 'Name of credit card', 'woocommerce-paypal-payments' ),
),
'screens' => array(
State::STATE_ONBOARDED,
),

View file

@ -0,0 +1,129 @@
<?php
/**
* Helper to detect what cart and checkout configuration is being used.
*
* @package WooCommerce\PayPalCommerce\WcGateway\Helper
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
* Class CartCheckoutDetector
*/
class CartCheckoutDetector {
/**
* Returns a list of Elementor widgets if they exist for a specific page.
*
* @param int $page_id The ID of the page.
*
* @return array List of widget types if any exist, otherwise an empty array.
*/
private static function get_elementor_widgets( $page_id ): array {
$elementor_data = get_post_meta( $page_id, '_elementor_data' );
if ( isset( $elementor_data[0] ) ) {
// Parse the Elementor json and find all widgets for a specific page.
$reg_exp = '/"widgetType":"([^"]*)/i';
$output_array = array();
if ( is_array( $elementor_data[0] ) ) {
$elementor_data[0] = wp_json_encode( $elementor_data[0] );
}
preg_match_all( $reg_exp, $elementor_data[0], $output_array, PREG_SET_ORDER );
$widgets_list = array();
foreach ( $output_array as $found ) {
if ( ! isset( $found[1] ) ) {
continue;
}
$widget_key = $found[1];
$widgets_list[] = $widget_key;
}
return $widgets_list;
}
return array();
}
/**
* Check if the Checkout page is using Elementor.
*
* @return bool
*/
public static function has_elementor_checkout(): bool {
// Check if Elementor is installed and activated.
if ( did_action( 'elementor/loaded' ) ) {
$elementor_widgets = self::get_elementor_widgets( wc_get_page_id( 'checkout' ) );
if ( $elementor_widgets ) {
return in_array( 'woocommerce-checkout-page', $elementor_widgets, true );
}
}
return false;
}
/**
* Check if the Cart page is using Elementor.
*
* @return bool
*/
public static function has_elementor_cart(): bool {
$elementor_widgets = self::get_elementor_widgets( wc_get_page_id( 'cart' ) );
if ( $elementor_widgets ) {
return in_array( 'woocommerce-cart-page', $elementor_widgets, true );
}
return false;
}
/**
* Check if the Checkout page is using the block checkout.
*
* @return bool
*/
public static function has_block_checkout(): bool {
$checkout_page_id = wc_get_page_id( 'checkout' );
return $checkout_page_id && has_block( 'woocommerce/checkout', $checkout_page_id );
}
/**
* Check if the Cart page is using the block cart.
*
* @return bool
*/
public static function has_block_cart(): bool {
$cart_page_id = wc_get_page_id( 'cart' );
return $cart_page_id && has_block( 'woocommerce/cart', $cart_page_id );
}
/**
* Check if the Checkout page is using the classic checkout.
*
* @return bool
*/
public static function has_classic_checkout(): bool {
$checkout_page_id = wc_get_page_id( 'checkout' );
return $checkout_page_id && has_block( 'woocommerce/classic-shortcode', $checkout_page_id );
}
/**
* Check if the Cart page is using the classic cart.
*
* @return bool
*/
public static function has_classic_cart(): bool {
$cart_page_id = wc_get_page_id( 'cart' );
return $cart_page_id && has_block( 'woocommerce/classic-shortcode', $cart_page_id );
}
}

View file

@ -16,7 +16,6 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Amount;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
@ -25,6 +24,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
use WooCommerce\PayPalCommerce\WcGateway\Helper\RefundFeesUpdater;
/**
@ -109,7 +109,7 @@ class RefundProcessor {
*/
public function process( WC_Order $wc_order, float $amount = null, string $reason = '' ) : bool {
try {
if ( ! in_array( $wc_order->get_payment_method(), array( PayPalGateway::ID, CreditCardGateway::ID, CardButtonGateway::ID ), true ) ) {
if ( ! in_array( $wc_order->get_payment_method(), array( PayPalGateway::ID, CreditCardGateway::ID, CardButtonGateway::ID, PayUponInvoiceGateway::ID ), true ) ) {
return true;
}

View file

@ -268,6 +268,31 @@ class SettingsRenderer {
return $html;
}
/**
* Renders the html field.
*
* @param string $field The current field HTML.
* @param string $key The current key.
* @param array $config The configuration array.
* @param string $value The current value.
*
* @return string
*/
public function render_html( $field, $key, $config, $value ): string {
if ( 'ppcp-html' !== $config['type'] ) {
return $field;
}
$html = sprintf(
'<div class="wc-settings-html %s">%s</div>',
esc_attr( implode( ' ', $config['classes'] ) ),
$config['html']
);
return $html;
}
/**
* Renders the table row.
*

View file

@ -627,6 +627,7 @@ class WCGatewayModule implements ModuleInterface {
$field = $renderer->render_password( $field, $key, $args, $value );
$field = $renderer->render_heading( $field, $key, $args, $value );
$field = $renderer->render_table( $field, $key, $args, $value );
$field = $renderer->render_html( $field, $key, $args, $value );
return $field;
},
10,

View file

@ -1,6 +1,6 @@
{
"name": "woocommerce-paypal-payments",
"version": "2.7.0",
"version": "2.7.1",
"description": "WooCommerce PayPal Payments",
"repository": "https://github.com/woocommerce/woocommerce-paypal-payments",
"license": "GPL-2.0",

View file

@ -4,7 +4,7 @@ Tags: woocommerce, paypal, payments, ecommerce, checkout, cart, pay later, apple
Requires at least: 5.3
Tested up to: 6.5
Requires PHP: 7.2
Stable tag: 2.7.0
Stable tag: 2.7.1
License: GPLv2
License URI: http://www.gnu.org/licenses/gpl-2.0.html
@ -179,6 +179,13 @@ If you encounter issues with the PayPal buttons not appearing after an update, p
== Changelog ==
= 2.7.1 - xxxx-xx-xx =
* Fix - Ensure package tracking data is sent to original PayPal transaction #2180
* Fix - Set the 'Woo_PPCP' as a default value for data-partner-attribution-id #2188
* Fix - Allow PUI Gateway for refund processor #2192
* Fix - Notice on newly created block cart checkout #2211
* Fix - Apple Pay button in the editor #2177
= 2.7.0 - 2024-04-30 =
* Fix - Zero sum subscriptions cause CANNOT_BE_ZERO_OR_NEGATIVE when using Vault v3 #2152
* Fix - Incorrect Pricing Issue with Variable Subscriptions in PayPal Subscriptions Mode #2156

View file

@ -3,7 +3,7 @@
* Plugin Name: WooCommerce PayPal Payments
* Plugin URI: https://woocommerce.com/products/woocommerce-paypal-payments/
* Description: PayPal's latest complete payments processing solution. Accept PayPal, Pay Later, credit/debit cards, alternative digital wallets local payment types and bank accounts. Turn on only PayPal options or process a full suite of payment methods. Enable global transaction with extensive currency and country coverage.
* Version: 2.7.0
* Version: 2.7.1
* Author: WooCommerce
* Author URI: https://woocommerce.com/
* License: GPL-2.0
@ -26,7 +26,7 @@ define( 'PAYPAL_API_URL', 'https://api-m.paypal.com' );
define( 'PAYPAL_URL', 'https://www.paypal.com' );
define( 'PAYPAL_SANDBOX_API_URL', 'https://api-m.sandbox.paypal.com' );
define( 'PAYPAL_SANDBOX_URL', 'https://www.sandbox.paypal.com' );
define( 'PAYPAL_INTEGRATION_DATE', '2024-04-22' );
define( 'PAYPAL_INTEGRATION_DATE', '2024-05-13' );
! defined( 'CONNECT_WOO_CLIENT_ID' ) && define( 'CONNECT_WOO_CLIENT_ID', 'AcCAsWta_JTL__OfpjspNyH7c1GGHH332fLwonA5CwX4Y10mhybRZmHLA0GdRbwKwjQIhpDQy0pluX_P' );
! defined( 'CONNECT_WOO_SANDBOX_CLIENT_ID' ) && define( 'CONNECT_WOO_SANDBOX_CLIENT_ID', 'AYmOHbt1VHg-OZ_oihPdzKEVbU3qg0qXonBcAztuzniQRaKE0w1Hr762cSFwd4n8wxOl-TCWohEa0XM_' );