From add9569ad50d72d7c435e715d16f5d53a1728738 Mon Sep 17 00:00:00 2001 From: WooCommerce Date: Fri, 13 Sep 2024 10:14:00 +0000 Subject: [PATCH] Updates to 2.9.7 --- changelog.txt | 9 ++ includes/class-wc-eu-vat-admin.php | 23 ++++- .../class-wc-eu-vat-extend-store-endpoint.php | 4 +- includes/class-wc-eu-vat-number.php | 37 +++++-- includes/class-wc-eu-vat-reports.php | 68 +++++++++++++ includes/vies/class-vies-client.php | 2 +- languages/woocommerce-eu-vat-number.pot | 97 +++++++++++-------- woocommerce-eu-vat-number.php | 8 +- 8 files changed, 194 insertions(+), 54 deletions(-) diff --git a/changelog.txt b/changelog.txt index ca8f145..f2fefe3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,14 @@ *** EU VAT Number Changelog *** +2024-09-09 - version 2.9.7 +* Add - Disable reports & display a notice when HPOS is enabled & syncing is disabled. +* Fix - Ensure the proper IP country is shown in the EU VAT section of the order screen. +* Fix - Ensure the VAT Number Field Label can be properly translated. +* Dev - Bump WooCommerce "tested up to" version 9.2. +* Dev - Bump WooCommerce minimum supported version to 9.0. +* Dev - Log API errors to improve debugging. +* Dev - Fix QIT E2E tests and add support for a few new test types. + 2024-07-29 - version 2.9.6 * Dev - Bump WooCommerce "tested up to" version 9.1. * Dev - Bump WooCommerce minimum supported version to 8.9. diff --git a/includes/class-wc-eu-vat-admin.php b/includes/class-wc-eu-vat-admin.php index adce4cd..7fef7c6 100644 --- a/includes/class-wc-eu-vat-admin.php +++ b/includes/class-wc-eu-vat-admin.php @@ -261,12 +261,16 @@ public static function output() { ip_country ) { - echo esc_html( $countries[ $data->billing_country ] ) . ' '; + echo esc_html( $countries[ $data->ip_country ] ) . ' '; if ( $data->billing_country === $data->ip_country ) { echo ''; } elseif ( $data->self_declared ) { - esc_html_e( '(self-declared)', 'woocommerce-eu-vat-number' ); + printf( + '(%s %s)', + esc_html__( 'User self-declared country as', 'woocommerce-eu-vat-number' ), + esc_html( $countries[ $data->billing_country ] ), + ); } else { echo ''; } @@ -703,6 +707,21 @@ public static function is_eu_vat_block_adjusted() { set_transient( $transient_key, $is_adjusted ? 'yes' : 'no', HOUR_IN_SECONDS ); return $is_adjusted; } + + /** + * Get VAT Number field label. + * + * @return string + */ + public static function get_vat_number_field_label() { + $label = get_option( 'woocommerce_eu_vat_number_field_label' ); + + if ( empty( $label ) ) { + return _x( 'VAT number', 'Default Field Label', 'woocommerce-eu-vat-number' ); + } + + return $label; + } } WC_EU_VAT_Admin::init(); diff --git a/includes/class-wc-eu-vat-extend-store-endpoint.php b/includes/class-wc-eu-vat-extend-store-endpoint.php index b290d9c..76acec1 100644 --- a/includes/class-wc-eu-vat-extend-store-endpoint.php +++ b/includes/class-wc-eu-vat-extend-store-endpoint.php @@ -254,7 +254,7 @@ public function vat_number_information() { $is_valid = $validation_data['validation']['valid'] ?? false; $error_code = $validation_data['validation']['code'] ?? false; - if ( ( 'reject' === $fail_handler && ! $is_valid ) || 'api' === $error_code ) { + if ( ( 'reject' === $fail_handler && ! $is_valid ) || 'wc-eu-vat-api-error' === $error_code ) { WC()->session->set( 'vat-number', null ); } @@ -378,7 +378,7 @@ private function set_vat_exemption( $validation ) { case 'accept': $error_code = $validation['validation']['code'] ?? false; - if ( 'api' !== $error_code ) { + if ( 'wc-eu-vat-api-error' !== $error_code ) { WC_EU_VAT_Number::maybe_set_vat_exempt( true, $b_country, $s_country ); } break; diff --git a/includes/class-wc-eu-vat-number.php b/includes/class-wc-eu-vat-number.php index 46501c8..59b0dfe 100644 --- a/includes/class-wc-eu-vat-number.php +++ b/includes/class-wc-eu-vat-number.php @@ -11,6 +11,7 @@ require_once __DIR__ . '/vies/class-vies-client.php'; require_once __DIR__ . '/class-wc-eu-vat-uk-number-api.php'; +require_once __DIR__ . '/class-wc-eu-vat-admin.php'; /** * WC_EU_VAT_Number class. @@ -112,6 +113,30 @@ public static function init() { // Add VAT Number in order endpoint (REST API). add_filter( 'woocommerce_api_order_response', array( __CLASS__, 'add_vat_number_to_order_response' ) ); add_filter( 'woocommerce_rest_prepare_shop_order', array( __CLASS__, 'add_vat_number_to_order_response' ) ); + + // Logs API errors generated by this plugin. + add_action( 'wp_error_added', array( __CLASS__, 'log_api_errors' ), 10, 2 ); + } + + /** + * Logs API errors. + * + * @param string $code Error code. + * @param string $message Error message. + */ + public static function log_api_errors( $code, $message ) { + if ( 'wc-eu-vat-api-error' !== $code ) { + return; + } + + $logger = wc_get_logger(); + + $logger->info( + $message, + array( + 'source' => 'woocommerce-eu-vat-number', + ) + ); } /** @@ -142,7 +167,7 @@ public static function localize_wc_eu_vat_params( $script_handle ) { array( 'eu_countries' => self::get_eu_countries(), 'b2b_required' => get_option( 'woocommerce_eu_vat_number_b2b', 'false' ), - 'input_label' => get_option( 'woocommerce_eu_vat_number_field_label', 'VAT number' ), + 'input_label' => WC_EU_VAT_Admin::get_vat_number_field_label(), 'input_description' => get_option( 'woocommerce_eu_vat_number_field_description', '' ), 'failure_handler' => get_option( 'woocommerce_eu_vat_number_failure_handling', 'reject' ), 'use_shipping_country' => wc_eu_vat_use_shipping_country(), @@ -231,7 +256,7 @@ public static function vat_number_field( $fields ) { } $fields['billing_vat_number'] = array( - 'label' => get_option( 'woocommerce_eu_vat_number_field_label', __( 'VAT number', 'woocommerce-eu-vat-number' ) ), + 'label' => WC_EU_VAT_Admin::get_vat_number_field_label(), 'default' => $user_id > 0 ? get_user_meta( $user_id, 'vat_number', true ) : '', 'required' => false, 'class' => array( @@ -309,7 +334,7 @@ public static function get_ip_country() { public static function vat_number_is_valid( $vat_number, $country, $postcode = '' ) { // The StoreAPI will set $vat_number to null if the user does not enter it. We should show an error in this case. if ( null === $vat_number ) { - return new WP_Error( 'api', __( 'VAT number is required.', 'woocommerce-eu-vat-number' ) ); + return new WP_Error( 'wc-eu-vat-api-error', __( 'VAT number is required.', 'woocommerce-eu-vat-number' ) ); } // Replace unwanted chars on VAT Number. @@ -329,7 +354,7 @@ public static function vat_number_is_valid( $vat_number, $country, $postcode = ' // Return error if VAT Country Code doesn't match or exist. if ( ! isset( self::$country_codes_patterns[ $vat_prefix ] ) || ( $vat_prefix . $vat_number_formatted !== $vat_number ) ) { // translators: %1$s - VAT number field label, %2$s - VAT Number from user, %3$s - Billing country. - return new WP_Error( 'api', sprintf( __( 'You have entered an invalid country code for %1$s (%2$s) for your country (%3$s).', 'woocommerce-eu-vat-number' ), get_option( 'woocommerce_eu_vat_number_field_label', 'VAT number' ), $vat_number, $country ) ); + return new WP_Error( 'wc-eu-vat-api-error', sprintf( __( 'You have entered an invalid country code for %1$s (%2$s) for your country (%3$s).', 'woocommerce-eu-vat-number' ), get_option( 'woocommerce_eu_vat_number_field_label', 'VAT number' ), $vat_number, $country ) ); } if ( ! empty( $cached_result ) ) { @@ -343,7 +368,7 @@ public static function vat_number_is_valid( $vat_number, $country, $postcode = ' $uk_vat_api = new WC_EU_VAT_UK_Number_API(); $is_valid = $uk_vat_api->check_vat_number( $vat_number_formatted ); } catch ( Exception $e ) { - return new WP_Error( 'api', __( 'Error communicating with the VAT validation server - please try again.', 'woocommerce-eu-vat-number' ) ); + return new WP_Error( 'wc-eu-vat-api-error', __( 'Error communicating with the VAT validation server - please try again.', 'woocommerce-eu-vat-number' ) ); } } else { // Check rest of EU countries with VIES. @@ -361,7 +386,7 @@ public static function vat_number_is_valid( $vat_number, $country, $postcode = ' $is_valid = $vies_req->is_valid(); } catch ( SoapFault $e ) { - return new WP_Error( 'api', __( 'Error communicating with the VAT validation server - please try again.', 'woocommerce-eu-vat-number' ) ); + return new WP_Error( 'wc-eu-vat-api-error', __( 'Error communicating with the VAT validation server - please try again.', 'woocommerce-eu-vat-number' ) ); } } } diff --git a/includes/class-wc-eu-vat-reports.php b/includes/class-wc-eu-vat-reports.php index bed8d23..0180b11 100644 --- a/includes/class-wc-eu-vat-reports.php +++ b/includes/class-wc-eu-vat-reports.php @@ -14,13 +14,81 @@ */ class WC_EU_VAT_Reports { + /** + * OrderUtil object. + * + * @var \Automattic\WooCommerce\Utilities\OrderUtil object. + */ + public static $order_util; + /** * Constructor */ public static function init() { + if ( ! function_exists( 'wc_get_container' ) ) { + return; + } + + try { + self::$order_util = wc_get_container()->get( Automattic\WooCommerce\Utilities\OrderUtil::class ); + } catch ( Exception $e ) { + self::$order_util = false; + } + + // The EU VAT reports are incompatible with stores running HPOS with syncing disabled. + if ( self::is_cot_enabled() && ! self::is_cot_sync_enabled() ) { + add_action( 'admin_notices', array( __CLASS__, 'display_hpos_incompatibility_notice' ) ); + return; + } + add_action( 'woocommerce_admin_reports', array( __CLASS__, 'init_reports' ) ); } + /** + * Helper function to get whether custom order tables are enabled or not. + * + * @return bool + */ + public static function is_cot_enabled() { + return self::$order_util && self::$order_util::custom_orders_table_usage_is_enabled(); + } + + /** + * Helper function to check whether custom order tables are in sync or not. + * + * @return bool + */ + public static function is_cot_sync_enabled() { + return self::$order_util && self::$order_util::is_custom_order_tables_in_sync(); + } + + /** + * Displays an admin notice indicating EU VAT reports are disabled on HPOS environments with no syncing. + */ + public static function display_hpos_incompatibility_notice() { + $screen = get_current_screen(); + + // Only display the admin notice on report admin screens. + if ( ! $screen || 'woocommerce_page_wc-reports' !== $screen->id ) { + return; + } + + if ( current_user_can( 'activate_plugins' ) ) { + /* translators: %1$s: Minimum version %2$s: Plugin page link start %3$s Link end */ + printf( + '

%s

%s

', + esc_html__( 'WooCommerce EU VAT Number - Reports Not Available', 'woocommerce-eu-vat-number' ), + sprintf( + // translators: placeholders $1 and $2 are opening tags linking to the WooCommerce documentation on HPOS and data synchronization. Placeholder $3 is a closing link () tag. + esc_html__( 'EU VAT reports are incompatible with the %1$sWooCommerce data storage features%3$s enabled on your store. Please enable %2$stable synchronization%3$s if you wish to use EU VAT reports.', 'woocommerce-eu-vat-number' ), + '', + '', + '', + ) + ); + } + } + /** * Add reports * diff --git a/includes/vies/class-vies-client.php b/includes/vies/class-vies-client.php index 9a00707..9e29e70 100644 --- a/includes/vies/class-vies-client.php +++ b/includes/vies/class-vies-client.php @@ -89,7 +89,7 @@ public function get_soap_client() { $soap_parameters ); } catch ( Exception $e ) { - return new WP_Error( 'api', __( 'Error communicating with the VAT validation server - please try again.', 'woocommerce-eu-vat-number' ) ); + return new WP_Error( 'wc-eu-vat-api-error', __( 'Error communicating with the VAT validation server - please try again.', 'woocommerce-eu-vat-number' ) ); } } diff --git a/languages/woocommerce-eu-vat-number.pot b/languages/woocommerce-eu-vat-number.pot index 6660181..0bc2901 100644 --- a/languages/woocommerce-eu-vat-number.pot +++ b/languages/woocommerce-eu-vat-number.pot @@ -2,10 +2,10 @@ # This file is distributed under the GNU General Public License v3.0. msgid "" msgstr "" -"Project-Id-Version: WooCommerce EU VAT Number 2.9.6\n" +"Project-Id-Version: WooCommerce EU VAT Number 2.9.7\n" "Report-Msgid-Bugs-To: " "https://wordpress.org/support/plugin/woocommerce-eu-vat-number\n" -"POT-Creation-Date: 2024-07-29 14:00:36+00:00\n" +"POT-Creation-Date: 2024-09-09 14:33:52+00:00\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -16,17 +16,16 @@ msgstr "" #: includes/class-wc-eu-vat-admin.php:114 #: includes/class-wc-eu-vat-admin.php:241 -#: includes/class-wc-eu-vat-admin.php:447 -#: includes/class-wc-eu-vat-admin.php:465 -#: includes/class-wc-eu-vat-admin.php:472 +#: includes/class-wc-eu-vat-admin.php:451 +#: includes/class-wc-eu-vat-admin.php:469 +#: includes/class-wc-eu-vat-admin.php:476 #: includes/class-wc-eu-vat-my-account.php:173 #: includes/class-wc-eu-vat-my-account.php:195 #: includes/class-wc-eu-vat-my-account.php:260 #: includes/class-wc-eu-vat-my-account.php:277 -#: includes/class-wc-eu-vat-number.php:199 -#: includes/class-wc-eu-vat-number.php:234 -#: includes/class-wc-eu-vat-number.php:812 -#: includes/class-wc-eu-vat-number.php:835 +#: includes/class-wc-eu-vat-number.php:224 +#: includes/class-wc-eu-vat-number.php:837 +#: includes/class-wc-eu-vat-number.php:860 #: includes/class-wc-eu-vat-privacy.php:147 #: includes/class-wc-eu-vat-report-ec-sales-list.php:216 #: templates/my-account/my-vat-number.php:22 @@ -34,7 +33,7 @@ msgid "VAT number" msgstr "" #: includes/class-wc-eu-vat-admin.php:134 -#: includes/class-wc-eu-vat-admin.php:321 +#: includes/class-wc-eu-vat-admin.php:325 #: includes/class-wc-eu-vat-privacy.php:20 msgid "EU VAT" msgstr "" @@ -64,8 +63,8 @@ msgid "IP Address" msgstr "" #: includes/class-wc-eu-vat-admin.php:256 -#: includes/class-wc-eu-vat-admin.php:274 -#: includes/class-wc-eu-vat-admin.php:282 +#: includes/class-wc-eu-vat-admin.php:278 +#: includes/class-wc-eu-vat-admin.php:286 msgid "Unknown" msgstr "" @@ -73,40 +72,43 @@ msgstr "" msgid "IP Country" msgstr "" -#: includes/class-wc-eu-vat-admin.php:269 -#: includes/class-wc-eu-vat-admin.php:365 -msgid "(self-declared)" +#: includes/class-wc-eu-vat-admin.php:271 +msgid "User self-declared country as" msgstr "" -#: includes/class-wc-eu-vat-admin.php:281 +#: includes/class-wc-eu-vat-admin.php:285 msgid "Billing Country" msgstr "" -#: includes/class-wc-eu-vat-admin.php:353 +#: includes/class-wc-eu-vat-admin.php:357 msgid "(validation failed)" msgstr "" -#: includes/class-wc-eu-vat-admin.php:407 +#: includes/class-wc-eu-vat-admin.php:369 +msgid "(self-declared)" +msgstr "" + +#: includes/class-wc-eu-vat-admin.php:411 #: includes/class-wc-eu-vat-my-account.php:254 -#: includes/class-wc-eu-vat-number.php:814 -#: includes/class-wc-eu-vat-number.php:836 +#: includes/class-wc-eu-vat-number.php:839 +#: includes/class-wc-eu-vat-number.php:861 msgid "billing" msgstr "" -#: includes/class-wc-eu-vat-admin.php:411 +#: includes/class-wc-eu-vat-admin.php:415 #: includes/class-wc-eu-vat-my-account.php:254 -#: includes/class-wc-eu-vat-number.php:814 -#: includes/class-wc-eu-vat-number.php:836 +#: includes/class-wc-eu-vat-number.php:839 +#: includes/class-wc-eu-vat-number.php:861 msgid "shipping" msgstr "" -#: includes/class-wc-eu-vat-admin.php:447 +#: includes/class-wc-eu-vat-admin.php:451 #. translators: %1$s VAT number field label, %2$s VAT number, %3$s Country %4$s #. country type: billing/shipping. msgid "You have entered an invalid %1$s (%2$s) for your %4$s country (%3$s)." msgstr "" -#: includes/class-wc-eu-vat-admin.php:552 +#: includes/class-wc-eu-vat-admin.php:556 #. translators: %1$s Opening strong tag, %2$s Closing strong tag, %3$s Break #. tag. msgid "" @@ -118,7 +120,7 @@ msgid "" "from %1$sNorthern Ireland%2$s." msgstr "" -#: includes/class-wc-eu-vat-admin.php:563 +#: includes/class-wc-eu-vat-admin.php:567 #. translators: %1$s Opening strong tag, %2$s Closing strong tag. msgid "" "By using %1$sWooCommerce EU VAT Number%2$s plugin, you've agreed that the " @@ -127,11 +129,11 @@ msgid "" "tax specific questions." msgstr "" -#: includes/class-wc-eu-vat-admin.php:568 +#: includes/class-wc-eu-vat-admin.php:572 msgid "I understand" msgstr "" -#: includes/class-wc-eu-vat-admin.php:639 +#: includes/class-wc-eu-vat-admin.php:643 #. translators: %1$s - , %2$s - , %3$s - Link to edit checkout #. page, %4$s - closing tag msgid "" @@ -186,11 +188,11 @@ msgstr "" msgid "VAT number updated successfully!" msgstr "" -#: includes/class-wc-eu-vat-number.php:312 +#: includes/class-wc-eu-vat-number.php:337 msgid "VAT number is required." msgstr "" -#: includes/class-wc-eu-vat-number.php:332 +#: includes/class-wc-eu-vat-number.php:357 #. translators: %1$s - VAT number field label, %2$s - VAT Number from user, #. %3$s - Billing country. msgid "" @@ -198,29 +200,29 @@ msgid "" "(%3$s)." msgstr "" -#: includes/class-wc-eu-vat-number.php:346 -#: includes/class-wc-eu-vat-number.php:364 +#: includes/class-wc-eu-vat-number.php:371 +#: includes/class-wc-eu-vat-number.php:389 #: includes/vies/class-vies-client.php:92 msgid "Error communicating with the VAT validation server - please try again." msgstr "" -#: includes/class-wc-eu-vat-number.php:668 +#: includes/class-wc-eu-vat-number.php:693 #. translators: %s: VAT Number msgid "VAT Number: %s" msgstr "" -#: includes/class-wc-eu-vat-number.php:811 +#: includes/class-wc-eu-vat-number.php:836 #. translators: 1: VAT number field label, 2: VAT Number, 3: Address type, 4: #. Country msgid "You have entered an invalid %1$s (%2$s) for your %3$s country (%4$s)." msgstr "" -#: includes/class-wc-eu-vat-number.php:834 +#: includes/class-wc-eu-vat-number.php:859 #. translators: 1: VAT number field label, 2: Address type, 3: Billing country msgid "%1$s is a required field for your %2$s country (%3$s)." msgstr "" -#: includes/class-wc-eu-vat-number.php:853 +#: includes/class-wc-eu-vat-number.php:878 #. translators: 1: Ip Address. msgid "" "Your IP Address (%1$s) does not match your billing country (%2$s). European " @@ -370,15 +372,31 @@ msgstr "" msgid "No taxes found in this period" msgstr "" -#: includes/class-wc-eu-vat-reports.php:33 +#: includes/class-wc-eu-vat-reports.php:80 +#. translators: %1$s: Minimum version %2$s: Plugin page link start %3$s Link +#. end +msgid "WooCommerce EU VAT Number - Reports Not Available" +msgstr "" + +#: includes/class-wc-eu-vat-reports.php:83 +#. translators: placeholders $1 and $2 are opening tags linking to the +#. WooCommerce documentation on HPOS and data synchronization. Placeholder $3 +#. is a closing link () tag. +msgid "" +"EU VAT reports are incompatible with the %1$sWooCommerce data storage " +"features%3$s enabled on your store. Please enable %2$stable " +"synchronization%3$s if you wish to use EU VAT reports." +msgstr "" + +#: includes/class-wc-eu-vat-reports.php:101 msgid "EC Sales List" msgstr "" -#: includes/class-wc-eu-vat-reports.php:39 +#: includes/class-wc-eu-vat-reports.php:107 msgid "EU VAT by state" msgstr "" -#: includes/class-wc-eu-vat-reports.php:45 +#: includes/class-wc-eu-vat-reports.php:113 msgid "Non EU Sales" msgstr "" @@ -626,6 +644,7 @@ msgstr "" msgid "https://woocommerce.com/" msgstr "" +#: includes/class-wc-eu-vat-admin.php:720 #: includes/data/eu-vat-number-settings.php:45 #: includes/data/eu-vat-number-settings.php:46 msgctxt "Default Field Label" diff --git a/woocommerce-eu-vat-number.php b/woocommerce-eu-vat-number.php index 0092fa9..460dbda 100644 --- a/woocommerce-eu-vat-number.php +++ b/woocommerce-eu-vat-number.php @@ -4,15 +4,15 @@ * Requires Plugins: woocommerce * Plugin URI: https://woocommerce.com/products/eu-vat-number/ * Description: The EU VAT Number extension lets you collect and validate EU VAT numbers during checkout to identify B2B transactions verses B2C. IP Addresses can also be validated to ensure they match the billing address. EU businesses with a valid VAT number can have their VAT removed prior to payment. - * Version: 2.9.6 + * Version: 2.9.7 * Author: WooCommerce * Author URI: https://woocommerce.com/ * Text Domain: woocommerce-eu-vat-number * Domain Path: /languages * Requires at least: 6.4 * Tested up to: 6.6 - * WC requires at least: 8.9 - * WC tested up to: 9.1 + * WC requires at least: 9.0 + * WC tested up to: 9.2 * Requires PHP: 7.4 * PHP tested up to: 8.3 * @@ -26,7 +26,7 @@ // phpcs:disable WordPress.Files.FileName -define( 'WC_EU_VAT_VERSION', '2.9.6' ); // WRCS: DEFINED_VERSION. +define( 'WC_EU_VAT_VERSION', '2.9.7' ); // WRCS: DEFINED_VERSION. define( 'WC_EU_VAT_FILE', __FILE__ ); define( 'WC_EU_ABSPATH', __DIR__ . '/' ); define( 'WC_EU_VAT_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );