Merge branch 'trunk' into add/feedback-label-action
This commit is contained in:
commit
85893dd018
|
@ -0,0 +1,20 @@
|
|||
name: 'Close stale needs-feedback issues'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 21 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: "As a part of this repository’s maintenance, this issue is being marked as stale due to inactivity. Please feel free to comment on it in case we missed something.\n\n###### After 7 days with no activity this issue will be automatically be closed."
|
||||
close-issue-message: 'This issue was closed because it has been 14 days with no activity.'
|
||||
days-before-issue-stale: 7
|
||||
days-before-issue-close: 7
|
||||
days-before-pr-close: -1
|
||||
only-issue-label: 'needs feedback'
|
||||
close-issue-label: "category: can't reproduce"
|
||||
debug-only: true
|
|
@ -348,6 +348,12 @@ a.button {
|
|||
.woocommerce,
|
||||
.woocommerce-page {
|
||||
|
||||
&.is-dark-theme {
|
||||
.select2-dropdown {
|
||||
color: var(--global--color-dark-gray);
|
||||
}
|
||||
}
|
||||
|
||||
table.shop_table {
|
||||
|
||||
td,
|
||||
|
|
|
@ -62,6 +62,9 @@
|
|||
shippingMethod.trigger( 'change:methods' );
|
||||
shippingMethod.changes = {};
|
||||
shippingMethod.trigger( 'saved:methods' );
|
||||
|
||||
// Overrides the onbeforeunload callback added by settings.js.
|
||||
window.onbeforeunload = null;
|
||||
} else {
|
||||
window.alert( data.strings.save_failed );
|
||||
}
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
== Changelog ==
|
||||
|
||||
= 5.2.0 RC 2021-03-30 =
|
||||
|
||||
* Update - WooCommerce Admin package 2.1.4. #29520
|
||||
* Fix - Don't remove existing coupons from order when an invalid REST API request for updating coupons is submitted. #29474
|
||||
* Fix - Wrong logic for including or excluding the payments step in the list of completed tasks in the onboarding wizard. #29518
|
||||
|
||||
**WooCommerce Admin - 2.1.4**
|
||||
|
||||
* Fix - Adding New Zealand and Ireland to selective bundle option, previously missed. #6649
|
||||
|
||||
= 5.2.0 beta 2021-03-23 =
|
||||
|
||||
**WooCommerce**
|
||||
|
@ -42,6 +52,8 @@
|
|||
* Fix - add validation of the posted country codes on checkout. #28849
|
||||
* Fix - Correctly display pagination arrows on RTL languages. #28523
|
||||
* Fix - Invalid refund amount error on $0 refund when number of decimals is equal to 0. #27277
|
||||
* Fix - "Sale" badge misaligned on products when displaying 1 item per row. #29425
|
||||
* Fix - Revert a replacement of wp_redirect to wp_safe_redirect in WC_Checkout::process_order_payment that caused issues in the default PayPal interface. #29459
|
||||
* Tweak - Added the Mercado Pago logo into the assets/images folder in order to use it in the payments setup task. #29365
|
||||
* Tweak - Update the contributor guidelines. #29150
|
||||
* Tweak - Introduced phone number input validation. #27242
|
||||
|
@ -1342,6 +1354,7 @@
|
|||
* Fix - Don't show duplicated update notifications on Woo Screens. #25828
|
||||
* Fix - Escape MaxMind database URL. #25682
|
||||
* Fix - System status report should correctly identify inactive package. #25830
|
||||
* Fix - "Sale" badge misaligned on products when displaying 1 item per row. #29425
|
||||
* Dev - Added support for placeholder attribute in quantity inputs. #25418
|
||||
* Dev - Added `tax_status` and `tax_class` columns to the product meta data lookup table. #25428
|
||||
* Dev - Introduced `woocommerce_top_rated_widget_args` filter. #25320
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
],
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"automattic/jetpack-autoloader": "2.9.1",
|
||||
"automattic/jetpack-autoloader": "2.10.1",
|
||||
"automattic/jetpack-constants": "1.5.1",
|
||||
"composer/installers": "~1.7",
|
||||
"maxmind-db/reader": "1.6.0",
|
||||
"pelago/emogrifier": "3.1.0",
|
||||
"psr/container": "1.0.0",
|
||||
"woocommerce/action-scheduler": "3.1.6",
|
||||
"woocommerce/woocommerce-admin": "2.1.3",
|
||||
"woocommerce/woocommerce-admin": "2.1.4",
|
||||
"woocommerce/woocommerce-blocks": "4.7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
|
@ -4,32 +4,39 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "dc5e21e29d4fb70bba776d20112c74f0",
|
||||
"content-hash": "b1d6d94c8cfae572ab27c288c6865787",
|
||||
"packages": [
|
||||
{
|
||||
"name": "automattic/jetpack-autoloader",
|
||||
"version": "v2.9.1",
|
||||
"version": "2.10.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Automattic/jetpack-autoloader.git",
|
||||
"reference": "d6ca2cc26ad6963e1be19b3338a9e98f40d9bd88"
|
||||
"reference": "20393c4677765c3e737dcb5aee7a3f7b90dce4b3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/d6ca2cc26ad6963e1be19b3338a9e98f40d9bd88",
|
||||
"reference": "d6ca2cc26ad6963e1be19b3338a9e98f40d9bd88",
|
||||
"url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/20393c4677765c3e737dcb5aee7a3f7b90dce4b3",
|
||||
"reference": "20393c4677765c3e737dcb5aee7a3f7b90dce4b3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.1 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"automattic/jetpack-changelogger": "^1.1",
|
||||
"yoast/phpunit-polyfills": "0.2.0"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "Automattic\\Jetpack\\Autoloader\\CustomAutoloaderPlugin",
|
||||
"mirror-repo": "Automattic/jetpack-autoloader"
|
||||
"mirror-repo": "Automattic/jetpack-autoloader",
|
||||
"changelogger": {
|
||||
"link-template": "https://github.com/Automattic/jetpack-autoloader/compare/v${old}...v${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "2.10.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
|
@ -45,9 +52,9 @@
|
|||
],
|
||||
"description": "Creates a custom autoloader for a plugin or theme.",
|
||||
"support": {
|
||||
"source": "https://github.com/Automattic/jetpack-autoloader/tree/v2.9.1"
|
||||
"source": "https://github.com/Automattic/jetpack-autoloader/tree/2.10.1"
|
||||
},
|
||||
"time": "2021-02-05T19:07:06+00:00"
|
||||
"time": "2021-03-30T15:15:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "automattic/jetpack-constants",
|
||||
|
@ -523,16 +530,16 @@
|
|||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-admin",
|
||||
"version": "2.1.3",
|
||||
"version": "2.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/woocommerce-admin.git",
|
||||
"reference": "60f4297838569341ae88738a4a8a8090889faaac"
|
||||
"reference": "f992b8c8664e72b00ee7283ba1d34e74e4b67ab0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/60f4297838569341ae88738a4a8a8090889faaac",
|
||||
"reference": "60f4297838569341ae88738a4a8a8090889faaac",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/f992b8c8664e72b00ee7283ba1d34e74e4b67ab0",
|
||||
"reference": "f992b8c8664e72b00ee7283ba1d34e74e4b67ab0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -566,9 +573,9 @@
|
|||
"homepage": "https://github.com/woocommerce/woocommerce-admin",
|
||||
"support": {
|
||||
"issues": "https://github.com/woocommerce/woocommerce-admin/issues",
|
||||
"source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.1.3"
|
||||
"source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.1.4"
|
||||
},
|
||||
"time": "2021-03-15T04:42:40+00:00"
|
||||
"time": "2021-03-29T11:59:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-blocks",
|
||||
|
|
|
@ -1633,6 +1633,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
continue;
|
||||
}
|
||||
$saved_rate_ids[] = $tax->get_rate_id();
|
||||
$tax->set_rate( $tax->get_rate_id() );
|
||||
$tax->set_tax_total( isset( $cart_taxes[ $tax->get_rate_id() ] ) ? $cart_taxes[ $tax->get_rate_id() ] : 0 );
|
||||
$tax->set_label( WC_Tax::get_rate_label( $tax->get_rate_id() ) );
|
||||
$tax->set_shipping_tax_total( ! empty( $shipping_taxes[ $tax->get_rate_id() ] ) ? $shipping_taxes[ $tax->get_rate_id() ] : 0 );
|
||||
|
|
|
@ -178,7 +178,7 @@ if ( ! class_exists( 'WC_Admin_Dashboard_Setup', false ) ) :
|
|||
}
|
||||
|
||||
// payments can't be used when woocommerce-payments exists and country is US.
|
||||
if ( $is_woo_payment_installed || 'US' === $country ) {
|
||||
if ( $is_woo_payment_installed && 'US' === $country ) {
|
||||
unset( $this->tasks['payments'] );
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render columm: thumb.
|
||||
* Render column: thumb.
|
||||
*/
|
||||
protected function render_thumb_column() {
|
||||
echo '<a href="' . esc_url( get_edit_post_link( $this->object->get_id() ) ) . '">' . $this->object->get_image( 'thumbnail' ) . '</a>'; // WPCS: XSS ok.
|
||||
|
@ -203,21 +203,21 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render columm: sku.
|
||||
* Render column: sku.
|
||||
*/
|
||||
protected function render_sku_column() {
|
||||
echo $this->object->get_sku() ? esc_html( $this->object->get_sku() ) : '<span class="na">–</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render columm: price.
|
||||
* Render column: price.
|
||||
*/
|
||||
protected function render_price_column() {
|
||||
echo $this->object->get_price_html() ? wp_kses_post( $this->object->get_price_html() ) : '<span class="na">–</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render columm: product_cat.
|
||||
* Render column: product_cat.
|
||||
*/
|
||||
protected function render_product_cat_column() {
|
||||
$terms = get_the_terms( $this->object->get_id(), 'product_cat' );
|
||||
|
@ -234,7 +234,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render columm: product_tag.
|
||||
* Render column: product_tag.
|
||||
*/
|
||||
protected function render_product_tag_column() {
|
||||
$terms = get_the_terms( $this->object->get_id(), 'product_tag' );
|
||||
|
@ -251,7 +251,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render columm: featured.
|
||||
* Render column: featured.
|
||||
*/
|
||||
protected function render_featured_column() {
|
||||
$url = wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_feature_product&product_id=' . $this->object->get_id() ), 'woocommerce-feature-product' );
|
||||
|
@ -265,7 +265,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render columm: is_in_stock.
|
||||
* Render column: is_in_stock.
|
||||
*/
|
||||
protected function render_is_in_stock_column() {
|
||||
if ( $this->object->is_on_backorder() ) {
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
/**
|
||||
* WooCommerce Settings Page/Tab
|
||||
*
|
||||
* @author WooThemes
|
||||
* @category Admin
|
||||
* @package WooCommerce\Admin
|
||||
* @version 2.1.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'WC_Settings_Page', false ) ) :
|
||||
|
@ -66,7 +64,7 @@ if ( ! class_exists( 'WC_Settings_Page', false ) ) :
|
|||
/**
|
||||
* Add this page to settings.
|
||||
*
|
||||
* @param array $pages
|
||||
* @param array $pages The pages array to add this page to.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
|
@ -102,7 +100,7 @@ if ( ! class_exists( 'WC_Settings_Page', false ) ) :
|
|||
|
||||
$sections = $this->get_sections();
|
||||
|
||||
if ( empty( $sections ) || 1 === sizeof( $sections ) ) {
|
||||
if ( empty( $sections ) || 1 === count( $sections ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -111,7 +109,8 @@ if ( ! class_exists( 'WC_Settings_Page', false ) ) :
|
|||
$array_keys = array_keys( $sections );
|
||||
|
||||
foreach ( $sections as $id => $label ) {
|
||||
echo '<li><a href="' . admin_url( 'admin.php?page=wc-settings&tab=' . $this->id . '§ion=' . sanitize_title( $id ) ) . '" class="' . ( $current_section == $id ? 'current' : '' ) . '">' . $label . '</a> ' . ( end( $array_keys ) == $id ? '' : '|' ) . ' </li>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<li><a href="' . admin_url( 'admin.php?page=wc-settings&tab=' . $this->id . '§ion=' . sanitize_title( $id ) ) . '" class="' . ( $current_section === $id ? 'current' : '' ) . '">' . esc_html( $label ) . '</a> ' . ( end( $array_keys ) === $id ? '' : '|' ) . ' </li>';
|
||||
}
|
||||
|
||||
echo '</ul><br class="clear" />';
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
/**
|
||||
* WooCommerce Tax Settings
|
||||
*
|
||||
* @author WooThemes
|
||||
* @category Admin
|
||||
* @package WooCommerce\Admin
|
||||
* @version 2.1.0
|
||||
*/
|
||||
|
@ -66,6 +64,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
|||
$tax_classes = WC_Tax::get_tax_classes();
|
||||
|
||||
foreach ( $tax_classes as $class ) {
|
||||
/* translators: $s tax rate section name */
|
||||
$sections[ sanitize_title( $class ) ] = sprintf( __( '%s rates', 'woocommerce' ), $class );
|
||||
}
|
||||
|
||||
|
@ -95,7 +94,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
|||
|
||||
$tax_classes = WC_Tax::get_tax_class_slugs();
|
||||
|
||||
if ( 'standard' === $current_section || in_array( $current_section, $tax_classes, true ) ) {
|
||||
if ( 'standard' === $current_section || in_array( $current_section, array_filter( $tax_classes ), true ) ) {
|
||||
$this->output_tax_rates();
|
||||
} else {
|
||||
$settings = $this->get_settings();
|
||||
|
@ -149,7 +148,19 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
|||
}
|
||||
|
||||
foreach ( $added as $name ) {
|
||||
WC_Tax::create_tax_class( $name );
|
||||
$tax_class = WC_Tax::create_tax_class( $name );
|
||||
|
||||
// Display any error that could be triggered while creating tax classes.
|
||||
if ( is_wp_error( $tax_class ) ) {
|
||||
WC_Admin_Settings::add_error(
|
||||
sprintf(
|
||||
/* translators: 1: tax class name 2: error message */
|
||||
esc_html__( 'Additional tax class "%1$s" couldn\'t be saved. %2$s.', 'woocommerce' ),
|
||||
esc_html( $name ),
|
||||
$tax_class->get_error_message()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -201,6 +212,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
|||
'wc_tax_nonce' => wp_create_nonce( 'wc_tax_nonce-class:' . $current_class ),
|
||||
'base_url' => $base_url,
|
||||
'rates' => array_values( WC_Tax::get_rates_for_tax_class( $current_class ) ),
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
'page' => ! empty( $_GET['p'] ) ? absint( $_GET['p'] ) : 1,
|
||||
'limit' => 100,
|
||||
'countries' => $countries,
|
||||
|
@ -278,6 +290,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
|||
'tax_rate_priority',
|
||||
);
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
foreach ( $tax_rate_keys as $tax_rate_key ) {
|
||||
if ( isset( $_POST[ $tax_rate_key ], $_POST[ $tax_rate_key ][ $key ] ) ) {
|
||||
$tax_rate[ $tax_rate_key ] = wc_clean( wp_unslash( $_POST[ $tax_rate_key ][ $key ] ) );
|
||||
|
@ -288,6 +301,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
|||
$tax_rate['tax_rate_shipping'] = isset( $_POST['tax_rate_shipping'][ $key ] ) ? 1 : 0;
|
||||
$tax_rate['tax_rate_order'] = $order;
|
||||
$tax_rate['tax_rate_class'] = $class;
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
|
||||
return $tax_rate;
|
||||
}
|
||||
|
@ -298,7 +312,8 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
|||
public function save_tax_rates() {
|
||||
global $wpdb;
|
||||
|
||||
$current_class = sanitize_title( $this->get_current_tax_class() );
|
||||
$current_class = sanitize_title( $this->get_current_tax_class() );
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.Missing
|
||||
$posted_countries = wc_clean( wp_unslash( $_POST['tax_rate_country'] ) );
|
||||
|
||||
// get the tax rate id of the first submited row.
|
||||
|
@ -310,13 +325,14 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
|||
$index = isset( $tax_rate_order ) ? $tax_rate_order : 0;
|
||||
|
||||
// Loop posted fields.
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
foreach ( $posted_countries as $key => $value ) {
|
||||
$mode = ( 0 === strpos( $key, 'new-' ) ) ? 'insert' : 'update';
|
||||
$tax_rate = $this->get_posted_tax_rate( $key, $index ++, $current_class );
|
||||
|
||||
if ( 'insert' === $mode ) {
|
||||
$tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate );
|
||||
} elseif ( 1 === absint( $_POST['remove_tax_rate'][ $key ] ) ) {
|
||||
} elseif ( isset( $_POST['remove_tax_rate'][ $key ] ) && 1 === absint( $_POST['remove_tax_rate'][ $key ] ) ) {
|
||||
$tax_rate_id = absint( $key );
|
||||
WC_Tax::_delete_tax_rate( $tax_rate_id );
|
||||
continue;
|
||||
|
@ -332,6 +348,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
|||
WC_Tax::_update_tax_rate_cities( $tax_rate_id, wc_clean( wp_unslash( $_POST['tax_rate_city'][ $key ] ) ) );
|
||||
}
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -175,6 +175,10 @@ final class WC_Cart_Session {
|
|||
if ( $update_cart_session || is_null( WC()->session->get( 'cart_totals', null ) ) ) {
|
||||
WC()->session->set( 'cart', $this->get_cart_for_session() );
|
||||
$this->cart->calculate_totals();
|
||||
|
||||
if ( $merge_saved_cart ) {
|
||||
$this->persistent_cart_update();
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a re-order, redirect to the cart page to get rid of the `order_again` query string.
|
||||
|
|
|
@ -51,6 +51,9 @@ class WC_Comments {
|
|||
|
||||
// Set comment type.
|
||||
add_action( 'preprocess_comment', array( __CLASS__, 'update_comment_type' ), 1 );
|
||||
|
||||
// Validate product reviews if requires verified owners.
|
||||
add_action( 'pre_comment_on_post', array( __CLASS__, 'validate_product_review_verified_owners' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -444,6 +447,36 @@ class WC_Comments {
|
|||
return $comment_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate product reviews if requires a verified owner.
|
||||
*
|
||||
* @param int $comment_post_id Post ID.
|
||||
*/
|
||||
public static function validate_product_review_verified_owners( $comment_post_id ) {
|
||||
// Only validate if option is enabled.
|
||||
if ( 'yes' !== get_option( 'woocommerce_review_rating_verification_required' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate only products.
|
||||
if ( 'product' !== get_post_type( $comment_post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if is a verified owner.
|
||||
if ( wc_customer_bought_product( '', get_current_user_id(), $comment_post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_die(
|
||||
esc_html__( 'Only logged in customers who have purchased this product may leave a review.', 'woocommerce' ),
|
||||
esc_html__( 'Reviews can only be left by "verified owners"', 'woocommerce' ),
|
||||
array(
|
||||
'code' => 403,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a comment is of the default type.
|
||||
*
|
||||
|
|
|
@ -75,7 +75,7 @@ class WC_Session_Handler extends WC_Session {
|
|||
add_action( 'wp_logout', array( $this, 'destroy_session' ) );
|
||||
|
||||
if ( ! is_user_logged_in() ) {
|
||||
add_filter( 'nonce_user_logged_out', array( $this, 'nonce_user_logged_out' ) );
|
||||
add_filter( 'nonce_user_logged_out', array( $this, 'maybe_update_nonce_user_logged_out' ), 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,6 +187,25 @@ class WC_Session_Handler extends WC_Session {
|
|||
return $customer_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session unique ID for requests if session is initialized or user ID if logged in.
|
||||
* Introduced to help with unit tests.
|
||||
*
|
||||
* @since 5.3.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_customer_unique_id() {
|
||||
$customer_id = '';
|
||||
|
||||
if ( $this->has_session() && $this->_customer_id ) {
|
||||
$customer_id = $this->_customer_id;
|
||||
} elseif ( is_user_logged_in() ) {
|
||||
$customer_id = (string) get_current_user_id();
|
||||
}
|
||||
|
||||
return $customer_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the session cookie, if set. Otherwise return false.
|
||||
*
|
||||
|
@ -288,13 +307,33 @@ class WC_Session_Handler extends WC_Session {
|
|||
/**
|
||||
* When a user is logged out, ensure they have a unique nonce by using the customer/session ID.
|
||||
*
|
||||
* @deprecated 5.3.0
|
||||
* @param int $uid User ID.
|
||||
* @return string
|
||||
* @return int|string
|
||||
*/
|
||||
public function nonce_user_logged_out( $uid ) {
|
||||
wc_deprecated_function( 'WC_Session_Handler::nonce_user_logged_out', '5.3', 'WC_Session_Handler::maybe_update_nonce_user_logged_out' );
|
||||
|
||||
return $this->has_session() && $this->_customer_id ? $this->_customer_id : $uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a user is logged out, ensure they have a unique nonce to manage cart and more using the customer/session ID.
|
||||
* This filter runs everything `wp_verify_nonce()` and `wp_create_nonce()` gets called.
|
||||
*
|
||||
* @since 5.3.0
|
||||
* @param int $uid User ID.
|
||||
* @param string $action The nonce action.
|
||||
* @return int|string
|
||||
*/
|
||||
public function maybe_update_nonce_user_logged_out( $uid, $action ) {
|
||||
if ( Automattic\WooCommerce\Utilities\StringUtil::starts_with( $action, 'woocommerce' ) ) {
|
||||
return $this->has_session() && $this->_customer_id ? $this->_customer_id : $uid;
|
||||
}
|
||||
|
||||
return $uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup session data from the database and clear caches.
|
||||
*/
|
||||
|
|
|
@ -198,7 +198,7 @@ class WC_Structured_Data {
|
|||
$markup = array(
|
||||
'@type' => 'Product',
|
||||
'@id' => $permalink . '#product', // Append '#product' to differentiate between this @id and the @id generated for the Breadcrumblist.
|
||||
'name' => $product->get_name(),
|
||||
'name' => wp_kses_post( $product->get_name() ),
|
||||
'url' => $permalink,
|
||||
'description' => wp_strip_all_tags( do_shortcode( $product->get_short_description() ? $product->get_short_description() : $product->get_description() ) ),
|
||||
);
|
||||
|
@ -477,7 +477,7 @@ class WC_Structured_Data {
|
|||
),
|
||||
'itemOffered' => array(
|
||||
'@type' => 'Product',
|
||||
'name' => apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, $is_visible ),
|
||||
'name' => wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, $is_visible ) ),
|
||||
'sku' => $product_exists ? $product->get_sku() : '',
|
||||
'image' => $product_exists ? wp_get_attachment_image_url( $product->get_image_id() ) : '',
|
||||
'url' => $is_visible ? get_permalink( $product->get_id() ) : get_home_url(),
|
||||
|
|
|
@ -815,6 +815,7 @@ class WC_Tax {
|
|||
|
||||
$existing = self::get_tax_classes();
|
||||
$existing_slugs = self::get_tax_class_slugs();
|
||||
$name = wc_clean( $name );
|
||||
|
||||
if ( in_array( $name, $existing, true ) ) {
|
||||
return new WP_Error( 'tax_class_exists', __( 'Tax class already exists', 'woocommerce' ) );
|
||||
|
@ -824,6 +825,11 @@ class WC_Tax {
|
|||
$slug = sanitize_title( $name );
|
||||
}
|
||||
|
||||
// Stop if there's no slug.
|
||||
if ( ! $slug ) {
|
||||
return new WP_Error( 'tax_class_slug_invalid', __( 'Tax class slug is invalid', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
if ( in_array( $slug, $existing_slugs, true ) ) {
|
||||
return new WP_Error( 'tax_class_slug_exists', __( 'Tax class slug already exists', 'woocommerce' ) );
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
*
|
||||
* Handles requests to the /taxes endpoint.
|
||||
*
|
||||
* @author WooThemes
|
||||
* @category API
|
||||
* @package WooCommerce\RestApi
|
||||
* @since 3.0.0
|
||||
*/
|
||||
|
@ -40,67 +38,79 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
* Register the routes for taxes.
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base,
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
|
||||
'args' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/(?P<id>[\d]+)',
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'update_item' ),
|
||||
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => array( $this, 'delete_item' ),
|
||||
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'force' => array(
|
||||
'default' => false,
|
||||
'type' => 'boolean',
|
||||
'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ),
|
||||
'args' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'update_item' ),
|
||||
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => array( $this, 'delete_item' ),
|
||||
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'force' => array(
|
||||
'default' => false,
|
||||
'type' => 'boolean',
|
||||
'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array(
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/batch',
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'batch_items' ),
|
||||
'permission_callback' => array( $this, 'batch_items_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_batch_schema' ),
|
||||
) );
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'batch_items' ),
|
||||
'permission_callback' => array( $this, 'batch_items_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_batch_schema' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,7 +210,7 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
public function get_items( $request ) {
|
||||
global $wpdb;
|
||||
|
||||
$prepared_args = array();
|
||||
$prepared_args = array();
|
||||
$prepared_args['order'] = $request['order'];
|
||||
$prepared_args['number'] = $request['per_page'];
|
||||
if ( ! empty( $request['offset'] ) ) {
|
||||
|
@ -208,9 +218,10 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
} else {
|
||||
$prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number'];
|
||||
}
|
||||
$orderby_possibles = array(
|
||||
'id' => 'tax_rate_id',
|
||||
'order' => 'tax_rate_order',
|
||||
$orderby_possibles = array(
|
||||
'id' => 'tax_rate_id',
|
||||
'order' => 'tax_rate_order',
|
||||
'priority' => 'tax_rate_priority',
|
||||
);
|
||||
$prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
|
||||
$prepared_args['class'] = $request['class'];
|
||||
|
@ -223,30 +234,42 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
*/
|
||||
$prepared_args = apply_filters( 'woocommerce_rest_tax_query', $prepared_args, $request );
|
||||
|
||||
$query = "
|
||||
$orderby = sanitize_key( $prepared_args['orderby'] ) . ' ' . sanitize_key( $prepared_args['order'] );
|
||||
$query = "
|
||||
SELECT *
|
||||
FROM {$wpdb->prefix}woocommerce_tax_rates
|
||||
WHERE 1 = 1
|
||||
%s
|
||||
ORDER BY {$orderby}
|
||||
LIMIT %%d, %%d
|
||||
";
|
||||
|
||||
$wpdb_prepare_args = array(
|
||||
$prepared_args['offset'],
|
||||
$prepared_args['number'],
|
||||
);
|
||||
|
||||
// Filter by tax class.
|
||||
if ( ! empty( $prepared_args['class'] ) ) {
|
||||
if ( empty( $prepared_args['class'] ) ) {
|
||||
$query = sprintf( $query, '' );
|
||||
} else {
|
||||
$class = 'standard' !== $prepared_args['class'] ? sanitize_title( $prepared_args['class'] ) : '';
|
||||
$query .= " AND tax_rate_class = '$class'";
|
||||
array_unshift( $wpdb_prepare_args, $class );
|
||||
$query = sprintf( $query, 'WHERE tax_rate_class = %s' );
|
||||
}
|
||||
|
||||
// Order tax rates.
|
||||
$order_by = sprintf( ' ORDER BY %s', sanitize_key( $prepared_args['orderby'] ) );
|
||||
|
||||
// Pagination.
|
||||
$pagination = sprintf( ' LIMIT %d, %d', $prepared_args['offset'], $prepared_args['number'] );
|
||||
|
||||
// Query taxes.
|
||||
$results = $wpdb->get_results( $query . $order_by . $pagination );
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
|
||||
$results = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
$query,
|
||||
$wpdb_prepare_args
|
||||
)
|
||||
);
|
||||
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
$taxes = array();
|
||||
foreach ( $results as $tax ) {
|
||||
$data = $this->prepare_item_for_response( $tax, $request );
|
||||
$data = $this->prepare_item_for_response( $tax, $request );
|
||||
$taxes[] = $this->prepare_response_for_collection( $data );
|
||||
}
|
||||
|
||||
|
@ -254,10 +277,18 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
|
||||
// Store pagination values for headers then unset for count query.
|
||||
$per_page = (int) $prepared_args['number'];
|
||||
$page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
|
||||
$page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
|
||||
|
||||
// Query only for ids.
|
||||
$wpdb->get_results( str_replace( 'SELECT *', 'SELECT tax_rate_id', $query ) );
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
|
||||
$query = str_replace( 'SELECT *', 'SELECT tax_rate_id', $query );
|
||||
$wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
$query,
|
||||
$wpdb_prepare_args
|
||||
)
|
||||
);
|
||||
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
// Calculate totals.
|
||||
$total_taxes = (int) $wpdb->num_rows;
|
||||
|
@ -287,13 +318,13 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
* Take tax data from the request and return the updated or newly created rate.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @param stdClass|null $current Existing tax object.
|
||||
* @param stdClass|null $current Existing tax object.
|
||||
* @return object
|
||||
*/
|
||||
protected function create_or_update_tax( $request, $current = null ) {
|
||||
$id = absint( isset( $request['id'] ) ? $request['id'] : 0 );
|
||||
$data = array();
|
||||
$fields = array(
|
||||
$id = absint( isset( $request['id'] ) ? $request['id'] : 0 );
|
||||
$data = array();
|
||||
$fields = array(
|
||||
'tax_rate_country',
|
||||
'tax_rate_state',
|
||||
'tax_rate',
|
||||
|
@ -321,25 +352,25 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
|
||||
// Add to data array.
|
||||
switch ( $key ) {
|
||||
case 'tax_rate_priority' :
|
||||
case 'tax_rate_compound' :
|
||||
case 'tax_rate_shipping' :
|
||||
case 'tax_rate_order' :
|
||||
case 'tax_rate_priority':
|
||||
case 'tax_rate_compound':
|
||||
case 'tax_rate_shipping':
|
||||
case 'tax_rate_order':
|
||||
$data[ $field ] = absint( $request[ $key ] );
|
||||
break;
|
||||
case 'tax_rate_class' :
|
||||
case 'tax_rate_class':
|
||||
$data[ $field ] = 'standard' !== $request['tax_rate_class'] ? $request['tax_rate_class'] : '';
|
||||
break;
|
||||
default :
|
||||
default:
|
||||
$data[ $field ] = wc_clean( $request[ $key ] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $id ) {
|
||||
WC_Tax::_update_tax_rate( $id, $data );
|
||||
} else {
|
||||
if ( ! $id ) {
|
||||
$id = WC_Tax::_insert_tax_rate( $data );
|
||||
} elseif ( $data ) {
|
||||
WC_Tax::_update_tax_rate( $id, $data );
|
||||
}
|
||||
|
||||
// Add locales.
|
||||
|
@ -538,7 +569,7 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
*/
|
||||
protected function prepare_links( $tax ) {
|
||||
$links = array(
|
||||
'self' => array(
|
||||
'self' => array(
|
||||
'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $tax->tax_rate_id ) ),
|
||||
),
|
||||
'collection' => array(
|
||||
|
@ -592,18 +623,18 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
'title' => 'tax',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'id' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'country' => array(
|
||||
'country' => array(
|
||||
'description' => __( 'Country ISO 3166 code.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'state' => array(
|
||||
'state' => array(
|
||||
'description' => __( 'State code.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
|
@ -613,17 +644,17 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'city' => array(
|
||||
'city' => array(
|
||||
'description' => __( 'City name.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'rate' => array(
|
||||
'rate' => array(
|
||||
'description' => __( 'Tax rate.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'name' => array(
|
||||
'name' => array(
|
||||
'description' => __( 'Tax rate name.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
|
@ -646,12 +677,12 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
'default' => true,
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'order' => array(
|
||||
'order' => array(
|
||||
'description' => __( 'Indicates the order that will appear in queries.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'class' => array(
|
||||
'class' => array(
|
||||
'description' => __( 'Tax class.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
'default' => 'standard',
|
||||
|
@ -674,54 +705,55 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
|||
$params['context'] = $this->get_context_param();
|
||||
$params['context']['default'] = 'view';
|
||||
|
||||
$params['page'] = array(
|
||||
'description' => __( 'Current page of the collection.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
'default' => 1,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
'minimum' => 1,
|
||||
$params['page'] = array(
|
||||
'description' => __( 'Current page of the collection.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
'default' => 1,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
'minimum' => 1,
|
||||
);
|
||||
$params['per_page'] = array(
|
||||
'description' => __( 'Maximum number of items to be returned in result set.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
'default' => 10,
|
||||
'minimum' => 1,
|
||||
'maximum' => 100,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
'description' => __( 'Maximum number of items to be returned in result set.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
'default' => 10,
|
||||
'minimum' => 1,
|
||||
'maximum' => 100,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
$params['offset'] = array(
|
||||
'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
$params['offset'] = array(
|
||||
'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
$params['order'] = array(
|
||||
'default' => 'asc',
|
||||
'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),
|
||||
'enum' => array( 'asc', 'desc' ),
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
'type' => 'string',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
$params['order'] = array(
|
||||
'default' => 'asc',
|
||||
'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),
|
||||
'enum' => array( 'asc', 'desc' ),
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
'type' => 'string',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
$params['orderby'] = array(
|
||||
'default' => 'order',
|
||||
'description' => __( 'Sort collection by object attribute.', 'woocommerce' ),
|
||||
'enum' => array(
|
||||
$params['orderby'] = array(
|
||||
'default' => 'order',
|
||||
'description' => __( 'Sort collection by object attribute.', 'woocommerce' ),
|
||||
'enum' => array(
|
||||
'id',
|
||||
'order',
|
||||
'priority',
|
||||
),
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
'type' => 'string',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
'type' => 'string',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
$params['class'] = array(
|
||||
'description' => __( 'Sort by tax class.', 'woocommerce' ),
|
||||
'enum' => array_merge( array( 'standard' ), WC_Tax::get_tax_class_slugs() ),
|
||||
'sanitize_callback' => 'sanitize_title',
|
||||
'type' => 'string',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
$params['class'] = array(
|
||||
'description' => __( 'Sort by tax class.', 'woocommerce' ),
|
||||
'enum' => array_merge( array( 'standard' ), WC_Tax::get_tax_class_slugs() ),
|
||||
'sanitize_callback' => 'sanitize_title',
|
||||
'type' => 'string',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
return $params;
|
||||
|
|
|
@ -34,31 +34,58 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller {
|
|||
* @return bool
|
||||
*/
|
||||
protected function calculate_coupons( $request, $order ) {
|
||||
if ( ! isset( $request['coupon_lines'] ) || ! is_array( $request['coupon_lines'] ) ) {
|
||||
if ( ! isset( $request['coupon_lines'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove all coupons first to ensure calculation is correct.
|
||||
foreach ( $order->get_items( 'coupon' ) as $coupon ) {
|
||||
$order->remove_coupon( $coupon->get_code() );
|
||||
}
|
||||
// Validate input and at the same time store the processed coupon codes to apply.
|
||||
|
||||
$coupon_codes = array();
|
||||
$discounts = new WC_Discounts( $order );
|
||||
|
||||
$current_order_coupons = array_values( $order->get_coupons() );
|
||||
$current_order_coupon_codes = array_map(
|
||||
function( $coupon ) {
|
||||
return $coupon->get_code();
|
||||
},
|
||||
$current_order_coupons
|
||||
);
|
||||
|
||||
foreach ( $request['coupon_lines'] as $item ) {
|
||||
if ( is_array( $item ) ) {
|
||||
if ( ! empty( $item['id'] ) ) {
|
||||
throw new WC_REST_Exception( 'woocommerce_rest_coupon_item_id_readonly', __( 'Coupon item ID is readonly.', 'woocommerce' ), 400 );
|
||||
}
|
||||
if ( ! empty( $item['id'] ) ) {
|
||||
throw new WC_REST_Exception( 'woocommerce_rest_coupon_item_id_readonly', __( 'Coupon item ID is readonly.', 'woocommerce' ), 400 );
|
||||
}
|
||||
|
||||
if ( empty( $item['code'] ) ) {
|
||||
throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon', __( 'Coupon code is required.', 'woocommerce' ), 400 );
|
||||
}
|
||||
if ( empty( $item['code'] ) ) {
|
||||
throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon', __( 'Coupon code is required.', 'woocommerce' ), 400 );
|
||||
}
|
||||
|
||||
$results = $order->apply_coupon( wc_clean( $item['code'] ) );
|
||||
$coupon_code = wc_format_coupon_code( wc_clean( $item['code'] ) );
|
||||
$coupon = new WC_Coupon( $coupon_code );
|
||||
|
||||
if ( is_wp_error( $results ) ) {
|
||||
throw new WC_REST_Exception( 'woocommerce_rest_' . $results->get_error_code(), $results->get_error_message(), 400 );
|
||||
// Skip check if the coupon is already applied to the order, as this could wrongly throw an error for single-use coupons.
|
||||
if ( ! in_array( $coupon_code, $current_order_coupon_codes, true ) ) {
|
||||
$check_result = $discounts->is_coupon_valid( $coupon );
|
||||
if ( is_wp_error( $check_result ) ) {
|
||||
throw new WC_REST_Exception( 'woocommerce_rest_' . $check_result->get_error_code(), $check_result->get_error_message(), 400 );
|
||||
}
|
||||
}
|
||||
|
||||
$coupon_codes[] = $coupon_code;
|
||||
}
|
||||
|
||||
// Remove all coupons first to ensure calculation is correct.
|
||||
foreach ( $order->get_items( 'coupon' ) as $existing_coupon ) {
|
||||
$order->remove_coupon( $existing_coupon->get_code() );
|
||||
}
|
||||
|
||||
// Apply the coupons.
|
||||
foreach ( $coupon_codes as $new_coupon ) {
|
||||
$results = $order->apply_coupon( $new_coupon );
|
||||
|
||||
if ( is_wp_error( $results ) ) {
|
||||
throw new WC_REST_Exception( 'woocommerce_rest_' . $results->get_error_code(), $results->get_error_message(), 400 );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -74,7 +74,7 @@ class WC_REST_Taxes_Controller extends WC_REST_Taxes_V2_Controller {
|
|||
$schema = parent::get_item_schema();
|
||||
|
||||
$schema['properties']['postcodes'] = array(
|
||||
'description' => __( 'List of postcodes / ZIPs.', 'woocommerce' ),
|
||||
'description' => __( 'List of postcodes / ZIPs. Introduced in WooCommerce 5.3.', 'woocommerce' ),
|
||||
'type' => 'array',
|
||||
'items' => array(
|
||||
'type' => 'string',
|
||||
|
@ -83,7 +83,7 @@ class WC_REST_Taxes_Controller extends WC_REST_Taxes_V2_Controller {
|
|||
);
|
||||
|
||||
$schema['properties']['cities'] = array(
|
||||
'description' => __( 'List of city names.', 'woocommerce' ),
|
||||
'description' => __( 'List of city names. Introduced in WooCommerce 5.3.', 'woocommerce' ),
|
||||
'type' => 'array',
|
||||
'items' => array(
|
||||
'type' => 'string',
|
||||
|
@ -91,6 +91,51 @@ class WC_REST_Taxes_Controller extends WC_REST_Taxes_V2_Controller {
|
|||
'context' => array( 'view', 'edit' ),
|
||||
);
|
||||
|
||||
$schema['properties']['postcode']['description'] =
|
||||
__( "Postcode/ZIP, it doesn't support multiple values. Deprecated as of WooCommerce 5.3, 'postcodes' should be used instead.", 'woocommerce' );
|
||||
|
||||
$schema['properties']['city']['description'] =
|
||||
__( "City name, it doesn't support multiple values. Deprecated as of WooCommerce 5.3, 'cities' should be used instead.", 'woocommerce' );
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single tax.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response The response, or an error.
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
$this->adjust_cities_and_postcodes( $request );
|
||||
|
||||
return parent::create_item( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a single tax.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response The response, or an error.
|
||||
*/
|
||||
public function update_item( $request ) {
|
||||
$this->adjust_cities_and_postcodes( $request );
|
||||
|
||||
return parent::update_item( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert array "cities" and "postcodes" parameters
|
||||
* into semicolon-separated strings "city" and "postcode".
|
||||
*
|
||||
* @param WP_REST_Request $request The request to adjust.
|
||||
*/
|
||||
private function adjust_cities_and_postcodes( &$request ) {
|
||||
if ( isset( $request['cities'] ) ) {
|
||||
$request['city'] = join( ';', $request['cities'] );
|
||||
}
|
||||
if ( isset( $request['postcodes'] ) ) {
|
||||
$request['postcode'] = join( ';', $request['postcodes'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"psr/container": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"league/container": "3.3.3"
|
||||
"league/container": "3.3.5"
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "df548645b5c00d585705cd10c6ffd3f7",
|
||||
"content-hash": "9ae561875707d59bc392f6329d4f565a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "psr/container",
|
||||
|
@ -59,21 +59,21 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "league/container",
|
||||
"version": "3.3.3",
|
||||
"version": "3.3.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/container.git",
|
||||
"reference": "7dc67bdf89efc338e674863c0ea70a63efe4de05"
|
||||
"reference": "048ab87810f508dbedbcb7ae941b606eb8ee353b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/container/zipball/7dc67bdf89efc338e674863c0ea70a63efe4de05",
|
||||
"reference": "7dc67bdf89efc338e674863c0ea70a63efe4de05",
|
||||
"url": "https://api.github.com/repos/thephpleague/container/zipball/048ab87810f508dbedbcb7ae941b606eb8ee353b",
|
||||
"reference": "048ab87810f508dbedbcb7ae941b606eb8ee353b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.0 || ^8.0",
|
||||
"psr/container": "^1.0"
|
||||
"psr/container": "^1.0.0 || ^2.0.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/container-implementation": "^1.0"
|
||||
|
@ -83,11 +83,14 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.0",
|
||||
"squizlabs/php_codesniffer": "^3.3"
|
||||
"roave/security-advisories": "dev-master",
|
||||
"scrutinizer/ocular": "^1.8",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev",
|
||||
"dev-3.x": "3.x-dev",
|
||||
"dev-2.x": "2.x-dev",
|
||||
"dev-1.x": "1.x-dev"
|
||||
|
@ -127,7 +130,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-09-28T13:38:44+00:00"
|
||||
"time": "2021-03-16T09:42:56+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
14
readme.txt
14
readme.txt
|
@ -1,5 +1,5 @@
|
|||
=== WooCommerce ===
|
||||
Contributors: automattic, mikejolley, jameskoster, claudiosanches, rodrigosprimo, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski, wpmuguru, royho
|
||||
Contributors: automattic, mikejolley, jameskoster, claudiosanches, rodrigosprimo, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski, wpmuguru, royho, barryhughes-1
|
||||
Tags: e-commerce, store, sales, sell, woo, shop, cart, checkout, downloadable, downloads, payments, paypal, storefront, stripe, woo commerce
|
||||
Requires at least: 5.5
|
||||
Tested up to: 5.7
|
||||
|
@ -160,6 +160,16 @@ WooCommerce comes with some sample data you can use to see how products look; im
|
|||
|
||||
== Changelog ==
|
||||
|
||||
= 5.2.0 RC 2021-03-30 =
|
||||
|
||||
* Update - WooCommerce Admin package 2.1.4. #29520
|
||||
* Fix - Don't remove existing coupons from order when an invalid REST API request for updating coupons is submitted. #29474
|
||||
* Fix - Wrong logic for including or excluding the payments step in the list of completed tasks in the onboarding wizard. #29518
|
||||
|
||||
**WooCommerce Admin - 2.1.4**
|
||||
|
||||
* Fix - Adding New Zealand and Ireland to selective bundle option, previously missed. #6649
|
||||
|
||||
= 5.2.0 beta 2021-03-23 =
|
||||
|
||||
**WooCommerce**
|
||||
|
@ -202,6 +212,8 @@ WooCommerce comes with some sample data you can use to see how products look; im
|
|||
* Fix - add validation of the posted country codes on checkout. #28849
|
||||
* Fix - Correctly display pagination arrows on RTL languages. #28523
|
||||
* Fix - Invalid refund amount error on $0 refund when number of decimals is equal to 0. #27277
|
||||
* Fix - Revert a replacement of wp_redirect to wp_safe_redirect in WC_Checkout::process_order_payment that caused issues in the default PayPal interface. #29459
|
||||
* Fix - "Sale" badge misaligned on products when displaying 1 item per row. #29425
|
||||
* Tweak - Added the Mercado Pago logo into the assets/images folder in order to use it in the payments setup task. #29365
|
||||
* Tweak - Update the contributor guidelines. #29150
|
||||
* Tweak - Introduced phone number input validation. #27242
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*
|
||||
* @see https://docs.woocommerce.com/document/template-structure/
|
||||
* @package WooCommerce\Templates
|
||||
* @version 3.7.0
|
||||
* @version 5.2.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
@ -53,10 +53,10 @@ do_action( 'woocommerce_before_mini_cart' ); ?>
|
|||
);
|
||||
?>
|
||||
<?php if ( empty( $product_permalink ) ) : ?>
|
||||
<?php echo $thumbnail . $product_name; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php echo $thumbnail . wp_kses_post( $product_name ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php else : ?>
|
||||
<a href="<?php echo esc_url( $product_permalink ); ?>">
|
||||
<?php echo $thumbnail . $product_name; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php echo $thumbnail . wp_kses_post( $product_name ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php echo wc_get_formatted_cart_item_data( $cart_item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*
|
||||
* @see https://docs.woocommerce.com/document/template-structure/
|
||||
* @package WooCommerce\Templates
|
||||
* @version 3.4.0
|
||||
* @version 5.2.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
@ -40,7 +40,7 @@ $totals = $order->get_order_item_totals(); // phpcs:ignore WordPress.WP.GlobalVa
|
|||
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_order_item_class', 'order_item', $item, $order ) ); ?>">
|
||||
<td class="product-name">
|
||||
<?php
|
||||
echo apply_filters( 'woocommerce_order_item_name', esc_html( $item->get_name() ), $item, false ); // @codingStandardsIgnoreLine
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false ) );
|
||||
|
||||
do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, false );
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*
|
||||
* @see https://docs.woocommerce.com/document/template-structure/
|
||||
* @package WooCommerce\Templates
|
||||
* @version 3.8.0
|
||||
* @version 5.2.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
@ -35,7 +35,7 @@ defined( 'ABSPATH' ) || exit;
|
|||
?>
|
||||
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key ) ); ?>">
|
||||
<td class="product-name">
|
||||
<?php echo apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ' '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) ) . ' '; ?>
|
||||
<?php echo apply_filters( 'woocommerce_checkout_cart_item_quantity', ' <strong class="product-quantity">' . sprintf( '× %s', $cart_item['quantity'] ) . '</strong>', $cart_item, $cart_item_key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php echo wc_get_formatted_cart_item_data( $cart_item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</td>
|
||||
|
|
|
@ -21,14 +21,27 @@ defined( 'ABSPATH' ) || exit;
|
|||
<li>
|
||||
<?php do_action( 'woocommerce_widget_product_review_item_start', $args ); ?>
|
||||
|
||||
<?php
|
||||
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
?>
|
||||
|
||||
<a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>">
|
||||
<?php echo $product->get_image(); ?>
|
||||
<span class="product-title"><?php echo $product->get_name(); ?></span>
|
||||
<span class="product-title"><?php echo wp_kses_post( $product->get_name() ); ?></span>
|
||||
</a>
|
||||
|
||||
<?php echo wc_get_rating_html( intval( get_comment_meta( $comment->comment_ID, 'rating', true ) ) ); ?>
|
||||
|
||||
<span class="reviewer"><?php echo sprintf( esc_html__( 'by %s', 'woocommerce' ), get_comment_author( $comment->comment_ID ) ); ?></span>
|
||||
<span class="reviewer">
|
||||
<?php
|
||||
/* translators: %s: Comment author. */
|
||||
echo sprintf( esc_html__( 'by %s', 'woocommerce' ), get_comment_author( $comment->comment_ID ) );
|
||||
?>
|
||||
</span>
|
||||
|
||||
<?php
|
||||
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
?>
|
||||
|
||||
<?php do_action( 'woocommerce_widget_product_review_item_end', $args ); ?>
|
||||
</li>
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
*
|
||||
* @see https://docs.woocommerce.com/document/template-structure/
|
||||
* @package WooCommerce\Templates\Emails\Plain
|
||||
* @version 3.7.0
|
||||
* @version 5.2.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
foreach ( $items as $item_id => $item ) :
|
||||
|
@ -30,15 +30,18 @@ foreach ( $items as $item_id => $item ) :
|
|||
$purchase_note = $product->get_purchase_note();
|
||||
}
|
||||
|
||||
echo apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false );
|
||||
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false ) );
|
||||
if ( $show_sku && $sku ) {
|
||||
echo ' (#' . $sku . ')';
|
||||
}
|
||||
echo ' X ' . apply_filters( 'woocommerce_email_order_item_quantity', $item->get_quantity(), $item );
|
||||
echo ' = ' . $order->get_formatted_line_subtotal( $item ) . "\n";
|
||||
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
// allow other plugins to add additional product information here
|
||||
// allow other plugins to add additional product information here.
|
||||
do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, $plain_text );
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo strip_tags(
|
||||
wc_display_item_meta(
|
||||
$item,
|
||||
|
@ -52,10 +55,10 @@ foreach ( $items as $item_id => $item ) :
|
|||
)
|
||||
);
|
||||
|
||||
// allow other plugins to add additional product information here
|
||||
// allow other plugins to add additional product information here.
|
||||
do_action( 'woocommerce_order_item_meta_end', $item_id, $item, $order, $plain_text );
|
||||
}
|
||||
// Note
|
||||
// Note.
|
||||
if ( $show_purchase_note && $purchase_note ) {
|
||||
echo "\n" . do_shortcode( wp_kses_post( $purchase_note ) );
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*
|
||||
* @see https://docs.woocommerce.com/document/template-structure/
|
||||
* @package WooCommerce\Templates
|
||||
* @version 3.7.0
|
||||
* @version 5.2.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
|
@ -30,7 +30,7 @@ if ( ! apply_filters( 'woocommerce_order_item_visible', true, $item ) ) {
|
|||
$is_visible = $product && $product->is_visible();
|
||||
$product_permalink = apply_filters( 'woocommerce_order_item_permalink', $is_visible ? $product->get_permalink( $item ) : '', $item, $order );
|
||||
|
||||
echo apply_filters( 'woocommerce_order_item_name', $product_permalink ? sprintf( '<a href="%s">%s</a>', $product_permalink, $item->get_name() ) : $item->get_name(), $item, $is_visible ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $product_permalink ? sprintf( '<a href="%s">%s</a>', $product_permalink, $item->get_name() ) : $item->get_name(), $item, $is_visible ) );
|
||||
|
||||
$qty = $item->get_quantity();
|
||||
$refunded_qty = $order->get_qty_refunded_for_item( $item_id );
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# Unreleased
|
||||
|
||||
|
||||
# 0.1.2
|
||||
|
||||
## Added
|
||||
|
||||
- Support for the external product type.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@woocommerce/api",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"author": "Automattic",
|
||||
"description": "A simple interface for interacting with a WooCommerce installation.",
|
||||
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/api/README.md",
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
# Unreleased
|
||||
|
||||
# 0.1.3
|
||||
|
||||
## Fixed
|
||||
|
||||
- removed use of ES6 `import`
|
||||
|
||||
# 0.1.2
|
||||
|
||||
## Added
|
||||
|
||||
- api package test for variable products and product variations
|
||||
- api package test for grouped products
|
||||
- api package test for external products
|
||||
- api package test for coupons
|
||||
|
||||
# 0.1.1
|
||||
|
||||
## Added
|
||||
|
||||
- Registered Shopper Checkout tests
|
||||
- Merchant Order Status Filter tests
|
||||
- Merchant Order Refund tests
|
||||
- Merchant Apply Coupon tests
|
||||
- Added new config variable for Simple Product price to `tests/e2e/env/config/default.json`. Defaults to 9.99
|
||||
- Merchant Product Edit tests
|
||||
- Merchant Product Search tests
|
||||
- Shopper Single Product tests
|
||||
- Shopper My Account Pay Order
|
||||
- Shopper Checkout Apply Coupon
|
||||
- Shopper Shop Browse Search Sort
|
||||
- Merchant Orders Customer Checkout Page
|
||||
- Shopper Cart Apply Coupon
|
||||
|
@ -28,6 +26,18 @@
|
|||
- Merchant Settings Shipping Zones
|
||||
- Shopper Variable product info updates on different variations
|
||||
- Merchant order emails flow
|
||||
- Merchant analytics page load tests
|
||||
- Shopper Checkout Create Account
|
||||
|
||||
# 0.1.1
|
||||
|
||||
## Added
|
||||
|
||||
- Merchant Order Status Filter tests
|
||||
- Merchant Order Refund tests
|
||||
- Merchant Apply Coupon tests
|
||||
- Added new config variable for Simple Product price to `tests/e2e/env/config/default.json`. Defaults to 9.99
|
||||
- Shopper Checkout Apply Coupon
|
||||
|
||||
## Fixed
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ The functions to access the core tests are:
|
|||
- `runTaxSettingsTest` - Merchant can update tax settings
|
||||
- `runUpdateGeneralSettingsTest` - Merchant can update general settings
|
||||
- `runMerchantOrderEmailsTest` - Merchant can receive order emails and resend emails by Order Actions
|
||||
- `runAnalyticsPageLoadsTest` - Merchant can load and see all pages in Analytics
|
||||
|
||||
### Shopper
|
||||
|
||||
|
@ -75,6 +76,7 @@ The functions to access the core tests are:
|
|||
- `runProductBrowseSearchSortTest` - Shopper can browse, search & sort products
|
||||
- `runSingleProductPageTest` - Shopper can view single product page in many variations (simple, variable, grouped)
|
||||
- `runVariableProductUpdateTest` - Shopper can view and update variations on a variable product
|
||||
- `runCheckoutCreateAccountTest` - Shopper can create an account during checkout
|
||||
|
||||
### REST API
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@woocommerce/e2e-core-tests",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.3",
|
||||
"description": "End-To-End (E2E) tests for WooCommerce",
|
||||
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/core-tests/README.md",
|
||||
"repository": {
|
||||
|
@ -14,8 +14,8 @@
|
|||
"config": "3.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@woocommerce/api": "^0.1.1",
|
||||
"@woocommerce/e2e-utils": "^0.1.2"
|
||||
"@woocommerce/api": "^0.1.2",
|
||||
"@woocommerce/e2e-utils": "^0.1.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
|
@ -18,6 +18,7 @@ const runMyAccountPageTest = require( './shopper/front-end-my-account.test' );
|
|||
const runMyAccountPayOrderTest = require( './shopper/front-end-my-account-pay-order.test' );
|
||||
const runSingleProductPageTest = require( './shopper/front-end-single-product.test' );
|
||||
const runVariableProductUpdateTest = require( './shopper/front-end-variable-product-updates.test' );
|
||||
const runCheckoutCreateAccountTest = require( './shopper/front-end-checkout-create-account.test' );
|
||||
|
||||
// Merchant tests
|
||||
const runAddNewShippingZoneTest = require ( './merchant/wp-admin-settings-shipping-zones.test' );
|
||||
|
@ -36,6 +37,7 @@ const runProductSearchTest = require( './merchant/wp-admin-product-search.test'
|
|||
const runMerchantOrdersCustomerPaymentPage = require( './merchant/wp-admin-order-customer-payment-page.test' );
|
||||
const runMerchantOrderEmailsTest = require( './merchant/wp-admin-order-emails.test' );
|
||||
const runOrderSearchingTest = require( './merchant/wp-admin-order-searching.test' );
|
||||
const runAnalyticsPageLoadsTest = require( './merchant/wp-admin-analytics-page-loads.test' );
|
||||
|
||||
// REST API tests
|
||||
const runExternalProductAPITest = require( './api/external-product.test' );
|
||||
|
@ -60,6 +62,7 @@ const runShopperTests = () => {
|
|||
runMyAccountPayOrderTest();
|
||||
runSingleProductPageTest();
|
||||
runVariableProductUpdateTest();
|
||||
runCheckoutCreateAccountTest();
|
||||
};
|
||||
|
||||
const runMerchantTests = () => {
|
||||
|
@ -79,6 +82,7 @@ const runMerchantTests = () => {
|
|||
runProductEditDetailsTest();
|
||||
runProductSearchTest();
|
||||
runMerchantOrdersCustomerPaymentPage();
|
||||
runAnalyticsPageLoadsTest();
|
||||
}
|
||||
|
||||
const runApiTests = () => {
|
||||
|
@ -127,4 +131,6 @@ module.exports = {
|
|||
runAddNewShippingZoneTest,
|
||||
runProductBrowseSearchSortTest,
|
||||
runApiTests,
|
||||
runAnalyticsPageLoadsTest,
|
||||
runCheckoutCreateAccountTest,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/* eslint-disable jest/no-export, jest/no-disabled-tests */
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
const {
|
||||
merchant,
|
||||
} = require( '@woocommerce/e2e-utils' );
|
||||
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
const {
|
||||
it,
|
||||
describe,
|
||||
beforeAll,
|
||||
} = require( '@jest/globals' );
|
||||
|
||||
/**
|
||||
* Quick check for page title and no data message.
|
||||
*
|
||||
* @param pageTitle Page title in H1.
|
||||
* @param element Defaults to '.d3-chart__empty-message'
|
||||
* @param elementText Defaults to 'No data for the selected date range'
|
||||
*/
|
||||
const checkHeadingAndElement = async (
|
||||
pageTitle, element = '.d3-chart__empty-message', elementText = 'No data for the selected date range') => {
|
||||
await expect(page).toMatchElement('h1', {text: pageTitle});
|
||||
await expect(page).toMatchElement(element, elementText);
|
||||
};
|
||||
|
||||
const runAnalyticsPageLoadsTest = () => {
|
||||
describe('Analytics > Opening Top Level Pages', () => {
|
||||
beforeAll(async () => {
|
||||
await merchant.login();
|
||||
});
|
||||
|
||||
it('can see Overview page properly', async () => {
|
||||
// Go to "overview" page and verify it
|
||||
await merchant.openAnalyticsPage('overview');
|
||||
await checkHeadingAndElement('Overview');
|
||||
});
|
||||
|
||||
it('can see Products page properly', async () => {
|
||||
// Go to "products" page and verify it
|
||||
await merchant.openAnalyticsPage('products');
|
||||
await checkHeadingAndElement('Products');
|
||||
});
|
||||
|
||||
it('can see Revenue page properly', async () => {
|
||||
// Go to "revenue" page and verify it
|
||||
await merchant.openAnalyticsPage('revenue');
|
||||
await checkHeadingAndElement('Revenue');
|
||||
});
|
||||
|
||||
it('can see Orders page properly', async () => {
|
||||
// Go to "orders" page and verify it
|
||||
await merchant.openAnalyticsPage('orders');
|
||||
await checkHeadingAndElement('Orders');
|
||||
});
|
||||
|
||||
it('can see Variations page properly', async () => {
|
||||
// Go to "variations" page and verify it
|
||||
await merchant.openAnalyticsPage('variations');
|
||||
await checkHeadingAndElement('Variations');
|
||||
});
|
||||
|
||||
it('can see Categories page properly', async () => {
|
||||
// Go to "categories" page and verify it
|
||||
await merchant.openAnalyticsPage('categories');
|
||||
await checkHeadingAndElement('Categories');
|
||||
});
|
||||
|
||||
it('can see Coupons page properly', async () => {
|
||||
// Go to "coupons" page and verify it
|
||||
await merchant.openAnalyticsPage('coupons');
|
||||
await checkHeadingAndElement('Coupons');
|
||||
});
|
||||
|
||||
it('can see Taxes page properly', async () => {
|
||||
// Go to "taxes" page and verify it
|
||||
await merchant.openAnalyticsPage('taxes');
|
||||
await checkHeadingAndElement('Taxes');
|
||||
});
|
||||
|
||||
it('can see Downloads page properly', async () => {
|
||||
// Go to "downloads" page and verify it
|
||||
await merchant.openAnalyticsPage('downloads');
|
||||
await checkHeadingAndElement('Downloads');
|
||||
});
|
||||
|
||||
it('can see Stock page properly', async () => {
|
||||
// Go to "stock" page and verify it
|
||||
await merchant.openAnalyticsPage('stock');
|
||||
await checkHeadingAndElement('Stock', '.components-button > span', 'Product / Variation');
|
||||
});
|
||||
|
||||
it('can see Settings page properly', async () => {
|
||||
// Go to "settings" page and verify it
|
||||
await merchant.openAnalyticsPage('settings');
|
||||
await checkHeadingAndElement('Settings', 'h2', 'Analytics Settings');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = runAnalyticsPageLoadsTest;
|
|
@ -1,5 +1,5 @@
|
|||
/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/no-standalone-expect */
|
||||
import {createSimpleProduct} from "@woocommerce/e2e-utils";
|
||||
const { createSimpleProduct } = require( '@woocommerce/e2e-utils' );
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
const {
|
||||
merchant,
|
||||
clearAndFillInput,
|
||||
selectOptionInSelect2,
|
||||
searchForOrder,
|
||||
createSimpleProduct,
|
||||
addProductToOrder,
|
||||
|
@ -20,40 +19,36 @@ const runOrderSearchingTest = () => {
|
|||
await merchant.login();
|
||||
await createSimpleProduct('Wanted Product');
|
||||
|
||||
await Promise.all([
|
||||
// Create new order for testing
|
||||
await merchant.openNewOrder(),
|
||||
await page.waitForSelector('#order_status'),
|
||||
await page.click('#customer_user'),
|
||||
await page.click('span.select2-search > input.select2-search__field'),
|
||||
await page.type('span.select2-search > input.select2-search__field', 'Customer'),
|
||||
await page.waitFor(2000), // to avoid flakyness
|
||||
await page.keyboard.press('Enter'),
|
||||
]);
|
||||
// Create new order for testing
|
||||
await merchant.openNewOrder();
|
||||
await page.waitForSelector('#order_status');
|
||||
await page.click('#customer_user');
|
||||
await page.click('span.select2-search > input.select2-search__field');
|
||||
await page.type('span.select2-search > input.select2-search__field', 'Customer');
|
||||
await page.waitFor(2000); // to avoid flakyness
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await Promise.all([
|
||||
// Change the shipping data
|
||||
await page.waitFor(1000), // to avoid flakiness
|
||||
await page.waitForSelector('#_shipping_first_name'),
|
||||
await clearAndFillInput('#_shipping_first_name', 'Tim'),
|
||||
await clearAndFillInput('#_shipping_last_name', 'Clark'),
|
||||
await clearAndFillInput('#_shipping_address_1', 'Oxford Ave'),
|
||||
await clearAndFillInput('#_shipping_address_2', 'Linwood Ave'),
|
||||
await clearAndFillInput('#_shipping_city', 'Buffalo'),
|
||||
await clearAndFillInput('#_shipping_postcode', '14201'),
|
||||
await page.keyboard.press('Tab'),
|
||||
await page.keyboard.press('Tab'),
|
||||
await page.keyboard.press('Enter'),
|
||||
await page.select('select[name="_shipping_state"]', 'NY'),
|
||||
]);
|
||||
// Change the shipping data
|
||||
await page.waitFor(1000); // to avoid flakiness
|
||||
await page.click('.billing-same-as-shipping');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForSelector('#_shipping_first_name');
|
||||
await clearAndFillInput('#_shipping_first_name', 'Tim');
|
||||
await clearAndFillInput('#_shipping_last_name', 'Clark');
|
||||
await clearAndFillInput('#_shipping_address_1', 'Oxford Ave');
|
||||
await clearAndFillInput('#_shipping_address_2', 'Linwood Ave');
|
||||
await clearAndFillInput('#_shipping_city', 'Buffalo');
|
||||
await clearAndFillInput('#_shipping_postcode', '14201');
|
||||
|
||||
// Get the post id
|
||||
const variablePostId = await page.$('#post_ID');
|
||||
orderId = (await(await variablePostId.getProperty('value')).jsonValue());
|
||||
|
||||
// Save new order
|
||||
// Save new order and add desired product to order
|
||||
await clickUpdateOrder('Order updated.', true);
|
||||
await addProductToOrder(orderId, 'Wanted Product');
|
||||
|
||||
// Open All Orders view
|
||||
await merchant.openAllOrdersView();
|
||||
});
|
||||
|
||||
|
@ -126,7 +121,7 @@ const runOrderSearchingTest = () => {
|
|||
})
|
||||
|
||||
it('can search for order by shipping state name', async () => {
|
||||
await searchForOrder('NY', orderId, 'John Doe');
|
||||
await searchForOrder('CA', orderId, 'John Doe');
|
||||
})
|
||||
|
||||
it('can search for order by item name', async () => {
|
||||
|
|
|
@ -17,7 +17,7 @@ const {
|
|||
const config = require( 'config' );
|
||||
const simpleProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99';
|
||||
const simpleProductName = config.get( 'products.simple.name' );
|
||||
const california = 'California, United States (US)';
|
||||
const california = 'state:US:CA';
|
||||
const sanFranciscoZIP = '94107';
|
||||
const shippingZoneNameUS = 'US with Flat rate';
|
||||
const shippingZoneNameFL = 'CA with Free shipping';
|
||||
|
@ -90,10 +90,6 @@ const runAddNewShippingZoneTest = () => {
|
|||
await selectOptionInSelect2('New York');
|
||||
await expect(page).toClick('button[name="calc_shipping"]');
|
||||
|
||||
// Set shipping postcode to 10010
|
||||
await clearAndFillInput('#calc_shipping_postcode', '10010');
|
||||
await expect(page).toClick('button[name="calc_shipping"]');
|
||||
|
||||
// Verify shipping costs
|
||||
await page.waitForSelector('.order-total');
|
||||
await expect(page).toMatchElement('.shipping .amount', {text: '$10.00'});
|
||||
|
@ -102,6 +98,7 @@ const runAddNewShippingZoneTest = () => {
|
|||
|
||||
it('allows customer to benefit from a Free shipping if in CA', async () => {
|
||||
await page.reload();
|
||||
|
||||
// Set shipping state to California
|
||||
await expect(page).toClick('a.shipping-calculator-button');
|
||||
await expect(page).toClick('#select2-calc_shipping_state-container');
|
||||
|
@ -119,6 +116,7 @@ const runAddNewShippingZoneTest = () => {
|
|||
|
||||
it('allows customer to benefit from a free Local pickup if in SF', async () => {
|
||||
await page.reload();
|
||||
|
||||
// Set shipping postcode to 94107
|
||||
await expect(page).toClick('a.shipping-calculator-button');
|
||||
await clearAndFillInput('#calc_shipping_postcode', '94107');
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect */
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
const {
|
||||
shopper,
|
||||
merchant,
|
||||
createSimpleProduct,
|
||||
uiUnblocked,
|
||||
setCheckbox,
|
||||
settingsPageSaveChanges,
|
||||
} = require( '@woocommerce/e2e-utils' );
|
||||
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
const {
|
||||
it,
|
||||
describe,
|
||||
beforeAll,
|
||||
} = require( '@jest/globals' );
|
||||
|
||||
const config = require( 'config' );
|
||||
const simpleProductName = config.get( 'products.simple.name' );
|
||||
|
||||
const runCheckoutCreateAccountTest = () => {
|
||||
describe('Shopper Checkout Create Account', () => {
|
||||
beforeAll(async () => {
|
||||
await merchant.login();
|
||||
await createSimpleProduct();
|
||||
await merchant.openSettings('account');
|
||||
await setCheckbox('#woocommerce_enable_signup_and_login_from_checkout');
|
||||
await settingsPageSaveChanges();
|
||||
await merchant.logout();
|
||||
await shopper.goToShop();
|
||||
await shopper.addToCartFromShopPage(simpleProductName);
|
||||
await uiUnblocked();
|
||||
await shopper.goToCheckout();
|
||||
});
|
||||
|
||||
it('can create an account during checkout', async () => {
|
||||
// Fill all the details for a new customer
|
||||
await shopper.fillBillingDetails(config.get('addresses.customer.billing'));
|
||||
await uiUnblocked();
|
||||
|
||||
// Set checkbox for creating account during checkout
|
||||
await setCheckbox('#createaccount');
|
||||
|
||||
// Place an order
|
||||
await shopper.placeOrder();
|
||||
await expect(page).toMatchElement('h1.entry-title', {text: 'Order received'});
|
||||
});
|
||||
|
||||
it('can verify that the customer has been created', async () => {
|
||||
await merchant.login();
|
||||
await merchant.openAllUsersView();
|
||||
await expect(page).toMatchElement('td.email.column-email > a', {text: 'john.doe@example.com'});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = runCheckoutCreateAccountTest;
|
|
@ -4,9 +4,7 @@
|
|||
*/
|
||||
const {
|
||||
shopper,
|
||||
merchant,
|
||||
createSimpleProductWithCategory,
|
||||
uiUnblocked,
|
||||
} = require( '@woocommerce/e2e-utils' );
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# Unreleased
|
||||
|
||||
|
||||
# 0.2.1
|
||||
|
||||
## Added
|
||||
|
||||
- Support for screenshots on test errors
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@woocommerce/e2e-environment",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "WooCommerce End to End Testing Environment Configuration.",
|
||||
"author": "Automattic",
|
||||
"license": "GPL-3.0-or-later",
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
* Internal dependencies
|
||||
*/
|
||||
const { runCheckoutCreateAccountTest } = require( '@woocommerce/e2e-core-tests' );
|
||||
|
||||
runCheckoutCreateAccountTest();
|
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
* Internal dependencies
|
||||
*/
|
||||
const { runAnalyticsPageLoadsTest } = require( '@woocommerce/e2e-core-tests' );
|
||||
|
||||
runAnalyticsPageLoadsTest();
|
|
@ -1,5 +1,30 @@
|
|||
# Unreleased
|
||||
|
||||
# 0.1.4
|
||||
|
||||
## Fixed
|
||||
|
||||
- build issue with faker import
|
||||
|
||||
# 0.1.3
|
||||
|
||||
## Added
|
||||
|
||||
- `selectOptionInSelect2( selector, value )` util helper method that search and select in any select2 type field
|
||||
- `searchForOrder( value, orderId, customerName )` util helper method that search order with different terms
|
||||
- `addShippingZoneAndMethod( zoneName, zoneLocation, zipCode, zoneMethod )` util helper method for adding shipping zones with shipping methods
|
||||
- `createSimpleProductWithCategory` component which creates a simple product with categories, containing three parameters for title, price and category name.
|
||||
- `applyCoupon( couponName )` util helper method which applies previously created coupon to cart or checkout
|
||||
- `removeCoupon()` util helper method that removes a single coupon within cart or checkout
|
||||
- `selectOrderAction( action )` util helper method to select and initiate an order action in the Order Action postbox
|
||||
- `merchant.openEmailLog()` go to the WP Mail Log page
|
||||
- `deleteAllEmailLogs` delete all email logs in the WP Mail Log plugin
|
||||
- `clickUpdateOrder( noticeText, waitForSave )` util helper that clicks the `Update` button on an order
|
||||
|
||||
## Changed
|
||||
|
||||
- Added coupon type parameter to `createCoupon( couponAmount, couponType )`. Default coupon type is fixed cart.
|
||||
|
||||
# 0.1.2
|
||||
|
||||
## Fixed
|
||||
|
@ -16,16 +41,6 @@
|
|||
- `addProductToOrder( orderId, productName )` component which adds the provided productName to the passed in orderId
|
||||
- `createCoupon( couponAmount )` component which accepts a coupon amount string (it defaults to 5) and creates a basic coupon. Returns the generated coupon code.
|
||||
- `evalAndClick( selector )` use Puppeteer page.$eval to select and click and element.
|
||||
- `selectOptionInSelect2( selector, value )` util helper method that search and select in any select2 type field
|
||||
- `searchForOrder( value, orderId, customerName )` util helper method that search order with different terms
|
||||
- `addShippingZoneAndMethod( zoneName, zoneLocation, zipCode, zoneMethod )` util helper method for adding shipping zones with shipping methods
|
||||
- `createSimpleProductWithCategory` component which creates a simple product with categories, containing three parameters for title, price and category name.
|
||||
- `applyCoupon( couponName )` util helper method which applies previously created coupon to cart or checkout
|
||||
- `removeCoupon()` util helper method that removes a single coupon within cart or checkout
|
||||
- `selectOrderAction( action )` util helper method to select and initiate an order action in the Order Action postbox
|
||||
- `merchant.openEmailLog()` go to the WP Mail Log page
|
||||
- `deleteAllEmailLogs` delete all email logs in the WP Mail Log plugin
|
||||
- `clickUpdateOrder( noticeText, waitForSave )` util helper that clicks the `Update` button on an order
|
||||
|
||||
## Changes
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ describe( 'Cart page', () => {
|
|||
| `runSetupWizard` | | Open the onboarding profiler |
|
||||
| `updateOrderStatus` | `orderId, status` | Update the status of an order |
|
||||
| `openEmailLog` | | Open the WP Mail Log page |
|
||||
| `openAnalyticsPage` | | Open any Analytics page |
|
||||
| `openAllUsersView` | | Open the All Users page |
|
||||
|
||||
### Shopper `shopper`
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@woocommerce/e2e-utils",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.4",
|
||||
"description": "End-To-End (E2E) test utils for WooCommerce",
|
||||
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e-utils/README.md",
|
||||
"repository": {
|
||||
|
@ -18,7 +18,7 @@
|
|||
"fishery": "^1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@woocommerce/api": "^0.1.0"
|
||||
"@woocommerce/api": "^0.1.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
|
@ -6,7 +6,14 @@
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { merchant } from './flows';
|
||||
import { clickTab, uiUnblocked, verifyCheckboxIsUnset, evalAndClick, selectOptionInSelect2, setCheckbox } from './page-utils';
|
||||
import {
|
||||
clickTab,
|
||||
uiUnblocked,
|
||||
verifyCheckboxIsUnset,
|
||||
selectOptionInSelect2,
|
||||
setCheckbox,
|
||||
unsetCheckbox
|
||||
} from './page-utils';
|
||||
import factories from './factories';
|
||||
|
||||
const config = require( 'config' );
|
||||
|
@ -143,7 +150,8 @@ const completeOnboardingWizard = async () => {
|
|||
await waitAndClickPrimary( false );
|
||||
|
||||
// Skip installing extensions
|
||||
await evalAndClick( '.components-checkbox-control__input' );
|
||||
await unsetCheckbox( '.components-checkbox-control__input' );
|
||||
await verifyCheckboxIsUnset( '.components-checkbox-control__input' );
|
||||
await waitAndClickPrimary();
|
||||
|
||||
// Theme section
|
||||
|
@ -464,11 +472,11 @@ const createCoupon = async ( couponAmount = '5', discountType = 'Fixed cart disc
|
|||
* Adds a shipping zone along with a shipping method.
|
||||
*
|
||||
* @param zoneName Shipping zone name.
|
||||
* @param zoneLocation Shiping zone location. Defaults to United States (US).
|
||||
* @param zoneLocation Shiping zone location. Defaults to country:US. For states use: state:US:CA
|
||||
* @param zipCode Shipping zone zip code. Defaults to empty one space.
|
||||
* @param zoneMethod Shipping method type. Defaults to flat_rate (use also: free_shipping or local_pickup)
|
||||
*/
|
||||
const addShippingZoneAndMethod = async ( zoneName, zoneLocation = 'United States (US)', zipCode = ' ', zoneMethod = 'flat_rate' ) => {
|
||||
const addShippingZoneAndMethod = async ( zoneName, zoneLocation = 'country:US', zipCode = ' ', zoneMethod = 'flat_rate' ) => {
|
||||
await merchant.openNewShipping();
|
||||
|
||||
// Fill shipping zone name
|
||||
|
@ -476,12 +484,7 @@ const addShippingZoneAndMethod = async ( zoneName, zoneLocation = 'United States
|
|||
await expect(page).toFill('input#zone_name', zoneName);
|
||||
|
||||
// Select shipping zone location
|
||||
// (.toSelect is not best option here because a lot of   are present in country/state names)
|
||||
await expect(page).toFill('#zone_locations', zoneLocation);
|
||||
await uiUnblocked();
|
||||
await page.keyboard.press('Tab');
|
||||
await uiUnblocked();
|
||||
await page.keyboard.press('Enter');
|
||||
await expect(page).toSelect('select[name="zone_locations"]', zoneLocation);
|
||||
|
||||
// Fill shipping zone postcode if needed otherwise just put empty space
|
||||
await page.waitForSelector('a.wc-shipping-zone-postcodes-toggle');
|
||||
|
@ -491,14 +494,12 @@ const addShippingZoneAndMethod = async ( zoneName, zoneLocation = 'United States
|
|||
await expect(page).toClick('button#submit');
|
||||
|
||||
// Add shipping zone method
|
||||
await uiUnblocked();
|
||||
await page.waitFor(1000);
|
||||
await expect(page).toClick('button.wc-shipping-zone-add-method', {text:'Add shipping method'});
|
||||
await page.waitForSelector('.wc-shipping-zone-method-selector');
|
||||
await expect(page).toSelect('select[name="add_method_id"]', zoneMethod);
|
||||
await uiUnblocked();
|
||||
await expect(page).toClick('button#btn-ok');
|
||||
await page.waitForSelector('#zone_locations');
|
||||
await uiUnblocked();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { SimpleProduct } from '@woocommerce/api';
|
||||
import faker from 'faker/locale/en';
|
||||
const faker = require( 'faker/locale/en' );
|
||||
import { Factory } from 'fishery';
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,8 @@ export const WP_ADMIN_NEW_PRODUCT = baseUrl + 'wp-admin/post-new.php?post_type=p
|
|||
export const WP_ADMIN_WC_SETTINGS = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=';
|
||||
export const WP_ADMIN_PERMALINK_SETTINGS = baseUrl + 'wp-admin/options-permalink.php';
|
||||
export const WP_ADMIN_NEW_SHIPPING_ZONE = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=shipping&zone_id=new';
|
||||
export const WP_ADMIN_ANALYTICS_PAGES = baseUrl + 'wp-admin/admin.php?page=wc-admin&path=%2Fanalytics%2F';
|
||||
export const WP_ADMIN_ALL_USERS_VIEW = baseUrl + 'wp-admin/users.php';
|
||||
|
||||
export const SHOP_PAGE = baseUrl + 'shop';
|
||||
export const SHOP_PRODUCT_PAGE = baseUrl + '?p=';
|
||||
|
|
|
@ -19,7 +19,9 @@ const {
|
|||
WP_ADMIN_PLUGINS,
|
||||
WP_ADMIN_SETUP_WIZARD,
|
||||
WP_ADMIN_WC_SETTINGS,
|
||||
WP_ADMIN_NEW_SHIPPING_ZONE
|
||||
WP_ADMIN_NEW_SHIPPING_ZONE,
|
||||
WP_ADMIN_ANALYTICS_PAGES,
|
||||
WP_ADMIN_ALL_USERS_VIEW,
|
||||
} = require( './constants' );
|
||||
|
||||
const baseUrl = config.get( 'url' );
|
||||
|
@ -182,6 +184,18 @@ const merchant = {
|
|||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
openAnalyticsPage: async ( pageName ) => {
|
||||
await page.goto( WP_ADMIN_ANALYTICS_PAGES + pageName, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
openAllUsersView: async () => {
|
||||
await page.goto( WP_ADMIN_ALL_USERS_VIEW, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = merchant;
|
||||
|
|
|
@ -4,11 +4,18 @@
|
|||
*
|
||||
* Provides REST API specific methods and setup/teardown.
|
||||
*
|
||||
* @package WooCommerce\Tests
|
||||
* @since 3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for REST related unit test classes.
|
||||
*/
|
||||
class WC_REST_Unit_Test_Case extends WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* @var WP_REST_Server
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
|
@ -36,4 +43,64 @@ class WC_REST_Unit_Test_Case extends WC_Unit_Test_Case {
|
|||
unset( $this->server );
|
||||
$wp_rest_server = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a REST request.
|
||||
*
|
||||
* @param string $url The endpopint url, if it doesn't start with '/' it'll be prepended with '/wc/v3/'.
|
||||
* @param string $verb HTTP verb for the request, default is GET.
|
||||
* @param array|null $body_params Body parameters for the request, null if none are required.
|
||||
* @param array|null $query_params Query string parameters for the request, null if none are required.
|
||||
* @return array Result from the request.
|
||||
*/
|
||||
public function do_rest_request( $url, $verb = 'GET', $body_params = null, $query_params = null ) {
|
||||
if ( '/' !== $url[0] ) {
|
||||
$url = '/wc/v3/' . $url;
|
||||
}
|
||||
|
||||
$request = new WP_REST_Request( $verb, $url );
|
||||
if ( ! is_null( $query_params ) ) {
|
||||
$request->set_query_params( $query_params );
|
||||
}
|
||||
if ( ! is_null( $body_params ) ) {
|
||||
$request->set_body_params( $body_params );
|
||||
}
|
||||
|
||||
return $this->server->dispatch( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a GET REST request.
|
||||
*
|
||||
* @param string $url The endpopint url, if it doesn't start with '/' it'll be prepended with '/wc/v3/'.
|
||||
* @param array|null $query_params Query string parameters for the request, null if none are required.
|
||||
* @return WP_REST_Response The response for the request.
|
||||
*/
|
||||
public function do_rest_get_request( $url, $query_params = null ) {
|
||||
return $this->do_rest_request( $url, 'GET', null, $query_params );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a POST REST request.
|
||||
*
|
||||
* @param string $url The endpopint url, if it doesn't start with '/' it'll be prepended with '/wc/v3/'.
|
||||
* @param array|null $body_params Body parameters for the request, null if none are required.
|
||||
* @param array|null $query_params Query string parameters for the request, null if none are required.
|
||||
* @return array Result from the request.
|
||||
*/
|
||||
public function do_rest_post_request( $url, $body_params = null, $query_params = null ) {
|
||||
return $this->do_rest_request( $url, 'POST', $body_params, $query_params );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a PUT REST request.
|
||||
*
|
||||
* @param string $url The endpopint url, if it doesn't start with '/' it'll be prepended with '/wc/v3/'.
|
||||
* @param array|null $body_params Body parameters for the request, null if none are required.
|
||||
* @param array|null $query_params Query string parameters for the request, null if none are required.
|
||||
* @return array Result from the request.
|
||||
*/
|
||||
public function do_rest_put_request( $url, $body_params = null, $query_params = null ) {
|
||||
return $this->do_rest_request( $url, 'PUT', $body_params, $query_params );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* @since 3.5.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\RestApi\UnitTests\Helpers\CouponHelper;
|
||||
use Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper;
|
||||
|
||||
/**
|
||||
* Class WC_Tests_API_Orders
|
||||
*/
|
||||
|
@ -51,7 +54,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
|
||||
// Create 10 orders.
|
||||
for ( $i = 0; $i < 10; $i++ ) {
|
||||
$this->orders[] = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order( $this->user );
|
||||
$this->orders[] = OrderHelper::create_order( $this->user );
|
||||
}
|
||||
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders' ) );
|
||||
|
@ -67,8 +70,8 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
public function test_get_items_ordered_by_modified() {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$order1 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order( $this->user );
|
||||
$order2 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order( $this->user );
|
||||
$order1 = OrderHelper::create_order( $this->user );
|
||||
$order2 = OrderHelper::create_order( $this->user );
|
||||
|
||||
$order1->set_status( 'completed' );
|
||||
$order1->save();
|
||||
|
@ -80,7 +83,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
$request->set_query_params(
|
||||
array(
|
||||
'orderby' => 'modified',
|
||||
'order' => 'asc',
|
||||
'order' => 'asc',
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
@ -90,7 +93,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
$request->set_query_params(
|
||||
array(
|
||||
'orderby' => 'modified',
|
||||
'order' => 'desc',
|
||||
'order' => 'desc',
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
@ -105,7 +108,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_get_items_without_permission() {
|
||||
wp_set_current_user( 0 );
|
||||
$this->orders[] = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$this->orders[] = OrderHelper::create_order();
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders' ) );
|
||||
$this->assertEquals( 401, $response->get_status() );
|
||||
}
|
||||
|
@ -116,7 +119,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_get_item() {
|
||||
wp_set_current_user( $this->user );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$order->add_meta_data( 'key', 'value' );
|
||||
$order->add_meta_data( 'key2', 'value2' );
|
||||
$order->save();
|
||||
|
@ -140,7 +143,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_get_item_without_permission() {
|
||||
wp_set_current_user( 0 );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$this->orders[] = $order;
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
|
||||
$this->assertEquals( 401, $response->get_status() );
|
||||
|
@ -152,18 +155,18 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
public function test_get_item_with_line_items_meta_data() {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$attribute_name = 'Site Level Type';
|
||||
$site_level_attribute_id = wc_create_attribute( array( 'name' => $attribute_name ) );
|
||||
$attribute_name = 'Site Level Type';
|
||||
$site_level_attribute_id = wc_create_attribute( array( 'name' => $attribute_name ) );
|
||||
$site_level_attribute_slug = wc_attribute_taxonomy_name_by_id( $site_level_attribute_id );
|
||||
|
||||
// Register the attribute so that wp_insert_term will be successful.
|
||||
register_taxonomy( $site_level_attribute_slug, array( 'product' ), array() );
|
||||
|
||||
$term_name = 'Site Level Value - Wood';
|
||||
$term_name = 'Site Level Value - Wood';
|
||||
$site_level_term_insertion_result = wp_insert_term( $term_name, $site_level_attribute_slug );
|
||||
$site_level_term = get_term( $site_level_term_insertion_result['term_id'] );
|
||||
$site_level_term = get_term( $site_level_term_insertion_result['term_id'] );
|
||||
|
||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product();
|
||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product();
|
||||
$variation = wc_get_product( $product->get_children()[0] );
|
||||
|
||||
$line_item = new WC_Order_Item_Product();
|
||||
|
@ -172,12 +175,12 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
array( 'variation' => array( "attribute_{$site_level_attribute_slug}" => $site_level_term->slug ) )
|
||||
);
|
||||
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$order->add_item( $line_item );
|
||||
$order->save();
|
||||
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
|
||||
$data = $response->get_data();
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertEquals( $order->get_id(), $data['id'] );
|
||||
|
@ -205,18 +208,18 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
public function test_get_item_with_variation_parent_name() {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product();
|
||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product();
|
||||
$variation = wc_get_product( $product->get_children()[0] );
|
||||
|
||||
$line_item = new WC_Order_Item_Product();
|
||||
$line_item->set_product( $variation );
|
||||
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$order->add_item( $line_item );
|
||||
$order->save();
|
||||
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
|
||||
$data = $response->get_data();
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertEquals( $order->get_id(), $data['id'] );
|
||||
|
@ -248,7 +251,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_get_item_refund_id() {
|
||||
wp_set_current_user( $this->user );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$refund = wc_create_refund(
|
||||
array(
|
||||
'order_id' => $order->get_id(),
|
||||
|
@ -352,7 +355,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
$this->assertEquals( 1, count( $data['line_items'] ) );
|
||||
$this->assertEquals( 1, count( $data['shipping_lines'] ) );
|
||||
|
||||
$shipping = current( $order->get_items( 'shipping' ) );
|
||||
$shipping = current( $order->get_items( 'shipping' ) );
|
||||
$expected_shipping_line = array(
|
||||
'id' => $shipping->get_id(),
|
||||
'method_title' => $shipping->get_method_title(),
|
||||
|
@ -542,7 +545,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_update_order() {
|
||||
wp_set_current_user( $this->user );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||
$request->set_body_params(
|
||||
array(
|
||||
|
@ -569,7 +572,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_update_order_remove_items() {
|
||||
wp_set_current_user( $this->user );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$fee = new WC_Order_Item_Fee();
|
||||
$fee->set_props(
|
||||
array(
|
||||
|
@ -610,7 +613,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
public function test_update_order_after_delete_product() {
|
||||
wp_set_current_user( $this->user );
|
||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_simple_product();
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order( 1, $product );
|
||||
$order = OrderHelper::create_order( 1, $product );
|
||||
$product->delete( true );
|
||||
|
||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||
|
@ -621,8 +624,8 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
array(
|
||||
'line_items' => array(
|
||||
array(
|
||||
'id' => $item->get_id(),
|
||||
'quantity' => 10,
|
||||
'id' => $item->get_id(),
|
||||
'quantity' => 10,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -652,56 +655,274 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
$this->assertEquals( $expected, $data['line_items'][0] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_update_order_add_coupons.
|
||||
*
|
||||
* @return array Data for test_update_order_add_coupons.
|
||||
*/
|
||||
public function data_provider_for_test_update_order_add_coupons() {
|
||||
return array(
|
||||
|
||||
// Successful case, no previous coupon, it gets created.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array(
|
||||
array(
|
||||
'code' => 'fake-coupon-2',
|
||||
),
|
||||
),
|
||||
),
|
||||
'order_has_coupon_before_request' => false,
|
||||
'expected_request_result' => array(
|
||||
'code' => 200,
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => 'fake-coupon-2',
|
||||
),
|
||||
|
||||
// Successful case with previous coupon, it gets replaced.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array(
|
||||
array(
|
||||
'code' => 'fake-coupon-2',
|
||||
),
|
||||
),
|
||||
),
|
||||
'order_has_coupon_before_request' => true,
|
||||
'expected_request_result' => array(
|
||||
'code' => 200,
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => 'fake-coupon-2',
|
||||
),
|
||||
|
||||
// Bad request: invalid coupon name, no previous coupon, it doesn't get added.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array(
|
||||
array(
|
||||
'code' => 'not-existing-coupon',
|
||||
),
|
||||
),
|
||||
),
|
||||
'order_has_coupon_before_request' => false,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Coupon "not-existing-coupon" does not exist!',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => null,
|
||||
),
|
||||
|
||||
// Bad request: invalid coupon name, coupon existed, it's kept.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array(
|
||||
array(
|
||||
'code' => 'not-existing-coupon',
|
||||
),
|
||||
),
|
||||
),
|
||||
'order_has_coupon_before_request' => true,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Coupon "not-existing-coupon" does not exist!',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||
),
|
||||
|
||||
// Bad request: has coupon id, no previous coupon, it doesn't get added.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array(
|
||||
array(
|
||||
'id' => '1234',
|
||||
'code' => 'fake-coupon-2',
|
||||
),
|
||||
),
|
||||
),
|
||||
'order_has_coupon_before_request' => false,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Coupon item ID is readonly.',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => null,
|
||||
),
|
||||
|
||||
// Bad request: has coupon id, previous coupon existed, it's kept.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array(
|
||||
array(
|
||||
'id' => '1234',
|
||||
'code' => 'fake-coupon-2',
|
||||
),
|
||||
),
|
||||
),
|
||||
'order_has_coupon_before_request' => true,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Coupon item ID is readonly.',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||
),
|
||||
|
||||
// Bad request: no coupon code, no previous coupon, it doesn't get added.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array(
|
||||
array(),
|
||||
),
|
||||
),
|
||||
'order_has_coupon_before_request' => false,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Coupon code is required.',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => null,
|
||||
),
|
||||
|
||||
// Bad request: no coupon code, previous coupon existed, it's kept.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array(
|
||||
array(),
|
||||
),
|
||||
),
|
||||
'order_has_coupon_before_request' => true,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Coupon code is required.',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||
),
|
||||
|
||||
// Bad request: invalid input ('coupon_lines' is not an array), no previous coupon, it doesn't get added.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => 1234,
|
||||
),
|
||||
'order_has_coupon_before_request' => false,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Invalid parameter(s): coupon_lines',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => null,
|
||||
),
|
||||
|
||||
// Bad request: invalid input ('coupon_lines' is not an array), previous coupon existed, it's kept.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => 1234,
|
||||
),
|
||||
'order_has_coupon_before_request' => true,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Invalid parameter(s): coupon_lines',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||
),
|
||||
|
||||
// Bad request: invalid input ('coupon_lines' has non-array elements), no previous coupon, it doesn't get added.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array( 1234 ),
|
||||
),
|
||||
'order_has_coupon_before_request' => false,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Invalid parameter(s): coupon_lines',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => null,
|
||||
),
|
||||
|
||||
// Bad request: invalid input ('coupon_lines' has non-array elements), previous coupon existed, it's kept.
|
||||
array(
|
||||
'request_body' => array(
|
||||
'coupon_lines' => array( 1234 ),
|
||||
),
|
||||
'order_has_coupon_before_request' => true,
|
||||
'expected_request_result' => array(
|
||||
'code' => 400,
|
||||
'message' => 'Invalid parameter(s): coupon_lines',
|
||||
),
|
||||
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests updating an order and adding a coupon.
|
||||
*
|
||||
* @dataProvider data_provider_for_test_update_order_add_coupons
|
||||
*
|
||||
* @param array $request_body The body for the API request.
|
||||
* @param bool $order_has_coupon_before_request If true, the order will have 'fake-coupon' applied before the API request.
|
||||
* @param array $expected_request_result Expected result from the API request, with 'code' and optionally 'message'.
|
||||
* @param string $expected_order_coupon_code_after_request Code of the expected applied coupon after the API request, null if it shouldn't have a coupon applied.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public function test_update_order_add_coupons() {
|
||||
public function test_update_order_add_coupons( $request_body, $order_has_coupon_before_request, $expected_request_result, $expected_order_coupon_code_after_request ) {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order_item = current( $order->get_items() );
|
||||
$coupon = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\CouponHelper::create_coupon( 'fake-coupon' );
|
||||
// Create order and coupons.
|
||||
|
||||
$order = OrderHelper::create_order();
|
||||
$original_order_amount = $order->get_total();
|
||||
|
||||
$coupons = array();
|
||||
|
||||
$coupon = CouponHelper::create_coupon( 'fake-coupon' );
|
||||
$coupon->set_amount( 5 );
|
||||
$coupon->save();
|
||||
$coupons['fake-coupon'] = $coupon;
|
||||
|
||||
$coupon = CouponHelper::create_coupon( 'fake-coupon-2' );
|
||||
$coupon->set_amount( 10 );
|
||||
$coupon->save();
|
||||
$coupons['fake-coupon-2'] = $coupon;
|
||||
|
||||
if ( $order_has_coupon_before_request ) {
|
||||
$order->apply_coupon( $coupons['fake-coupon'] );
|
||||
}
|
||||
|
||||
// Perform the request.
|
||||
|
||||
// Let's try a well-formed request first of all.
|
||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||
$request->set_body_params(
|
||||
array(
|
||||
'coupon_lines' => array(
|
||||
array(
|
||||
'code' => 'fake-coupon',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$request->set_body_params( $request_body );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertCount( 1, $data['coupon_lines'] );
|
||||
$this->assertEquals( '45.00', $data['total'] );
|
||||
// Check the response and the actual order data after the operation.
|
||||
|
||||
// Let's repeat, but this time we'll specify the item ID for the coupon: this is
|
||||
// a readonly property and we expect the request to fail as a result.
|
||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||
$request->set_body_params(
|
||||
array(
|
||||
'coupon_lines' => array(
|
||||
array(
|
||||
'id' => 123,
|
||||
'code' => 'fake-coupon',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
$this->assertEquals( $expected_request_result['code'], $response->get_status() );
|
||||
|
||||
$this->assertEquals( 400, $response->get_status() );
|
||||
$this->assertEquals( 'woocommerce_rest_coupon_item_id_readonly', $data['code'] );
|
||||
$order = wc_get_order( $order->get_id() );
|
||||
$order_coupons = array_values( $order->get_coupons() );
|
||||
if ( is_null( $expected_order_coupon_code_after_request ) ) {
|
||||
$expected_coupon = null;
|
||||
$expected_order_amount = $original_order_amount;
|
||||
} else {
|
||||
$expected_coupon = $coupons[ $expected_order_coupon_code_after_request ];
|
||||
$expected_order_amount = number_format( 50 - $expected_coupon->get_amount(), 2 );
|
||||
}
|
||||
|
||||
$is_ok_status = $response->get_status() < 300;
|
||||
if ( $is_ok_status ) {
|
||||
$this->assertEquals( $expected_order_amount, $data['total'] );
|
||||
$this->assertCount( 1, $data['coupon_lines'] );
|
||||
} else {
|
||||
$this->assertEquals( $expected_request_result['message'], $data['message'] );
|
||||
}
|
||||
|
||||
if ( is_null( $expected_order_coupon_code_after_request ) ) {
|
||||
$this->assertEquals( '50.00', $order->get_total() );
|
||||
$this->assertCount( 0, $order_coupons );
|
||||
} else {
|
||||
$this->assertEquals( number_format( $expected_order_amount, 2 ), $order->get_total() );
|
||||
$this->assertCount( 1, $order_coupons );
|
||||
$this->assertEquals( $expected_coupon->get_code(), $order_coupons[0]->get_code() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -711,9 +932,9 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_update_order_remove_coupons() {
|
||||
wp_set_current_user( $this->user );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$order_item = current( $order->get_items() );
|
||||
$coupon = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\CouponHelper::create_coupon( 'fake-coupon' );
|
||||
$coupon = CouponHelper::create_coupon( 'fake-coupon' );
|
||||
$coupon->set_amount( 5 );
|
||||
$coupon->save();
|
||||
|
||||
|
@ -723,7 +944,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
// Check that the coupon is applied.
|
||||
$this->assertEquals( '45.00', $order->get_total() );
|
||||
|
||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||
|
||||
$request->set_body_params(
|
||||
array(
|
||||
|
@ -752,7 +973,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_invalid_coupon() {
|
||||
wp_set_current_user( $this->user );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||
|
||||
$request->set_body_params(
|
||||
|
@ -779,7 +1000,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_update_order_without_permission() {
|
||||
wp_set_current_user( 0 );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||
$request->set_body_params(
|
||||
array(
|
||||
|
@ -822,7 +1043,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_delete_order() {
|
||||
wp_set_current_user( $this->user );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$request = new WP_REST_Request( 'DELETE', '/wc/v3/orders/' . $order->get_id() );
|
||||
$request->set_param( 'force', true );
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
@ -837,7 +1058,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_delete_order_without_permission() {
|
||||
wp_set_current_user( 0 );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$request = new WP_REST_Request( 'DELETE', '/wc/v3/orders/' . $order->get_id() );
|
||||
$request->set_param( 'force', true );
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
@ -865,9 +1086,9 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
public function test_orders_batch() {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$order1 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order2 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order3 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order1 = OrderHelper::create_order();
|
||||
$order2 = OrderHelper::create_order();
|
||||
$order3 = OrderHelper::create_order();
|
||||
|
||||
$request = new WP_REST_Request( 'POST', '/wc/v3/orders/batch' );
|
||||
$request->set_body_params(
|
||||
|
@ -904,7 +1125,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_order_schema() {
|
||||
wp_set_current_user( $this->user );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$order = OrderHelper::create_order();
|
||||
$request = new WP_REST_Request( 'OPTIONS', '/wc/v3/orders/' . $order->get_id() );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
|
@ -919,8 +1140,8 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_order_line_items_schema() {
|
||||
wp_set_current_user( $this->user );
|
||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
||||
$request = new WP_REST_Request( 'OPTIONS', '/wc/v3/orders/' . $order->get_id() );
|
||||
$order = OrderHelper::create_order();
|
||||
$request = new WP_REST_Request( 'OPTIONS', '/wc/v3/orders/' . $order->get_id() );
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
||||
$data = $response->get_data();
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
*/
|
||||
class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
|
@ -17,6 +20,9 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
|||
$this->create_session();
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Test that save data should insert new row.
|
||||
*/
|
||||
public function test_save_data_should_insert_new_row() {
|
||||
$current_session_data = $this->get_session_from_db( $this->session_key );
|
||||
// delete session to make sure a new row is created in the DB.
|
||||
|
@ -35,6 +41,9 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
|||
$this->assertEquals( array( 'cart' => 'new cart' ), wp_cache_get( $this->cache_prefix . $this->session_key, WC_SESSION_CACHE_GROUP ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Test that save data should replace existing row.
|
||||
*/
|
||||
public function test_save_data_should_replace_existing_row() {
|
||||
$current_session_data = $this->get_session_from_db( $this->session_key );
|
||||
|
||||
|
@ -49,23 +58,35 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
|||
$this->assertTrue( is_numeric( $updated_session_data->session_expiry ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Test that get_setting() should use cache.
|
||||
*/
|
||||
public function test_get_session_should_use_cache() {
|
||||
$session = $this->handler->get_session( $this->session_key );
|
||||
$this->assertEquals( array( 'cart' => 'fake cart' ), $session );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Test that get_setting() shouldn't use cache.
|
||||
*/
|
||||
public function test_get_session_should_not_use_cache() {
|
||||
wp_cache_delete( $this->cache_prefix . $this->session_key, WC_SESSION_CACHE_GROUP );
|
||||
$session = $this->handler->get_session( $this->session_key );
|
||||
$this->assertEquals( array( 'cart' => 'fake cart' ), $session );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Test that get_setting() should return default value.
|
||||
*/
|
||||
public function test_get_session_should_return_default_value() {
|
||||
$default_session = array( 'session' => 'default' );
|
||||
$session = $this->handler->get_session( 'non-existent key', $default_session );
|
||||
$this->assertEquals( $default_session, $session );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Test delete_session().
|
||||
*/
|
||||
public function test_delete_session() {
|
||||
global $wpdb;
|
||||
|
||||
|
@ -82,6 +103,9 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
|||
$this->assertNull( $session_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Test update_session_timestamp().
|
||||
*/
|
||||
public function test_update_session_timestamp() {
|
||||
global $wpdb;
|
||||
|
||||
|
@ -98,6 +122,14 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
|||
$this->assertEquals( $timestamp, $session_expiry );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Test that nonce of user logged out is only changed by WooCommerce.
|
||||
*/
|
||||
public function test_maybe_update_nonce_user_logged_out() {
|
||||
$this->assertEquals( 1, $this->handler->maybe_update_nonce_user_logged_out( 1, 'wp_rest' ) );
|
||||
$this->assertEquals( $this->handler->get_customer_unique_id(), $this->handler->maybe_update_nonce_user_logged_out( 1, 'woocommerce-something' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a WC session and save it to the DB.
|
||||
*/
|
||||
|
@ -113,7 +145,7 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
|||
/**
|
||||
* Helper function to get session data from DB.
|
||||
*
|
||||
* @param string $session_key
|
||||
* @param string $session_key Session key.
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_session_from_db( $session_key ) {
|
||||
|
|
|
@ -14,12 +14,22 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
|||
* Set up
|
||||
*/
|
||||
public function setUp() {
|
||||
// set default country to US so that 'payments' task does not get added.
|
||||
// we want to remove payment tasks as they depend on installation & activation.
|
||||
update_option( 'woocommerce_default_country', 'US' );
|
||||
// Set default country to non-US so that 'payments' task gets added but 'woocommerce-payments' doesn't,
|
||||
// by default it won't be considered completed but we can manually change that as needed.
|
||||
update_option( 'woocommerce_default_country', 'JP' );
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down
|
||||
*/
|
||||
public function tearDown() {
|
||||
remove_all_filters( 'woocommerce_available_payment_gateways' );
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes widget class and return the class.
|
||||
*
|
||||
|
@ -75,13 +85,21 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests the widget output when 0 task has been completed.
|
||||
* Tests the widget output when 1 task has been completed.
|
||||
*/
|
||||
public function test_initial_widget_output() {
|
||||
// Force the "payments" task to be considered incomplete.
|
||||
add_filter(
|
||||
'woocommerce_available_payment_gateways',
|
||||
function() {
|
||||
return array();
|
||||
}
|
||||
);
|
||||
|
||||
$html = $this->get_widget_output();
|
||||
|
||||
$required_strings = array(
|
||||
'Step 0 of 5',
|
||||
'Step 0 of 6',
|
||||
'You're almost there! Once you complete store setup you can start receiving orders.',
|
||||
'Start selling',
|
||||
'admin.php\?page=wc-admin&path=%2Fsetup-wizard',
|
||||
|
@ -96,9 +114,22 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
|||
* Tests completed task count as it completes one by one
|
||||
*/
|
||||
public function test_widget_renders_completed_task_count() {
|
||||
$completed_tasks = array();
|
||||
// Force the "payments" task to be considered completed
|
||||
// by faking a valid payment gateway.
|
||||
add_filter(
|
||||
'woocommerce_available_payment_gateways',
|
||||
function() {
|
||||
return array(
|
||||
new class() extends WC_Payment_Gateway {
|
||||
},
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
$completed_tasks = array( 'payments' );
|
||||
$tasks = $this->get_widget()->get_tasks();
|
||||
$tasks_count = count( $tasks );
|
||||
unset( $tasks['payments'] ); // That one is completed already.
|
||||
foreach ( $tasks as $key => $task ) {
|
||||
array_push( $completed_tasks, $key );
|
||||
update_option( 'woocommerce_task_list_tracked_completed_tasks', $completed_tasks );
|
||||
|
@ -108,7 +139,7 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
|||
if ( $completed_tasks_count === $tasks_count ) {
|
||||
$this->assertEmpty( $this->get_widget_output() );
|
||||
} else {
|
||||
$this->assertRegexp( "/Step ${completed_tasks_count} of 5/", $this->get_widget_output() );
|
||||
$this->assertRegexp( "/Step ${completed_tasks_count} of 6/", $this->get_widget_output() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,13 +153,13 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
|||
array(
|
||||
array(
|
||||
'woocommerce_task_list_complete' => 'yes',
|
||||
'woocommerce_task_list_hidden' => 'no',
|
||||
'woocommerce_task_list_hidden' => 'no',
|
||||
),
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'woocommerce_task_list_complete' => 'no',
|
||||
'woocommerce_task_list_hidden' => 'yes',
|
||||
'woocommerce_task_list_hidden' => 'yes',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* class WC_REST_Taxes_Controller_Tests.
|
||||
* Taxes Controller tests for V3 REST API.
|
||||
*/
|
||||
class WC_REST_Taxes_Controller_Tests extends WC_REST_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Runs before any test.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->user = $this->factory->user->create(
|
||||
array(
|
||||
'role' => 'administrator',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_can_create_and_update_tax_rates_with_multiple_cities_and_postcodes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_provider_for_test_can_create_and_update_tax_rates_with_multiple_cities_and_postcodes() {
|
||||
return array(
|
||||
array(
|
||||
array(
|
||||
'city' => 'Osaka;Kyoto;Kobe',
|
||||
'postcode' => '5555;7777;8888',
|
||||
),
|
||||
'create',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'cities' => array(
|
||||
'Osaka',
|
||||
'Kyoto',
|
||||
'Kobe',
|
||||
),
|
||||
'postcodes' => array(
|
||||
'5555',
|
||||
'7777',
|
||||
'8888',
|
||||
),
|
||||
),
|
||||
'create',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'city' => 'Osaka;Kyoto;Kobe',
|
||||
'postcode' => '5555;7777;8888',
|
||||
),
|
||||
'update',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'cities' => array(
|
||||
'Osaka',
|
||||
'Kyoto',
|
||||
'Kobe',
|
||||
),
|
||||
'postcodes' => array(
|
||||
'5555',
|
||||
'7777',
|
||||
'8888',
|
||||
),
|
||||
),
|
||||
'update',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox It is possible to create or update a tax rate passing either "city"/"postcode" (strings) or "cities"/"postcodes" (arrays) fields.
|
||||
*
|
||||
* @dataProvider data_provider_for_test_can_create_and_update_tax_rates_with_multiple_cities_and_postcodes
|
||||
*
|
||||
* @param array $request_body The body for the REST request.
|
||||
* @param string $action The action to perform, 'create' or 'update'.
|
||||
*/
|
||||
public function test_can_create_and_update_tax_rates_with_multiple_cities_and_postcodes( $request_body, $action ) {
|
||||
global $wpdb;
|
||||
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
if ( 'create' === $action ) {
|
||||
$tax_rate_id = null;
|
||||
|
||||
$request_body = array_merge(
|
||||
$request_body,
|
||||
array(
|
||||
'country' => 'JP',
|
||||
'rate' => '1',
|
||||
'name' => 'Fake Tax',
|
||||
)
|
||||
);
|
||||
|
||||
$verb = 'POST';
|
||||
$url = 'taxes';
|
||||
$success_status = 201;
|
||||
} else {
|
||||
$tax_rate_id = WC_Tax::_insert_tax_rate(
|
||||
array(
|
||||
'tax_rate_country' => 'JP',
|
||||
'tax_rate' => '1',
|
||||
'tax_rate_name' => 'Fake Tax',
|
||||
)
|
||||
);
|
||||
|
||||
WC_Tax::_update_tax_rate_cities( $tax_rate_id, 'Tokyo' );
|
||||
WC_Tax::_update_tax_rate_postcodes( $tax_rate_id, '0000' );
|
||||
|
||||
$verb = 'PUT';
|
||||
$url = 'taxes/' . $tax_rate_id;
|
||||
$success_status = 200;
|
||||
}
|
||||
|
||||
$response = $this->do_rest_request( $url, $verb, $request_body );
|
||||
$this->assertEquals( $success_status, $response->get_status() );
|
||||
if ( ! $tax_rate_id ) {
|
||||
$tax_rate_id = $response->get_data()['id'];
|
||||
}
|
||||
|
||||
$data = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT location_type, GROUP_CONCAT(location_code SEPARATOR ';') as items
|
||||
FROM {$wpdb->prefix}woocommerce_tax_rate_locations
|
||||
WHERE tax_rate_id=%d
|
||||
GROUP BY location_type",
|
||||
$tax_rate_id
|
||||
),
|
||||
OBJECT_K
|
||||
);
|
||||
|
||||
$this->assertEquals( 'OSAKA;KYOTO;KOBE', $data['city']->items );
|
||||
$this->assertEquals( '5555;7777;8888', $data['postcode']->items );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox The response for tax rate(s) includes the "city"/"postcode" (strings) and "cities"/"postcodes" (arrays) fields.
|
||||
*
|
||||
* @testWith [true]
|
||||
* [false]
|
||||
*
|
||||
* @param bool $request_one True to request only one tax, false to request all the taxes.
|
||||
*/
|
||||
public function test_get_tax_response_includes_cities_and_postcodes_as_arrays( $request_one ) {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$tax_id = WC_Tax::_insert_tax_rate(
|
||||
array(
|
||||
'tax_rate_country' => 'JP',
|
||||
'tax_rate' => '1',
|
||||
'tax_rate_name' => 'Fake Tax',
|
||||
)
|
||||
);
|
||||
|
||||
WC_Tax::_update_tax_rate_cities( $tax_id, 'Osaka;Kyoto;Kobe' );
|
||||
WC_Tax::_update_tax_rate_postcodes( $tax_id, '5555;7777;8888' );
|
||||
|
||||
if ( $request_one ) {
|
||||
$response = $this->do_rest_get_request( 'taxes/' . $tax_id );
|
||||
} else {
|
||||
$response = $this->do_rest_get_request( 'taxes' );
|
||||
}
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$data = $response->get_data();
|
||||
if ( ! $request_one ) {
|
||||
$data = current( $data );
|
||||
}
|
||||
|
||||
$this->assertEquals( 'KOBE', $data['city'] );
|
||||
$this->assertEquals( '8888', $data['postcode'] );
|
||||
$this->assertEquals( array( 'OSAKA', 'KYOTO', 'KOBE' ), $data['cities'] );
|
||||
$this->assertEquals( array( '5555', '7777', '8888' ), $data['postcodes'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox The response of a REST API request for taxes can be sorted by priority.
|
||||
*
|
||||
* @testWith ["asc"]
|
||||
* ["desc"]
|
||||
*
|
||||
* @param string $order_type Sort type, 'asc' or 'desc'.
|
||||
*/
|
||||
public function test_get_tax_response_can_be_sorted_by_priority( $order_type ) {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$tax_id_1 = WC_Tax::_insert_tax_rate(
|
||||
array(
|
||||
'tax_rate_country' => 'JP',
|
||||
'tax_rate' => '1',
|
||||
'tax_rate_priority' => 1,
|
||||
'tax_rate_name' => 'Fake Tax 1',
|
||||
)
|
||||
);
|
||||
$tax_id_3 = WC_Tax::_insert_tax_rate(
|
||||
array(
|
||||
'tax_rate_country' => 'JP',
|
||||
'tax_rate' => '1',
|
||||
'tax_rate_priority' => 3,
|
||||
'tax_rate_name' => 'Fake Tax 3',
|
||||
)
|
||||
);
|
||||
$tax_id_2 = WC_Tax::_insert_tax_rate(
|
||||
array(
|
||||
'tax_rate_country' => 'JP',
|
||||
'tax_rate' => '1',
|
||||
'tax_rate_priority' => 2,
|
||||
'tax_rate_name' => 'Fake Tax 2',
|
||||
)
|
||||
);
|
||||
|
||||
$response = $this->do_rest_get_request(
|
||||
'taxes',
|
||||
array(
|
||||
'orderby' => 'priority',
|
||||
'order' => $order_type,
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$data = array_values( $response->get_data() );
|
||||
$ids = array_map(
|
||||
function( $item ) {
|
||||
return $item['id'];
|
||||
},
|
||||
$data
|
||||
);
|
||||
|
||||
if ( 'asc' === $order_type ) {
|
||||
$expected = array( $tax_id_1, $tax_id_2, $tax_id_3 );
|
||||
} else {
|
||||
$expected = array( $tax_id_3, $tax_id_2, $tax_id_1 );
|
||||
}
|
||||
$this->assertEquals( $expected, $ids );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Tax rates can be queries filtering by tax class.
|
||||
*
|
||||
* @testWith ["standard"]
|
||||
* ["reduced-rate"]
|
||||
* ["zero-rate"]
|
||||
*
|
||||
* @param string $class The tax class name to try getting the taxes for.
|
||||
*/
|
||||
public function test_can_get_taxes_filtering_by_class( $class ) {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$classes = array( 'standard', 'reduced-rate', 'zero-rate' );
|
||||
|
||||
$tax_ids_by_class = array();
|
||||
foreach ( $classes as $class ) {
|
||||
$tax_id = WC_Tax::_insert_tax_rate(
|
||||
array(
|
||||
'tax_rate_country' => 'JP',
|
||||
'tax_rate' => '1',
|
||||
'tax_rate_priority' => 1,
|
||||
'tax_rate_name' => 'Fake Tax',
|
||||
'tax_rate_class' => $class,
|
||||
)
|
||||
);
|
||||
$tax_ids_by_class[ $class ] = $tax_id;
|
||||
}
|
||||
|
||||
$response = $this->do_rest_get_request(
|
||||
'taxes',
|
||||
array(
|
||||
'class' => $class,
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$data = array_values( $response->get_data() );
|
||||
$ids = array_map(
|
||||
function( $item ) {
|
||||
return $item['id'];
|
||||
},
|
||||
$data
|
||||
);
|
||||
|
||||
$this->assertEquals( array( $tax_ids_by_class[ $class ] ), $ids );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue