diff --git a/.gitignore b/.gitignore index 799075b..805e9d5 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ composer.lock /packages/* !/packages/README.md /composer.lock +.phpunit.result.cache diff --git a/assets/css/admin.scss b/assets/css/admin.scss index daa8197..f7aae6b 100644 --- a/assets/css/admin.scss +++ b/assets/css/admin.scss @@ -671,6 +671,7 @@ tbody.packaging_list { border-radius: 3px; display: inline-flex; white-space: nowrap; + max-width: 100%; &.status-draft, &.status-processing, &.status-requested, &.status-partially-shipped, &.status-partially-delivered, &.status-open, &.status-partially-returned { background: #f8dda7; @@ -691,6 +692,11 @@ tbody.packaging_list { background: #f8dda7; color: #94660c; } + + > span { + overflow: hidden; + text-overflow: ellipsis; + } } a.button.wc-stc-shipment-action-button { diff --git a/assets/js/blocks/checkout-pickup-location-select/index.js b/assets/js/blocks/checkout-pickup-location-select/index.js index f6f2341..0b74b59 100644 --- a/assets/js/blocks/checkout-pickup-location-select/index.js +++ b/assets/js/blocks/checkout-pickup-location-select/index.js @@ -1 +1,2 @@ -import './slotfills/pickup-location-select'; \ No newline at end of file +import './slotfills/pickup-location-select'; +import './set-payment-method'; \ No newline at end of file diff --git a/assets/js/blocks/checkout-pickup-location-select/set-payment-method.js b/assets/js/blocks/checkout-pickup-location-select/set-payment-method.js new file mode 100644 index 0000000..a3c0c7b --- /dev/null +++ b/assets/js/blocks/checkout-pickup-location-select/set-payment-method.js @@ -0,0 +1,38 @@ +import { registerPlugin } from "@wordpress/plugins"; +import { useEffect, useState, useCallback, useRef } from '@wordpress/element'; +import { useSelect } from '@wordpress/data'; +import { extensionCartUpdate } from '@woocommerce/blocks-checkout'; +import _ from 'lodash'; +import { PAYMENT_STORE_KEY } from '@woocommerce/block-data'; + +const render = () => { + const { + currentPaymentMethod + } = useSelect( ( select ) => { + const paymentStore = select( PAYMENT_STORE_KEY ); + + return { + currentPaymentMethod: paymentStore.getActivePaymentMethod(), + } + } ); + + useEffect( () => { + if ( currentPaymentMethod ) { + extensionCartUpdate( { + namespace: 'woocommerce-shiptastic-set-payment-method', + data: { + 'active_method': currentPaymentMethod, + }, + } ); + } + }, [ + currentPaymentMethod + ] ); + + return null; +}; + +registerPlugin( 'woocommerce-shiptastic-set-payment-method', { + render, + scope: 'woocommerce-checkout', +} ); \ No newline at end of file diff --git a/assets/js/static/admin-shipment.js b/assets/js/static/admin-shipment.js index 7c2e489..6c5c534 100644 --- a/assets/js/static/admin-shipment.js +++ b/assets/js/static/admin-shipment.js @@ -402,8 +402,6 @@ window.shiptastic.admin = window.shiptastic.admin || {}; }; this.onAddItemSuccess = function( data ) { - this.getShipmentContent().find( '.shipment-item-list' ).append( data.new_item ); - this.refreshDom(); this.unblockItems(); }; diff --git a/assets/js/static/admin-shipments-table.js b/assets/js/static/admin-shipments-table.js index ab64c3c..cb76c23 100644 --- a/assets/js/static/admin-shipments-table.js +++ b/assets/js/static/admin-shipments-table.js @@ -37,7 +37,6 @@ window.shiptastic.admin = window.shiptastic.admin || {}; }); if ( self.params.bulk_actions.hasOwnProperty( action ) && ids.length > 0 ) { - var actionData = self.params.bulk_actions[ action ]; $( '.bulk-action-wrapper' ).find( '.bulk-title' ).text( actionData['title'] ); @@ -63,6 +62,7 @@ window.shiptastic.admin = window.shiptastic.admin || {}; bulk_action : action, step : step, type : type, + referer : window.location.href, ids : ids, security : actionData['nonce'] }, diff --git a/assets/js/static/admin-shipping-provider-method.js b/assets/js/static/admin-shipping-provider-method.js index fa309d6..585f7c0 100644 --- a/assets/js/static/admin-shipping-provider-method.js +++ b/assets/js/static/admin-shipping-provider-method.js @@ -20,7 +20,7 @@ window.shiptastic.admin = window.shiptastic.admin || {}; .on( 'change', 'select[id$=shipping_provider]', self.showOrHideAll ) .on( 'click', '.wc-stc-shipping-provider-method-tabs .nav-tab-wrapper a.nav-tab', self.onChangeTab ) .on( 'change', '.override-checkbox :input', self.onChangeOverride ) - .on( 'change', '.wc-gzd-shipping-provider-method-tab-content :input[id]', self.onChangeInput ); + .on( 'change', '.wc-stc-shipping-provider-method-tab-content :input[id]', self.onChangeInput ); $( document.body ).on( 'wc_backbone_modal_loaded', self.onShippingMethodOpen ); @@ -65,6 +65,7 @@ window.shiptastic.admin = window.shiptastic.admin || {}; if ( $tab.length > 0 ) { $navTab.addClass( 'nav-tab-active' ); $tab.addClass( 'tab-content-active' ); + $tab.find( ':input:visible' ).trigger( 'change' ); } diff --git a/includes/admin/views/html-order-add-return-shipment-items.php b/includes/admin/views/html-order-add-return-shipment-items.php index 2b9a44a..685d6eb 100644 --- a/includes/admin/views/html-order-add-return-shipment-items.php +++ b/includes/admin/views/html-order-add-return-shipment-items.php @@ -6,7 +6,7 @@ ?> get_available_items_for_return() as $item_id => $item_data ) : +foreach ( $order_shipment->get_selectable_items_for_return() as $item_id => $item_data ) : ?> diff --git a/includes/admin/views/html-order-shipment-content.php b/includes/admin/views/html-order-shipment-content.php index 0d00024..a0e7ba7 100644 --- a/includes/admin/views/html-order-shipment-content.php +++ b/includes/admin/views/html-order-shipment-content.php @@ -119,8 +119,13 @@ if ( $shipment->supports_label() && ( ( $label = $shipment->get_label() ) || $shipment->needs_label() ) ) : include 'label/html-shipment-label.php'; - endif; - ?> + elseif ( $shipment->get_tracking_url() ) : + ?> +
+

+ get_tracking_id() ); ?> +
+
diff --git a/includes/admin/views/html-order-shipment-list.php b/includes/admin/views/html-order-shipment-list.php index f9846d4..5a48074 100644 --- a/includes/admin/views/html-order-shipment-list.php +++ b/includes/admin/views/html-order-shipment-list.php @@ -19,7 +19,7 @@

- get_return_status() ) ); ?> + get_return_status() ) ); ?>
diff --git a/includes/admin/views/html-order-shipment.php b/includes/admin/views/html-order-shipment.php index 60d53eb..907e516 100644 --- a/includes/admin/views/html-order-shipment.php +++ b/includes/admin/views/html-order-shipment.php @@ -11,7 +11,7 @@

get_type() ) ), esc_html( $shipment->get_shipment_number() ) ); ?>

- get_status() ) ); ?> + get_status() ) ); ?>
diff --git a/includes/admin/views/html-order-shipments.php b/includes/admin/views/html-order-shipments.php index d5d072d..3b9a990 100644 --- a/includes/admin/views/html-order-shipments.php +++ b/includes/admin/views/html-order-shipments.php @@ -14,7 +14,7 @@

- get_shipping_status() ) ); ?> + get_shipping_status() ) ); ?>
diff --git a/src/Admin/Admin.php b/src/Admin/Admin.php index 2ef74f6..d5e119c 100644 --- a/src/Admin/Admin.php +++ b/src/Admin/Admin.php @@ -658,7 +658,7 @@ public static function render_order_columns( $column, $post_id ) { if ( $shipment_order = wc_stc_get_shipment_order( $the_order ) ) { $shipping_status = $shipment_order->get_shipping_status(); - $status_html = '' . esc_html( wc_stc_get_shipment_order_shipping_status_name( $shipping_status ) ) . ''; + $status_html = '' . esc_html( wc_stc_get_shipment_order_shipping_status_name( $shipping_status ) ) . ''; if ( in_array( $shipping_status, array( 'shipped', 'partially-shipped' ), true ) && $shipment_order->get_shipments() ) { if ( $last_shipment = $shipment_order->get_last_shipment_with_tracking() ) { diff --git a/src/Admin/BulkActionHandler.php b/src/Admin/BulkActionHandler.php index 853e780..ec3a8a3 100644 --- a/src/Admin/BulkActionHandler.php +++ b/src/Admin/BulkActionHandler.php @@ -52,14 +52,23 @@ public function set_shipment_type( $type ) { $this->type = $type; } - public function get_success_redirect_url() { + public function get_success_redirect_url( $referer = false ) { $page = 'wc-shiptastic'; if ( 'simple' !== $this->get_shipment_type() ) { $page = 'wc-stc-' . $this->get_shipment_type() . '-shipments'; } - return admin_url( 'admin.php?page=' . $page . '&bulk_action_handling=finished¤t_bulk_action=' . sanitize_key( $this->get_action() ) ); + $base_url = $referer ? $referer : admin_url( 'admin.php?page=' . $page ); + $base_url = add_query_arg( + array( + 'bulk_action_handling' => 'finished', + 'current_bulk_action' => sanitize_key( $this->get_action() ), + ), + $base_url + ); + + return esc_url_raw( $base_url ); } public function get_step() { diff --git a/src/Admin/Table.php b/src/Admin/Table.php index 56e9471..0a782b8 100644 --- a/src/Admin/Table.php +++ b/src/Admin/Table.php @@ -454,13 +454,15 @@ protected function get_views() { /** * Helper to create links to edit.php with params. * - * * @param string[] $args Associative array of URL parameters for the link. * @param string $label Link text. * @param string $class_name Optional. Class attribute. Default empty string. * * @return string The formatted link string. + *@since 4.4.0 + * */ + protected function get_edit_link( $args, $label, $class_name = '' ) { $url = add_query_arg( $args, $this->get_main_page() ); @@ -1054,7 +1056,7 @@ public function column_address( $shipment ) { * @param Shipment $shipment The current shipment object. */ public function column_status( $shipment ) { - echo '' . esc_html( wc_stc_get_shipment_status_name( $shipment->get_status() ) ) . ''; + echo '' . esc_html( wc_stc_get_shipment_status_name( $shipment->get_status() ) ) . ''; } /** @@ -1166,7 +1168,7 @@ protected function get_custom_bulk_actions( $actions ) { protected function get_hook_prefix() { $suffix = ( 'simple' === $this->shipment_type ? '' : '_' . $this->shipment_type ); - return "woocommerce_gzd{$suffix}_shipments_table_"; + return "woocommerce_shiptastic{$suffix}_shipments_table_"; } /** diff --git a/src/Ajax.php b/src/Ajax.php index bb6fe8e..5168fc0 100644 --- a/src/Ajax.php +++ b/src/Ajax.php @@ -521,8 +521,9 @@ public static function sort_shipping_provider() { } public static function shipments_bulk_action_handle() { - $action = isset( $_POST['bulk_action'] ) ? wc_clean( wp_unslash( $_POST['bulk_action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing - $type = isset( $_POST['type'] ) ? wc_clean( wp_unslash( $_POST['type'] ) ) : 'simple'; // phpcs:ignore WordPress.Security.NonceVerification.Missing + $action = isset( $_POST['bulk_action'] ) ? wc_clean( wp_unslash( $_POST['bulk_action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing + $type = isset( $_POST['type'] ) ? wc_clean( wp_unslash( $_POST['type'] ) ) : 'simple'; // phpcs:ignore WordPress.Security.NonceVerification.Missing + $referer = isset( $_POST['referer'] ) ? wp_sanitize_redirect( wp_unslash( $_POST['referer'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing check_ajax_referer( "woocommerce_shiptastic_{$action}", 'security' ); @@ -573,7 +574,7 @@ public static function shipments_bulk_action_handle() { array( 'step' => 'done', 'percentage' => 100, - 'url' => $handler->get_success_redirect_url(), + 'url' => $handler->get_success_redirect_url( $referer ), 'type' => $handler->get_shipment_type(), ) ); @@ -1028,7 +1029,7 @@ public static function json_search_orders() { } private static function get_order_status_html( $order_shipment ) { - $status_html = '' . wc_stc_get_shipment_order_shipping_status_name( $order_shipment->get_shipping_status() ) . ''; + $status_html = '' . wc_stc_get_shipment_order_shipping_status_name( $order_shipment->get_shipping_status() ) . ''; return $status_html; } @@ -1090,7 +1091,7 @@ private static function get_global_order_status_html( $order ) { } private static function get_order_return_status_html( $order_shipment ) { - $status_html = '' . wc_stc_get_shipment_order_return_status_name( $order_shipment->get_return_status() ) . ''; + $status_html = '' . wc_stc_get_shipment_order_return_status_name( $order_shipment->get_return_status() ) . ''; return $status_html; } @@ -1287,14 +1288,14 @@ public static function add_shipment_item_load() { $items = array(); if ( 'return' === $shipment->get_type() ) { - $items = $order_shipment->get_available_items_for_return( + $items = $order_shipment->get_selectable_items_for_return( array( 'shipment_id' => $shipment->get_id(), 'disable_duplicates' => true, ) ); } else { - $items = $order_shipment->get_available_items_for_shipment( + $items = $order_shipment->get_selectable_items_for_shipment( array( 'shipment_id' => $shipment_id, 'disable_duplicates' => true, @@ -1322,9 +1323,8 @@ public static function add_shipment_item_submit() { ); $response = array( - 'success' => true, - 'message' => '', - 'new_item' => '', + 'success' => true, + 'message' => '', ); $shipment_id = absint( $_POST['reference_id'] ); @@ -1367,10 +1367,13 @@ public static function add_shipment_item_submit() { } ob_start(); - include Package::get_path() . '/includes/admin/views/html-order-shipment-item.php'; - $response['new_item'] = ob_get_clean(); + foreach ( $shipment->get_items() as $item ) { + include Package::get_path() . '/includes/admin/views/html-order-shipment-item.php'; + } + $html = ob_get_clean(); $response['fragments'] = array( + '#shipment-' . $shipment->get_id() . ' .shipment-item-list:first' => '
' . $html . '
', '#shipment-' . $shipment->get_id() . ' .item-count:first' => self::get_item_count_html( $shipment, $order_shipment ), ); diff --git a/src/Blocks/Checkout.php b/src/Blocks/Checkout.php index ec1b9b7..14b273a 100644 --- a/src/Blocks/Checkout.php +++ b/src/Blocks/Checkout.php @@ -197,6 +197,17 @@ private function register_endpoint_data() { }, ) ); + + woocommerce_store_api_register_update_callback( + array( + 'namespace' => 'woocommerce-shiptastic-set-payment-method', + 'callback' => function ( $data ) { + $active_method = isset( $data['active_method'] ) ? wc_clean( wp_unslash( $data['active_method'] ) ) : ''; + + WC()->session->set( 'wc_shiptastic_blocks_chosen_payment_method', $active_method ); + }, + ) + ); } private function get_checkout_schema() { diff --git a/src/Blocks/StoreApi/RoutesController.php b/src/Blocks/StoreApi/RoutesController.php index 161a9fc..84f5fbf 100644 --- a/src/Blocks/StoreApi/RoutesController.php +++ b/src/Blocks/StoreApi/RoutesController.php @@ -74,8 +74,8 @@ public function get( $name, $version = 'v1' ) { /** * Register defined list of routes with WordPress. * - * @param string $version API Version being registered.. - * @param string $namespace Overrides the default route namespace. + * @param string $version API Version being registered. + * @param string $ns Overrides the default route namespace. */ protected function register_routes( $version = 'v1', $namespace = 'wc/store/v1' ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.namespaceFound if ( ! isset( $this->routes[ $version ] ) ) { diff --git a/src/Compatibility/Bundles.php b/src/Compatibility/Bundles.php index ba8fb09..d37773d 100644 --- a/src/Compatibility/Bundles.php +++ b/src/Compatibility/Bundles.php @@ -5,6 +5,7 @@ use Vendidero\Shiptastic\Interfaces\Compatibility; use Vendidero\Shiptastic\Product; use Vendidero\Shiptastic\Shipment; +use Vendidero\Shiptastic\ShipmentItem; defined( 'ABSPATH' ) || exit; @@ -24,10 +25,79 @@ function () { } ); - add_filter( 'woocommerce_shiptastic_order_item_product', array( __CLASS__, 'get_product_from_item' ), 10, 2 ); + add_filter( 'woocommerce_shiptastic_shipment_order_item_product', array( __CLASS__, 'get_product_from_item' ), 10, 2 ); add_filter( 'woocommerce_shiptastic_cart_item', array( __CLASS__, 'adjust_cart_item' ), 10, 2 ); - add_action( 'woocommerce_shiptastic_shipment_items_synced', array( __CLASS__, 'apply_bundle_hierarchy' ), 10, 3 ); - add_filter( 'woocommerce_shiptastic_order_item_quantity_left_for_shipping', array( __CLASS__, 'maybe_remove_children' ), 10, 2 ); + add_filter( 'woocommerce_shiptastic_shipment_order_selectable_items_for_shipment', array( __CLASS__, 'filter_bundle_children' ), 10, 3 ); + add_action( 'woocommerce_shiptastic_shipment_added_item', array( __CLASS__, 'on_added_shipment_item' ), 10, 2 ); + add_filter( 'woocommerce_shiptastic_shipment_order_item_quantity_left_for_shipping', array( __CLASS__, 'maybe_remove_children' ), 10, 2 ); + } + + /** + * @param ShipmentItem $item + * @param Shipment $shipment + * + * @return void + */ + public static function on_added_shipment_item( $item, $shipment ) { + if ( $order_item = $item->get_order_item() ) { + if ( $shipment_order = $shipment->get_order_shipment() ) { + $order = $shipment_order->get_order(); + + if ( self::order_item_is_assembled_bundle( $order_item, $shipment_order ) ) { + $available = $shipment_order->get_available_items_for_shipment( + array( + 'shipment_id' => $shipment->get_id(), + 'disable_duplicates' => true, + ) + ); + + $children_to_add = array(); + + foreach ( $available as $item_id => $item_data ) { + if ( ! $child_order_item = $order->get_item( $item_id ) ) { + continue; + } + + if ( wc_pb_is_bundled_order_item( $child_order_item ) ) { + $container_id = wc_pb_get_bundled_order_item_container( $child_order_item, $order, true ); + + if ( $container_id === $order_item->get_id() ) { + $children_to_add[ $item_id ] = $item_data['max_quantity']; + + $props = array( + 'quantity' => $item_data['max_quantity'], + 'parent' => $item, + ); + + if ( $child_item = wc_stc_create_shipment_item( $shipment, $child_order_item, $props ) ) { + $shipment->add_item( $child_item ); + } + } + } + } + } + } + } + } + + /** + * @param $order_item + * @param $order + * + * @return void + */ + protected static function order_item_is_assembled_bundle( $order_item, $shipment_order ) { + $is_assembled = false; + + if ( wc_pb_is_bundle_container_order_item( $order_item ) ) { + if ( $product = $shipment_order->get_order_item_product( $order_item ) ) { + if ( ! $product->is_virtual() && apply_filters( 'woocommerce_shiptastic_force_bundle_item_container', true, $order_item, $shipment_order ) ) { + $is_assembled = true; + } + } + } + + return $is_assembled; } /** @@ -47,41 +117,30 @@ public static function maybe_remove_children( $quantity_left, $order_item ) { } /** - * Add parent bundle id to the child bundles. - * - * @param Shipment $shipment + * @param \WC_Order_Item[] $items + * @param array $args + * @param Order $shipment_order * - * @return void + * @return \WC_Order_Item[] */ - public static function apply_bundle_hierarchy( $shipment ) { - $map = array(); - $parents = array(); - - foreach ( $shipment->get_items() as $item ) { - if ( $order_item = $item->get_order_item() ) { - $map[ $item->get_order_item_id() ] = $item->get_id(); + public static function filter_bundle_children( $items, $args, $shipment_order ) { + $order = $shipment_order->get_order(); - if ( wc_pb_is_bundled_order_item( $order_item ) ) { - $container_id = wc_pb_get_bundled_order_item_container( $order_item, false, true ); + foreach ( $items as $order_item_id => $item ) { + if ( ! $order_item = $order->get_item( $order_item_id ) ) { + continue; + } - if ( ! isset( $parents[ $container_id ] ) ) { - $parents[ $container_id ] = array(); + if ( wc_pb_is_bundled_order_item( $order_item ) ) { + if ( $container = wc_pb_get_bundled_order_item_container( $order_item, $order, false ) ) { + if ( self::order_item_is_assembled_bundle( $container, $shipment_order ) ) { + unset( $items[ $order_item_id ] ); } - - $parents[ $container_id ][] = $item; } } } - foreach ( $parents as $order_item_id => $shipment_items ) { - if ( array_key_exists( $order_item_id, $map ) ) { - $parent_id = $map[ $order_item_id ]; - - foreach ( $shipment_items as $shipment_item ) { - $shipment_item->set_item_parent_id( $parent_id ); - } - } - } + return $items; } /** diff --git a/src/Compatibility/ShipmentTracking.php b/src/Compatibility/ShipmentTracking.php new file mode 100644 index 0000000..cc35fc7 --- /dev/null +++ b/src/Compatibility/ShipmentTracking.php @@ -0,0 +1,98 @@ + '', + 'custom_tracking_provider' => '', + 'tracking_provider' => '', + ) + ); + + if ( ! empty( $tracking_item['tracking_number'] ) ) { + if ( $shipment_order = wc_stc_get_shipment_order( $order_id ) ) { + if ( $shipment = $shipment_order->get_last_shipment_without_tracking() ) { + $shipment->set_tracking_id( $tracking_item['tracking_number'] ); + + $provider_title = $tracking_item['custom_tracking_provider'] ? $tracking_item['custom_tracking_provider'] : $tracking_item['tracking_provider']; + $provider = false; + + if ( ! empty( $provider_title ) ) { + $provider = Helper::instance()->get_shipping_provider_by_title( $provider_title ); + } + + $provider = apply_filters( 'woocommerce_shiptastic_shipment_tracking_item_shipping_provider', $provider, $provider_title, $tracking_item ); + + if ( $provider ) { + $shipment->set_shipping_provider( $provider->get_name() ); + } + + $shipment->update_status( 'shipped' ); + } + } + } + } + + public static function remove_tracking_from_shipment( $tracking_item, $order_id ) { + $tracking_item = wp_parse_args( + $tracking_item, + array( + 'tracking_number' => '', + ) + ); + + if ( ! empty( $tracking_item['tracking_number'] ) ) { + $shipments = wc_stc_get_shipments( + array( + 'order_id' => $order_id, + 'tracking_id' => $tracking_item['tracking_number'], + ) + ); + + if ( ! empty( $shipments ) ) { + foreach ( $shipments as $shipment ) { + $shipment->set_tracking_id( '' ); + $shipment->save(); + } + } + } + } +} diff --git a/src/DataStores/Label.php b/src/DataStores/Label.php index a9904a5..02743c4 100644 --- a/src/DataStores/Label.php +++ b/src/DataStores/Label.php @@ -421,8 +421,9 @@ protected function save_label_data( &$label ) { * @param string $meta_key Meta key to update. * @param mixed $meta_value Value to save. * - * * @return bool True if updated/deleted. + *@since 3.6.0 Added to prevent empty meta being stored unless required. + * */ protected function update_or_delete_meta( $label, $meta_key, $meta_value ) { if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { diff --git a/src/DataStores/Packaging.php b/src/DataStores/Packaging.php index 4015434..08f931d 100644 --- a/src/DataStores/Packaging.php +++ b/src/DataStores/Packaging.php @@ -372,8 +372,9 @@ protected function save_packaging_data( &$packaging ) { * @param string $meta_key Meta key to update. * @param mixed $meta_value Value to save. * - * * @return bool True if updated/deleted. + * @since 3.6.0 Added to prevent empty meta being stored unless required. + * */ protected function update_or_delete_meta( $packaging, $meta_key, $meta_value ) { if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { diff --git a/src/DataStores/Shipment.php b/src/DataStores/Shipment.php index 8ebc5db..e05e065 100644 --- a/src/DataStores/Shipment.php +++ b/src/DataStores/Shipment.php @@ -512,8 +512,9 @@ protected function save_shipment_data( &$shipment ) { * @param string $meta_key Meta key to update. * @param mixed $meta_value Value to save. * - * * @return bool True if updated/deleted. + * @since 3.6.0 Added to prevent empty meta being stored unless required. + * */ protected function update_or_delete_meta( $shipment, $meta_key, $meta_value ) { if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { diff --git a/src/DataStores/ShipmentItem.php b/src/DataStores/ShipmentItem.php index c679bab..2dd9159 100644 --- a/src/DataStores/ShipmentItem.php +++ b/src/DataStores/ShipmentItem.php @@ -238,8 +238,9 @@ protected function read_item_data( &$item ) { * @param string $meta_key Meta key to update. * @param mixed $meta_value Value to save. * - * * @return bool True if updated/deleted. + * @since 3.6.0 Added to prevent empty meta being stored unless required. + * */ protected function update_or_delete_meta( $shipment_item, $meta_key, $meta_value ) { if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { diff --git a/src/DataStores/ShippingProvider.php b/src/DataStores/ShippingProvider.php index 2958efb..95e4ac7 100644 --- a/src/DataStores/ShippingProvider.php +++ b/src/DataStores/ShippingProvider.php @@ -409,8 +409,9 @@ protected function save_provider_data( &$provider ) { * @param string $meta_key Meta key to update. * @param mixed $meta_value Value to save. * - * * @return bool True if updated/deleted. + * @since 3.6.0 Added to prevent empty meta being stored unless required. + * */ protected function update_or_delete_meta( $shipping_provider, $meta_key, $meta_value ) { if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { diff --git a/src/Interfaces/ShipmentLabel.php b/src/Interfaces/ShipmentLabel.php index 04b2b89..d95e840 100644 --- a/src/Interfaces/ShipmentLabel.php +++ b/src/Interfaces/ShipmentLabel.php @@ -7,9 +7,6 @@ exit; } -/** - * ShipmentLabel class. - */ interface ShipmentLabel { /** diff --git a/src/Labels/Query.php b/src/Labels/Query.php index f04bdf0..d5b7c05 100644 --- a/src/Labels/Query.php +++ b/src/Labels/Query.php @@ -401,14 +401,13 @@ protected function prepare_query() { /** * Used internally to generate an SQL string for searching across multiple columns * - * * @param string $search_query * @param array $cols * @param bool $wild Whether to allow wildcard searches. Default is false for Network Admin, true for single site. * Single site allows leading and trailing wildcards, Network Admin only trailing. * * @return string - *@global \wpdb $wpdb WordPress database abstraction object. + * @global \wpdb $wpdb WordPress database abstraction object. * */ protected function get_search_sql( $search_query, $cols, $wild = false ) { diff --git a/src/Order.php b/src/Order.php index 1e69b82..efe8fb3 100644 --- a/src/Order.php +++ b/src/Order.php @@ -93,6 +93,22 @@ public function is_shipped() { return apply_filters( 'woocommerce_shiptastic_shipment_order_shipping_status', ( in_array( $shipping_status, array( 'shipped', 'delivered' ), true ) || ( 'partially-delivered' === $shipping_status && ! $this->needs_shipping( array( 'sent_only' => true ) ) ) ), $this ); } + /** + * @return Shipment|false + */ + public function get_last_shipment_without_tracking() { + $last_shipment = false; + + foreach ( array_reverse( $this->get_simple_shipments() ) as $shipment ) { + if ( ! $shipment->get_tracking_id() && ! $shipment->is_shipped() ) { + $last_shipment = $shipment; + break; + } + } + + return apply_filters( 'woocommerce_shiptastic_shipment_order_last_shipment_without_tracking', $last_shipment, $this ); + } + /** * @return Shipment|false */ @@ -836,8 +852,13 @@ public function get_items_to_pack_left_for_shipping( $legacy_group_by_product_gr return apply_filters( 'woocommerce_shiptastic_shipment_order_items_to_pack_left_for_shipping', $items_to_be_packed ); } + public function get_selectable_items_for_shipment( $args = array() ) { + return apply_filters( 'woocommerce_shiptastic_shipment_order_selectable_items_for_shipment', $this->get_available_items_for_shipment( $args ), $args, $this ); + } + /** - * @param bool|Shipment $shipment + * @param array $args + * * @return array */ public function get_available_items_for_shipment( $args = array() ) { @@ -917,6 +938,10 @@ public function get_non_returnable_items() { return $items; } + public function get_selectable_items_for_return( $args = array() ) { + return apply_filters( 'woocommerce_shiptastic_shipment_order_selectable_items_for_return', $this->get_available_items_for_return( $args ), $args, $this ); + } + /** * @return array */ @@ -1065,7 +1090,6 @@ public function get_shippable_items() { * * @package Vendidero/Shiptastic */ - do_action( 'woocommerce_shiptastic_order_after_get_items', $this->get_order() ); return apply_filters( 'woocommerce_shiptastic_shipment_order_shippable_items', $items, $this->get_order(), $this ); @@ -1195,15 +1219,15 @@ public function get_pickup_delivery_args() { continue; } if ( $product = $item->get_product() ) { - $s_product = apply_filters( 'woocommerce_gzd_shipments_order_item_product', wc_gzd_shipments_get_product( $product ), $item ); + $s_product = apply_filters( 'woocommerce_shiptastic_shipment_order_item_product', wc_shiptastic_get_product( $product ), $item ); if ( $s_product ) { $width = empty( $s_product->get_shipping_width() ) ? 0 : (float) wc_format_decimal( $s_product->get_shipping_width() ); $length = empty( $s_product->get_shipping_length() ) ? 0 : (float) wc_format_decimal( $s_product->get_shipping_length() ); $height = empty( $s_product->get_shipping_height() ) ? 0 : (float) wc_format_decimal( $s_product->get_shipping_height() ); $dimensions = array( - 'width' => (float) wc_get_dimension( $width, wc_gzd_get_packaging_dimension_unit() ), - 'length' => (float) wc_get_dimension( $length, wc_gzd_get_packaging_dimension_unit() ), - 'height' => (float) wc_get_dimension( $height, wc_gzd_get_packaging_dimension_unit() ), + 'width' => (float) wc_get_dimension( $width, wc_stc_get_packaging_dimension_unit() ), + 'length' => (float) wc_get_dimension( $length, wc_stc_get_packaging_dimension_unit() ), + 'height' => (float) wc_get_dimension( $height, wc_stc_get_packaging_dimension_unit() ), ); if ( $dimensions['width'] > $args['max_dimensions']['width'] ) { $args['max_dimensions']['width'] = $dimensions['width']; @@ -1215,7 +1239,7 @@ public function get_pickup_delivery_args() { $args['max_dimensions']['height'] = $dimensions['height']; } $weight = empty( $product->get_weight() ) ? 0 : (float) wc_format_decimal( $product->get_weight() ); - $weight = (float) wc_get_weight( $weight, wc_gzd_get_packaging_weight_unit() ); + $weight = (float) wc_get_weight( $weight, wc_stc_get_packaging_weight_unit() ); if ( $weight > $args['max_weight'] ) { $args['max_weight'] = $weight; } diff --git a/src/Package.php b/src/Package.php index 981dd64..d78b06e 100644 --- a/src/Package.php +++ b/src/Package.php @@ -61,6 +61,7 @@ protected static function init_hooks() { add_action( 'init', array( __CLASS__, 'register_shortcodes' ) ); add_action( 'init', array( __CLASS__, 'check_version' ), 10 ); add_action( 'init', array( __CLASS__, 'load_plugin_textdomain' ) ); + add_action( 'init', array( __CLASS__, 'load_fallback_compatibility' ) ); add_filter( 'woocommerce_shipping_method_add_rate_args', array( __CLASS__, 'manipulate_shipping_rates' ), 1000, 2 ); } @@ -116,6 +117,37 @@ public static function support_german_language_variants( $locale, $domain ) { return $locale; } + /** + * Some label-related plugins, e.g. Swiss Post may have a built-in compatibility + * for the WooCommerce Shipment Tracking plugin. Let's mimic/add those basic API functions + * to make sure tracking-related info gets updates within shipments too. + * + * @return void + */ + public static function load_fallback_compatibility() { + if ( ! function_exists( 'wc_st_add_tracking_number' ) ) { + function wc_st_add_tracking_number( $order_id, $tracking_number, $provider, $date_shipped = null, $custom_url = false ) { + $tracking_item = array( + 'tracking_provider' => $provider, + 'custom_tracking_link' => $custom_url, + 'tracking_number' => $tracking_number, + ); + + Compatibility\ShipmentTracking::transfer_tracking_to_shipment( $tracking_item, $order_id ); + } + } + + if ( ! function_exists( 'wc_st_delete_tracking_number' ) ) { + function wc_st_delete_tracking_number( $order_id, $tracking_number, $provider = false ) { + $tracking_item = array( + 'tracking_number' => $tracking_number, + ); + + Compatibility\ShipmentTracking::remove_tracking_from_shipment( $tracking_item, $order_id ); + } + } + } + /** * Loads the dependency injection container for woocommerce blocks. * @@ -148,7 +180,8 @@ public static function load_compatibilities() { $compatibilities = apply_filters( 'woocommerce_shiptastic_compatibilities', array( - 'bundles' => '\Vendidero\Shiptastic\Compatibility\Bundles', + 'bundles' => '\Vendidero\Shiptastic\Compatibility\Bundles', + 'shipment-tracking' => '\Vendidero\Shiptastic\Compatibility\ShipmentTracking', ) ); @@ -287,6 +320,17 @@ public static function is_hpos_enabled() { return \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled(); } + public static function get_current_payment_gateway() { + $current_gateway = WC()->session ? WC()->session->get( 'chosen_payment_method' ) : ''; + $has_block_checkout = has_block( 'woocommerce/checkout' ) || has_block( 'woocommerce/cart' ) || WC()->is_rest_api_request(); + + if ( $has_block_checkout ) { + $current_gateway = WC()->session ? WC()->session->get( 'wc_shiptastic_blocks_chosen_payment_method', '' ) : ''; + } + + return $current_gateway; + } + public static function inject_endpoints() { if ( function_exists( 'WC' ) && WC()->query ) { foreach ( self::get_endpoints() as $endpoint ) { @@ -354,18 +398,6 @@ public static function base_country_belongs_to_eu_customs_area() { return self::country_belongs_to_eu_customs_area( self::get_base_country(), self::get_base_postcode() ); } - public static function get_shipping_zone( $country, $args = array() ) { - $zone = 'int'; - - if ( self::is_shipping_domestic( $country, $args ) ) { - $zone = 'dom'; - } elseif ( self::is_shipping_inner_eu_country( $country, $args ) ) { - $zone = 'eu'; - } - - return $zone; - } - public static function country_belongs_to_eu_customs_area( $country, $postcode = '' ) { $country = wc_strtoupper( $country ); $eu_countries = WC()->countries->get_european_union_countries(); @@ -425,6 +457,18 @@ public static function base_country_supports_export_reference_number() { return apply_filters( 'woocommerce_shiptastic_base_country_supports_export_reference_number', self::country_belongs_to_eu_customs_area( $base_country ) ); } + public static function get_shipping_zone( $country, $args = array() ) { + $zone = 'int'; + + if ( self::is_shipping_domestic( $country, $args ) ) { + $zone = 'dom'; + } elseif ( self::is_shipping_inner_eu_country( $country, $args ) ) { + $zone = 'eu'; + } + + return $zone; + } + public static function is_shipping_international( $country, $args = array() ) { $args = self::parse_location_data( $args ); /** diff --git a/src/Packing/PackagingList.php b/src/Packing/PackagingList.php index 09a7578..2b34099 100644 --- a/src/Packing/PackagingList.php +++ b/src/Packing/PackagingList.php @@ -2,13 +2,55 @@ namespace Vendidero\Shiptastic\Packing; +use DVDoug\BoxPacker\Box; use DVDoug\BoxPacker\BoxSorter; +use DVDoug\BoxPacker\DefaultBoxSorter; +use ArrayIterator; +use Traversable; class PackagingList extends \DVDoug\BoxPacker\BoxList { + /** + * @var Box[] + */ + private $list = array(); + + private $is_sorted = false; + + private $sorter; + public function __construct( $sorter = null ) { - $sorter = new PackagingSorter(); + $this->sorter = new PackagingSorter(); parent::__construct( $sorter ); } + + /** + * Do a bulk create. + * + * @param Box[] $boxes + */ + public static function fromArray( array $boxes, bool $pre_sorted = false ): self { + $list = new self(); + $list->list = $boxes; + $list->is_sorted = $pre_sorted; + + return $list; + } + + /** + * @return Traversable + */ + public function getIterator(): Traversable { + if ( ! $this->is_sorted ) { + usort( $this->list, array( $this->sorter, 'compare' ) ); + $this->is_sorted = true; + } + + return new ArrayIterator( $this->list ); + } + + public function insert( Box $item ): void { + $this->list[] = $item; + } } diff --git a/src/PickupDelivery.php b/src/PickupDelivery.php index 55b042e..3f7b1e5 100644 --- a/src/PickupDelivery.php +++ b/src/PickupDelivery.php @@ -715,6 +715,17 @@ public static function register_assets() { wp_enqueue_script( 'wc-shiptastic-pickup-locations' ); } + public static function get_excluded_gateways() { + /** + * Filter to disable pickup delivery for certain gateways. + * + * @param array $gateways Array of gateway IDs to exclude. + */ + $codes = apply_filters( 'woocommerce_shiptastic_pickup_delivery_excluded_gateways', array( 'cod', 'amazon_payments_advanced' ) ); + + return $codes; + } + public static function get_pickup_delivery_cart_args() { if ( ! wc()->cart ) { return array( @@ -804,7 +815,7 @@ public static function get_pickup_delivery_cart_args() { return array( 'max_weight' => $max_weight, 'max_dimensions' => $max_dimensions, - 'payment_gateway' => WC()->session ? WC()->session->get( 'chosen_payment_method' ) : '', + 'payment_gateway' => Package::get_current_payment_gateway(), 'shipping_method' => $shipping_method, ); } diff --git a/src/Rest/ShipmentsController.php b/src/Rest/ShipmentsController.php index 33d50a3..2ebb0e3 100644 --- a/src/Rest/ShipmentsController.php +++ b/src/Rest/ShipmentsController.php @@ -352,7 +352,9 @@ protected function prepare_object_for_database( $request, $creating = false ) { throw new \WC_REST_Exception( 'woocommerce_stc_rest_invalid_id', esc_html_x( 'This order does need a return.', 'shipments', 'shiptastic-for-woocommerce' ) ); } } elseif ( ! $order_shipment->needs_shipping() ) { - throw new \WC_REST_Exception( 'woocommerce_stc_rest_invalid_id', esc_html_x( 'This order does need shipping.', 'shipments', 'shiptastic-for-woocommerce' ) ); + throw new \WC_REST_Exception( 'woocommerce_stc_rest_invalid_id', esc_html_x( 'This order does need shipping.', 'shipments', 'shiptastic-for-woocommerce' ) ); + } elseif ( ! $order_shipment->needs_shipping() ) { + throw new \WC_REST_Exception( 'woocommerce_stc_rest_invalid_id', esc_html_x( 'This order does need shipping.', 'shipments', 'shiptastic-for-woocommerce' ) ); } $shipment->sync(); diff --git a/src/ReturnShipment.php b/src/ReturnShipment.php index 562e751..45909c9 100644 --- a/src/ReturnShipment.php +++ b/src/ReturnShipment.php @@ -349,7 +349,7 @@ public function sync_items( $args = array() ) { ) ); - $available_items = $order_shipment->get_available_items_for_return( + $available_items = $order_shipment->get_selectable_items_for_return( array( 'shipment_id' => $this->get_id(), 'exclude_current_shipment' => true, @@ -468,7 +468,6 @@ public function sync_items( $args = array() ) { * @return bool */ public function needs_items( $available_items = false ) { - if ( ! $available_items && ( $order_shipment = $this->get_order_shipment() ) ) { $available_items = array_keys( $order_shipment->get_available_items_for_return() ); } diff --git a/src/Shipment.php b/src/Shipment.php index f50012e..c5e30b1 100644 --- a/src/Shipment.php +++ b/src/Shipment.php @@ -2283,6 +2283,8 @@ public function add_item( $item ) { $this->reset_content_data(); $this->calculate_totals(); $this->sync_packaging(); + + do_action( "{$this->get_general_hook_prefix()}added_item", $item, $this ); } /** diff --git a/src/ShipmentItem.php b/src/ShipmentItem.php index 2386602..3f56401 100644 --- a/src/ShipmentItem.php +++ b/src/ShipmentItem.php @@ -449,8 +449,13 @@ public function sync( $args = array() ) { 'manufacture_country' => $product ? $product->get_manufacture_country() : '', 'attributes' => $attributes, 'item_parent_id' => $this->get_item_parent_id() ? $this->get_item_parent_id() : 0, + 'parent' => null, ) ); + + if ( ! is_null( $args['parent'] ) && is_a( $args['parent'], 'Vendidero\Shiptastic\ShipmentItem' ) ) { + $this->set_parent( $args['parent'] ); + } } $this->set_props( $args ); @@ -577,6 +582,17 @@ public function set_item_parent_id( $value ) { $this->set_prop( 'item_parent_id', absint( $value ) ); } + /** + * @param ShipmentItem $item + * + * @return void + */ + public function set_parent( $item ) { + $this->parent = $item; + + $this->set_item_parent_id( $item->get_id() ); + } + /** * @param ShipmentItem $item * @@ -602,11 +618,11 @@ public function remove_child( $key ) { * @return ShipmentItem|ShipmentReturnItem|null */ public function get_parent() { - if ( ! $this->get_item_parent_id() ) { - return null; - } - if ( is_null( $this->parent ) ) { + if ( ! $this->get_item_parent_id() ) { + return null; + } + if ( $this->get_shipment() ) { if ( $item = $this->get_shipment()->get_item( $this->get_item_parent_id() ) ) { $this->parent = $item; @@ -760,4 +776,24 @@ public function set_attributes( $attributes ) { public function is_readonly() { return apply_filters( "{$this->get_general_hook_prefix()}is_readonly", $this->get_item_parent_id() > 0 ? true : false, $this ); } + + public function save() { + if ( $parent = $this->get_parent() ) { + if ( $this->get_item_parent_id() !== $parent->get_id() ) { + $this->set_item_parent_id( $parent->get_id() ); + } + } + + return parent::save(); + } + + public function delete( $force_delete = false ) { + $has_deleted = parent::delete( $force_delete ); + + if ( true === $has_deleted && $this->has_children() ) { + foreach ( $this->get_children() as $child ) { + $child->delete( $force_delete ); + } + } + } } diff --git a/src/ShipmentQuery.php b/src/ShipmentQuery.php index d66c62b..b7d9f2e 100644 --- a/src/ShipmentQuery.php +++ b/src/ShipmentQuery.php @@ -521,14 +521,13 @@ protected function prepare_query() { /** * Used internally to generate an SQL string for searching across multiple columns * - * * @param string $search_query * @param array $cols * @param bool $wild Whether to allow wildcard searches. Default is false for Network Admin, true for single site. * Single site allows leading and trailing wildcards, Network Admin only trailing. * * @return string - *@global wpdb $wpdb WordPress database abstraction object. + * @global \wpdb $wpdb WordPress database abstraction object. * */ protected function get_search_sql( $search_query, $cols, $wild = false ) { diff --git a/src/ShippingMethod/MethodHelper.php b/src/ShippingMethod/MethodHelper.php index 7c129d6..71f6224 100644 --- a/src/ShippingMethod/MethodHelper.php +++ b/src/ShippingMethod/MethodHelper.php @@ -2,6 +2,7 @@ namespace Vendidero\Shiptastic\ShippingMethod; +use Vendidero\Shiptastic\Compatibility\Bundles; use Vendidero\Shiptastic\Package; use Vendidero\Shiptastic\Packing\CartItem; use Vendidero\Shiptastic\Packing\ItemList; diff --git a/src/ShippingProvider/Auto.php b/src/ShippingProvider/Auto.php index 95a5766..59298fc 100644 --- a/src/ShippingProvider/Auto.php +++ b/src/ShippingProvider/Auto.php @@ -705,9 +705,9 @@ protected function parse_pickup_location_query_args( $query_args ) { public function get_pickup_locations( $address, $query_args = array() ) { $query_args = $this->parse_pickup_location_query_args( $query_args ); + $address = $this->parse_pickup_location_address_args( $address ); $cache_key = $this->get_pickup_locations_cache_key( $address, $query_args ); $pickup_locations = get_transient( $cache_key ); - $address = $this->parse_pickup_location_address_args( $address ); if ( false === $pickup_locations && ( ! empty( $address['postcode'] ) || ! empty( $address['city'] ) ) ) { $pickup_locations = $this->fetch_pickup_locations( $address, $query_args ); diff --git a/src/ShippingProvider/Helper.php b/src/ShippingProvider/Helper.php index a5120dd..f92cae0 100644 --- a/src/ShippingProvider/Helper.php +++ b/src/ShippingProvider/Helper.php @@ -279,6 +279,39 @@ public function get_available_shipping_providers() { return $this->available_shipping_providers; } + /** + * @param string|ShippingProvider $title + * + * @return false|Simple|Auto|ShippingProvider + */ + public function get_shipping_provider_by_title( $title ) { + if ( is_a( $title, 'Vendidero\Shiptastic\Interfaces\ShippingProvider' ) ) { + $title = $title->get_title(); + } + + $title = sanitize_title( $title ); + $providers = $this->get_shipping_providers(); + $the_provider = false; + $alternate_match = false; + + foreach ( $providers as $provider ) { + $provider_title = sanitize_title( $provider->get_title() ); + + if ( $provider_title === $title ) { + $the_provider = $provider; + break; + } elseif ( strstr( $provider_title, $title ) ) { + $alternate_match = $provider; + } + } + + if ( ! $the_provider && $alternate_match ) { + $the_provider = $alternate_match; + } + + return $the_provider; + } + /** * @param string|ShippingProvider $name * diff --git a/src/ShippingProvider/Placeholder.php b/src/ShippingProvider/Placeholder.php index d78abb5..ace24e7 100644 --- a/src/ShippingProvider/Placeholder.php +++ b/src/ShippingProvider/Placeholder.php @@ -25,7 +25,7 @@ public function __construct( $data = 0, $args = array() ) { ); if ( empty( $this->placeholder_args['name'] ) ) { - $this->placeholder_args['name'] = sanitize_title( $this->placeholder_args['title'] ); + $this->placeholder_args['name'] = str_replace( '-', '_', sanitize_title( $this->placeholder_args['title'] ) ); } parent::__construct( $data ); @@ -52,7 +52,7 @@ public function get_extension_name() { } public function get_description( $context = 'view' ) { - return $this->placeholder_args['description']; + return empty( $this->placeholder_args['description'] ) ? sprintf( _x( 'Conveniently create %1$s labels to your shipments.', 'shipments', 'shiptastic-for-woocommerce' ), $this->get_title() ) : $this->placeholder_args['description']; } public function get_title( $context = 'view' ) { diff --git a/templates/myaccount/add-return-shipment.php b/templates/myaccount/add-return-shipment.php index 64552fd..3e6e2a5 100644 --- a/templates/myaccount/add-return-shipment.php +++ b/templates/myaccount/add-return-shipment.php @@ -47,7 +47,7 @@ */ do_action( 'woocommerce_shiptastic_add_return_shipment_details_before_shipment_table_items', $order ); - foreach ( $shipment_order->get_available_items_for_return() as $order_item_id => $item_data ) { + foreach ( $shipment_order->get_selectable_items_for_return() as $order_item_id => $item_data ) { wc_get_template( 'shipment/add-return-shipment-item.php', array( diff --git a/tests/unit-tests/shipment.php b/tests/unit-tests/shipment.php index 80e9e87..f39bce1 100644 --- a/tests/unit-tests/shipment.php +++ b/tests/unit-tests/shipment.php @@ -75,4 +75,45 @@ function test_sync_shipment() { $item = array_values( $shipment->get_items() )[0]; $this->assertEquals( 4, $item->get_quantity() ); } + + function test_child_parent_hierarchy() { + $shipment = new \Vendidero\Shiptastic\SimpleShipment(); + $parent_item = new \Vendidero\Shiptastic\ShipmentItem(); + $parent_item->set_quantity( 1 ); + $parent_item->set_name( 'parent' ); + $shipment->add_item( $parent_item ); + + $child_item = new \Vendidero\Shiptastic\ShipmentItem(); + $child_item->set_quantity( 3 ); + $child_item->set_name( 'child' ); + $child_item->set_parent( $parent_item ); + $shipment->add_item( $child_item ); + + $child_item_2 = new \Vendidero\Shiptastic\ShipmentItem(); + $child_item_2->set_quantity( 1 ); + $child_item_2->set_name( 'child_2' ); + $child_item_2->set_parent( $parent_item ); + $shipment->add_item( $child_item_2 ); + + $id = $shipment->save(); + $parent_id = 0; + + foreach( $shipment->get_items() as $item ) { + if ( 'parent' === $item->get_name() ) { + $this->assertEquals( 2, count( $item->get_children() ) ); + $parent_id = $item->get_id(); + } elseif ( 'child' === $item->get_name() ) { + $this->assertEquals( $parent_id, $item->get_item_parent_id() ); + } elseif ( 'child_2' === $item->get_name() ) { + $this->assertEquals( $parent_id, $item->get_item_parent_id() ); + } else { + $this->assertEquals( false, true ); + } + } + + $shipment->remove_item( $parent_id ); + $shipment->save(); + + $this->assertEquals( 0, count( $shipment->get_items() ) ); + } } \ No newline at end of file diff --git a/uninstall.php b/uninstall.php index 7f79152..05a4f9b 100644 --- a/uninstall.php +++ b/uninstall.php @@ -23,7 +23,6 @@ '_pickup_location_code', ); - // Delete gzd meta data $wpdb->query( "DELETE meta FROM {$wpdb->postmeta} meta WHERE meta.meta_key IN ('" . join( "','", $meta_keys ) . "');" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared // Remove Tables