add: stripe tax to onboarding tax task (#50989)

This commit is contained in:
RJ 2024-08-29 21:48:51 +10:00 committed by GitHub
parent f359c20f84
commit 88806aae87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 213 additions and 98 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
Add optional onclick to Plugins component

View File

@ -19,6 +19,7 @@ type PluginsProps = {
response: InstallPluginsResponse response: InstallPluginsResponse
) => void; ) => void;
onError: ( errors: unknown, response: InstallPluginsResponse ) => void; onError: ( errors: unknown, response: InstallPluginsResponse ) => void;
onClick?: () => void;
onSkip?: () => void; onSkip?: () => void;
skipText?: string; skipText?: string;
autoInstall?: boolean; autoInstall?: boolean;
@ -37,6 +38,7 @@ export const Plugins = ( {
onAbort, onAbort,
onComplete, onComplete,
onError = () => null, onError = () => null,
onClick = () => null,
pluginSlugs = [ 'woocommerce-services' ], pluginSlugs = [ 'woocommerce-services' ],
onSkip, onSkip,
installText = __( 'Install & enable', 'woocommerce' ), installText = __( 'Install & enable', 'woocommerce' ),
@ -159,6 +161,7 @@ export const Plugins = ( {
} }
disabled={ isRequesting && hasBeenClicked } disabled={ isRequesting && hasBeenClicked }
onClick={ () => { onClick={ () => {
onClick();
setHasBeenClicked( true ); setHasBeenClicked( true );
installAndActivate(); installAndActivate();
} } } }

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
Add stripe tax status to task type

View File

@ -29,8 +29,10 @@ export type TaskType = {
badge?: string; badge?: string;
additionalData?: { additionalData?: {
woocommerceTaxCountries?: string[]; woocommerceTaxCountries?: string[];
stripeTaxCountries?: string[];
taxJarActivated?: boolean; taxJarActivated?: boolean;
avalaraActivated?: boolean; avalaraActivated?: boolean;
stripeTaxActivated?: boolean;
woocommerceTaxActivated?: boolean; woocommerceTaxActivated?: boolean;
woocommerceShippingActivated?: boolean; woocommerceShippingActivated?: boolean;
}; };

View File

@ -1,73 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { getAdminLink } from '@woocommerce/settings';
import interpolateComponents from '@automattic/interpolate-components';
import { recordEvent } from '@woocommerce/tracks';
/**
* Internal dependencies
*/
import { PartnerCard } from '../components/partner-card';
import { TaxChildProps } from '../utils';
import logo from './logo.png';
export const Card: React.FC< TaxChildProps > = ( { task } ) => {
const { additionalData: { avalaraActivated } = {} } = task;
return (
<PartnerCard
name={ __( 'Avalara', 'woocommerce' ) }
logo={ logo }
description={ __( 'Powerful all-in-one tax tool', 'woocommerce' ) }
benefits={ [
__( 'Real-time sales tax calculation', 'woocommerce' ),
interpolateComponents( {
mixedString: __(
'{{strong}}Multi{{/strong}}-economic nexus compliance',
'woocommerce'
),
components: {
strong: <strong />,
},
} ),
__(
'Cross-border and multi-channel compliance',
'woocommerce'
),
__( 'Automate filing & remittance', 'woocommerce' ),
__(
'Return-ready, jurisdiction-level reporting.',
'woocommerce'
),
] }
terms={ '' }
actionText={
avalaraActivated
? __( 'Continue setup', 'woocommerce' )
: __( 'Download', 'woocommerce' )
}
onClick={ () => {
recordEvent( 'tasklist_tax_select_option', {
selected_option: 'avalara',
} );
if ( avalaraActivated ) {
window.location.href = getAdminLink(
'/admin.php?page=wc-settings&tab=tax&section=avatax'
);
return;
}
window.open(
new URL(
'https://woocommerce.com/products/woocommerce-avatax/'
).toString(),
'_blank'
);
} }
/>
);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -41,7 +41,7 @@
.woocommerce-tax-partner-card__terms { .woocommerce-tax-partner-card__terms {
color: $gray-600; color: $gray-600;
font-size: 9px; font-size: 12px;
margin-bottom: $gap-smaller; margin-bottom: $gap-smaller;
} }

View File

@ -15,7 +15,8 @@ export const PartnerCard: React.FC< {
description: string; description: string;
benefits: ( string | JSX.Element )[]; benefits: ( string | JSX.Element )[];
terms: string | JSX.Element; terms: string | JSX.Element;
actionText: string; children?: React.ReactNode;
actionText?: string;
onClick: () => void; onClick: () => void;
isBusy?: boolean; isBusy?: boolean;
} > = ( { } > = ( {
@ -27,6 +28,7 @@ export const PartnerCard: React.FC< {
actionText, actionText,
onClick, onClick,
isBusy, isBusy,
children,
} ) => { } ) => {
return ( return (
<div className="woocommerce-tax-partner-card"> <div className="woocommerce-tax-partner-card">
@ -59,14 +61,18 @@ export const PartnerCard: React.FC< {
<div className="woocommerce-tax-partner-card__terms"> <div className="woocommerce-tax-partner-card__terms">
{ terms } { terms }
</div> </div>
<Button { children ? (
isSecondary children
onClick={ onClick } ) : (
isBusy={ isBusy } <Button
disabled={ isBusy } isSecondary
> onClick={ onClick }
{ actionText } isBusy={ isBusy }
</Button> disabled={ isBusy }
>
{ actionText }
</Button>
) }
</div> </div>
</div> </div>
); );

View File

@ -17,6 +17,7 @@ import {
useEffect, useEffect,
useState, useState,
createElement, createElement,
useMemo,
} from '@wordpress/element'; } from '@wordpress/element';
import { WooOnboardingTask } from '@woocommerce/onboarding'; import { WooOnboardingTask } from '@woocommerce/onboarding';
@ -25,6 +26,7 @@ import { WooOnboardingTask } from '@woocommerce/onboarding';
*/ */
import { redirectToTaxSettings } from './utils'; import { redirectToTaxSettings } from './utils';
import { Card as WooCommerceTaxCard } from './woocommerce-tax/card'; import { Card as WooCommerceTaxCard } from './woocommerce-tax/card';
import { Card as StripeTaxCard } from './stripe-tax/card';
import { createNoticesFromResponse } from '../../../lib/notices'; import { createNoticesFromResponse } from '../../../lib/notices';
import { getCountryCode } from '~/dashboard/utils'; import { getCountryCode } from '~/dashboard/utils';
import { ManualConfiguration } from './manual-configuration'; import { ManualConfiguration } from './manual-configuration';
@ -150,20 +152,21 @@ export const Tax: React.FC< TaxProps > = ( { onComplete, query, task } ) => {
} ); } );
}, [ updateOptions ] ); }, [ updateOptions ] );
const getVisiblePartners = () => { const partners = useMemo( () => {
const countryCode = const countryCode =
getCountryCode( generalSettings?.woocommerce_default_country ) || getCountryCode( generalSettings?.woocommerce_default_country ) ||
''; '';
const { const {
additionalData: { additionalData: {
woocommerceTaxCountries = [], woocommerceTaxCountries = [],
stripeTaxCountries = [],
taxJarActivated, taxJarActivated,
woocommerceTaxActivated, woocommerceTaxActivated,
woocommerceShippingActivated, woocommerceShippingActivated,
} = {}, } = {},
} = task; } = task;
const partners = [ const allPartners = [
{ {
id: 'woocommerce-tax', id: 'woocommerce-tax',
card: WooCommerceTaxCard, card: WooCommerceTaxCard,
@ -174,31 +177,35 @@ export const Tax: React.FC< TaxProps > = ( { onComplete, query, task } ) => {
! woocommerceShippingActivated && ! woocommerceShippingActivated &&
woocommerceTaxCountries.includes( countryCode ), woocommerceTaxCountries.includes( countryCode ),
}, },
{
id: 'stripe-tax',
card: StripeTaxCard,
isVisible: stripeTaxCountries.includes( countryCode ),
},
]; ];
return partners.filter( ( partner ) => partner.isVisible ); return allPartners.filter( ( partner ) => partner.isVisible );
}; // eslint-disable-next-line react-hooks/exhaustive-deps -- the partner list shouldn't be changing in the middle of interaction. for some reason the country is becoming null in a re-render and causing unexpected behaviour
}, [] );
const partners = getVisiblePartners();
const { auto } = query;
useEffect( () => { useEffect( () => {
const { auto } = query;
if ( auto === 'true' ) { if ( auto === 'true' ) {
onAutomate(); onAutomate();
return;
} }
}, [ auto, onAutomate ] );
useEffect( () => {
if ( query.partner ) { if ( query.partner ) {
return; return;
} }
recordEvent( 'tasklist_tax_view_options', { recordEvent( 'tasklist_tax_view_options', {
options: partners.map( ( partner ) => partner.id ), options: partners.map( ( partner ) => partner.id ),
} ); } );
}, [ onAutomate, partners, query ] ); }, [ partners, query.partner ] );
const getCurrentPartner = () => { const currentPartner = useMemo( () => {
if ( ! query.partner ) { if ( ! query.partner ) {
return null; return null;
} }
@ -206,7 +213,7 @@ export const Tax: React.FC< TaxProps > = ( { onComplete, query, task } ) => {
return ( return (
partners.find( ( partner ) => partner.id === query.partner ) || null partners.find( ( partner ) => partner.id === query.partner ) || null
); );
}; }, [ partners, query.partner ] );
const childProps = { const childProps = {
isPending, isPending,
@ -220,8 +227,6 @@ export const Tax: React.FC< TaxProps > = ( { onComplete, query, task } ) => {
return <Spinner />; return <Spinner />;
} }
const currentPartner = getCurrentPartner();
if ( ! partners.length ) { if ( ! partners.length ) {
return ( return (
<TaskCard> <TaskCard>

View File

@ -0,0 +1,107 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { getAdminLink } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
import { Plugins } from '@woocommerce/components';
import { dispatch, useDispatch } from '@wordpress/data';
import { SETTINGS_STORE_NAME } from '@woocommerce/data';
import { Button } from '@wordpress/components';
/**
* Internal dependencies
*/
import { PartnerCard } from '../components/partner-card';
import { TaxChildProps } from '../utils';
import StripeTaxLogo from './stripe-tax-logo.svg';
import { createNoticesFromResponse } from '~/lib/notices';
const STRIPE_TAX_PLUGIN_SLUG = 'stripe-tax-for-woocommerce';
const redirectToStripeTaxSettings = () => {
window.location.href = getAdminLink(
'/admin.php?page=wc-settings&tab=stripe_tax_for_woocommerce'
);
};
export const Card: React.FC< TaxChildProps > = ( {
task: {
additionalData: { stripeTaxActivated } = {
stripeTaxActivated: false,
},
},
} ) => {
const { createSuccessNotice } = useDispatch( 'core/notices' );
return (
<PartnerCard
name={ __( 'Stripe Tax', 'woocommerce' ) }
logo={ StripeTaxLogo }
description={ __( 'Powerful global tax tool', 'woocommerce' ) }
benefits={ [
__( 'Real-time sales tax calculation', 'woocommerce' ),
__( 'Multi-economic nexus compliance', 'woocommerce' ),
__( 'Detailed tax transaction reports', 'woocommerce' ),
__( 'Coverage in over 55 countries', 'woocommerce' ),
] }
terms={ __(
'Free to install, then pay as you go.',
'woocommerce'
) }
onClick={ () => {} }
>
{ stripeTaxActivated ? (
<Button
variant="secondary"
onClick={ () => {
recordEvent(
'tasklist_tax_setup_stripe_tax_to_settings'
);
redirectToStripeTaxSettings();
} }
>
{ __( 'Continue to setttings', 'woocommerce' ) }
</Button>
) : (
<Plugins
installText={ __( 'Install for free', 'woocommerce' ) }
onClick={ () => {
recordEvent( 'tasklist_tax_select_option', {
selected_option: STRIPE_TAX_PLUGIN_SLUG,
} );
} }
onComplete={ () => {
recordEvent( 'tasklist_tax_install_plugin_success', {
selected_option: STRIPE_TAX_PLUGIN_SLUG,
} );
const { updateAndPersistSettingsForGroup } =
dispatch( SETTINGS_STORE_NAME );
updateAndPersistSettingsForGroup( 'general', {
general: {
woocommerce_calc_taxes: 'yes', // Stripe tax requires tax calculation to be enabled so let's do it here to save the user from doing it manually
},
} ).then( () => {
createSuccessNotice(
__(
"Stripe Tax for Woocommerce has been successfully installed. Let's configure it now.",
'woocommerce'
)
);
redirectToStripeTaxSettings();
} );
} }
onError={ ( errors, response ) => {
recordEvent( 'tasklist_tax_install_plugin_error', {
selected_option: STRIPE_TAX_PLUGIN_SLUG,
errors,
} );
createNoticesFromResponse( response );
} }
installButtonVariant="secondary"
pluginSlugs={ [ STRIPE_TAX_PLUGIN_SLUG ] }
/>
) }
</PartnerCard>
);
};

View File

@ -0,0 +1 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 468 222.5" style="enable-background:new 0 0 468 222.5" xml:space="preserve"><style>.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#0a2540}</style><path class="st0" d="M414 113.4c0-25.6-12.4-45.8-36.1-45.8-23.8 0-38.2 20.2-38.2 45.6 0 30.1 17 45.3 41.4 45.3 11.9 0 20.9-2.7 27.7-6.5v-20c-6.8 3.4-14.6 5.5-24.5 5.5-9.7 0-18.3-3.4-19.4-15.2h48.9c0-1.3.2-6.5.2-8.9zm-49.4-9.5c0-11.3 6.9-16 13.2-16 6.1 0 12.6 4.7 12.6 16h-25.8zM301.1 67.6c-9.8 0-16.1 4.6-19.6 7.8l-1.3-6.2h-22v116.6l25-5.3.1-28.3c3.6 2.6 8.9 6.3 17.7 6.3 17.9 0 34.2-14.4 34.2-46.1-.1-29-16.6-44.8-34.1-44.8zm-6 68.9c-5.9 0-9.4-2.1-11.8-4.7l-.1-37.1c2.6-2.9 6.2-4.9 11.9-4.9 9.1 0 15.4 10.2 15.4 23.3 0 13.4-6.2 23.4-15.4 23.4zM223.8 61.7l25.1-5.4V36l-25.1 5.3zM223.8 69.3h25.1v87.5h-25.1zM196.9 76.7l-1.6-7.4h-21.6v87.5h25V97.5c5.9-7.7 15.9-6.3 19-5.2v-23c-3.2-1.2-14.9-3.4-20.8 7.4zM146.9 47.6l-24.4 5.2-.1 80.1c0 14.8 11.1 25.7 25.9 25.7 8.2 0 14.2-1.5 17.5-3.3V135c-3.2 1.3-19 5.9-19-8.9V90.6h19V69.3h-19l.1-21.7zM79.3 94.7c0-3.9 3.2-5.4 8.5-5.4 7.6 0 17.2 2.3 24.8 6.4V72.2c-8.3-3.3-16.5-4.6-24.8-4.6C67.5 67.6 54 78.2 54 95.9c0 27.6 38 23.2 38 35.1 0 4.6-4 6.1-9.6 6.1-8.3 0-18.9-3.4-27.3-8v23.8c9.3 4 18.7 5.7 27.3 5.7 20.8 0 35.1-10.3 35.1-28.2-.1-29.8-38.2-24.5-38.2-35.7z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Added Stripe tax in onboarding tax task

View File

@ -129,9 +129,11 @@ class Tax extends Task {
return array( return array(
'avalara_activated' => PluginsHelper::is_plugin_active( 'woocommerce-avatax' ), 'avalara_activated' => PluginsHelper::is_plugin_active( 'woocommerce-avatax' ),
'tax_jar_activated' => class_exists( 'WC_Taxjar' ), 'tax_jar_activated' => class_exists( 'WC_Taxjar' ),
'stripe_tax_activated' => PluginsHelper::is_plugin_active( 'stripe-tax-for-woocommerce' ),
'woocommerce_tax_activated' => PluginsHelper::is_plugin_active( 'woocommerce-tax' ), 'woocommerce_tax_activated' => PluginsHelper::is_plugin_active( 'woocommerce-tax' ),
'woocommerce_shipping_activated' => PluginsHelper::is_plugin_active( 'woocommerce-shipping' ), 'woocommerce_shipping_activated' => PluginsHelper::is_plugin_active( 'woocommerce-shipping' ),
'woocommerce_tax_countries' => self::get_automated_support_countries(), 'woocommerce_tax_countries' => self::get_automated_support_countries(),
'stripe_tax_countries' => self::get_stripe_tax_support_countries(),
); );
} }
@ -162,4 +164,54 @@ class Tax extends Task {
return $tax_supported_countries; return $tax_supported_countries;
} }
/**
* Get an array of countries that support Stripe tax.
*
* @return array
*/
private static function get_stripe_tax_support_countries() {
// https://docs.stripe.com/tax/supported-countries#supported-countries accurate as of 2024-08-26.
// countries with remote sales not included.
return array(
'AU',
'AT',
'BE',
'BG',
'CA',
'HR',
'CY',
'CZ',
'DK',
'EE',
'FI',
'FR',
'DE',
'GR',
'HK',
'HU',
'IE',
'IT',
'JP',
'LV',
'LT',
'LU',
'MT',
'NL',
'NZ',
'NO',
'PL',
'PT',
'RO',
'SG',
'SK',
'SI',
'ES',
'SE',
'CH',
'AE',
'GB',
'US',
);
}
} }