diff --git a/package.json b/package.json
index 735824f2..c6b0633a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "woocommerce-germanized-shipments",
"title": "Shipments for WooCommerce",
- "version": "3.0.5",
+ "version": "3.1.1",
"homepage": "https://vendidero.de",
"repository": {
"type": "git",
diff --git a/src/Automation.php b/src/Automation.php
index 77baf76b..3a171373 100644
--- a/src/Automation.php
+++ b/src/Automation.php
@@ -220,12 +220,11 @@ public static function create_shipments( $order ) {
if ( $order_shipment = wc_gzd_get_shipment_order( $order ) ) {
/**
- * Sync existing shipments and items before creating new shipments
+ * Sync existing shipments before creating new shipments
*/
foreach ( $order_shipment->get_simple_shipments() as $shipment ) {
if ( $shipment->is_editable() ) {
$shipment->sync();
- $shipment->sync_items();
$shipment->save();
}
}
diff --git a/src/Package.php b/src/Package.php
index c982f3e2..ffcd3c7c 100644
--- a/src/Package.php
+++ b/src/Package.php
@@ -18,7 +18,7 @@ class Package {
*
* @var string
*/
- const VERSION = '3.0.5';
+ const VERSION = '3.1.1';
public static $upload_dir_suffix = '';
@@ -424,11 +424,15 @@ public static function register_endpoints( $query_vars ) {
public static function install() {
self::init();
+
+ if ( ! self::has_dependencies() ) {
+ return;
+ }
+
Install::install();
}
public static function install_integration() {
- self::init();
self::install();
}
@@ -478,6 +482,14 @@ protected static function generate_key() {
return md5( serialize( $key ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
}
+ public static function is_shipping_debug_mode() {
+ return apply_filters( 'woocommerce_gzd_shipments_is_shipping_debug_mode', 'yes' === get_option( 'woocommerce_shipping_debug_mode', 'no' ) );
+ }
+
+ public static function is_constant_defined( $constant ) {
+ return class_exists( 'Automattic\Jetpack\Constants' ) ? \Automattic\Jetpack\Constants::is_defined( $constant ) : defined( $constant );
+ }
+
public static function log( $message, $type = 'info', $source = '' ) {
$enable_logging = defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false;
diff --git a/src/Packaging.php b/src/Packaging.php
index 10227452..8c506c1d 100644
--- a/src/Packaging.php
+++ b/src/Packaging.php
@@ -279,6 +279,12 @@ public function has_inner_dimensions() {
return ! empty( $this->get_inner_width( 'edit' ) ) || ! empty( $this->get_inner_length( 'edit' ) ) || ! empty( $this->get_inner_height( 'edit' ) );
}
+ public function has_shipping_class_restrictions() {
+ $classes = $this->get_available_shipping_classes( 'edit' );
+
+ return ! empty( $classes ) ? true : false;
+ }
+
/**
* Returns the available shipping provider names.
*
@@ -315,7 +321,9 @@ public function supports_shipping_class( $shipping_class ) {
$classes = $this->get_available_shipping_classes( 'edit' );
$supports = false;
- if ( empty( $classes ) || in_array( $shipping_class, $classes, true ) ) {
+ if ( empty( $shipping_class ) && empty( $classes ) ) {
+ $supports = true;
+ } elseif ( empty( $classes ) || in_array( $shipping_class, $classes, true ) ) {
$supports = true;
}
diff --git a/src/Packing/CartItem.php b/src/Packing/CartItem.php
index 830df78e..39d44591 100644
--- a/src/Packing/CartItem.php
+++ b/src/Packing/CartItem.php
@@ -48,8 +48,7 @@ public function __construct( $item, $incl_taxes = false ) {
$line_subtotal += (int) wc_add_number_precision( $this->item['line_subtotal_tax'] );
}
- $this->weight = (int) wc_get_weight( $weight, 'g' );
-
+ $this->weight = (int) wc_get_weight( $weight, 'g' );
$this->total = $quantity > 0 ? NumberUtil::round( $line_total / $quantity ) : 0;
$this->subtotal = $quantity > 0 ? NumberUtil::round( $line_subtotal / $quantity ) : 0;
}
diff --git a/src/Packing/Item.php b/src/Packing/Item.php
index 3a395ef0..d1d65ffd 100644
--- a/src/Packing/Item.php
+++ b/src/Packing/Item.php
@@ -60,7 +60,7 @@ public function canBePacked( $box, $already_packed_items, int $proposed_x, int $
if ( $product = $this->get_product() ) {
$shipping_class = $product->get_shipping_class_id();
- if ( ! empty( $shipping_class ) ) {
+ if ( $box->get_packaging()->has_shipping_class_restrictions() ) {
if ( ! $box->get_packaging()->supports_shipping_class( $shipping_class ) ) {
$fits = false;
}
diff --git a/src/Shipment.php b/src/Shipment.php
index 320c0772..dabaed33 100644
--- a/src/Shipment.php
+++ b/src/Shipment.php
@@ -273,13 +273,17 @@ public function get_shipping_zone() {
}
public function is_shipping_domestic() {
- return Package::is_shipping_domestic(
- $this->get_country(),
- array(
- 'sender_country' => $this->get_sender_country(),
- 'sender_postcode' => $this->get_sender_postcode(),
- 'postcode' => $this->get_postcode(),
- )
+ return apply_filters(
+ "{$this->get_general_hook_prefix()}is_shipping_domestic",
+ Package::is_shipping_domestic(
+ $this->get_country(),
+ array(
+ 'sender_country' => $this->get_sender_country(),
+ 'sender_postcode' => $this->get_sender_postcode(),
+ 'postcode' => $this->get_postcode(),
+ )
+ ),
+ $this
);
}
@@ -290,13 +294,17 @@ public function is_shipping_domestic() {
* @return bool
*/
public function is_shipping_inner_eu() {
- if ( Package::is_shipping_inner_eu_country(
- $this->get_country(),
- array(
- 'sender_country' => $this->get_sender_country(),
- 'sender_postcode' => $this->get_sender_postcode(),
- 'postcode' => $this->get_postcode(),
- )
+ if ( apply_filters(
+ "{$this->get_general_hook_prefix()}is_shipping_inner_eu",
+ Package::is_shipping_inner_eu_country(
+ $this->get_country(),
+ array(
+ 'sender_country' => $this->get_sender_country(),
+ 'sender_postcode' => $this->get_sender_postcode(),
+ 'postcode' => $this->get_postcode(),
+ )
+ ),
+ $this
) ) {
return true;
}
diff --git a/src/ShippingMethod/ShippingMethod.php b/src/ShippingMethod/ShippingMethod.php
index 9a195f74..c8afde27 100644
--- a/src/ShippingMethod/ShippingMethod.php
+++ b/src/ShippingMethod/ShippingMethod.php
@@ -538,10 +538,13 @@ public function get_available_packaging_boxes( $package_data = array() ) {
public function calculate_shipping( $package = array() ) {
$applied_rules = array();
+ $debug_notices = array();
+ $is_debug_mode = Package::is_shipping_debug_mode();
if ( isset( $package['items_to_pack'], $package['package_data'] ) ) {
$cart_data = (array) $package['package_data'];
- $boxes = \DVDoug\BoxPacker\BoxList::fromArray( $this->get_available_packaging_boxes( $cart_data ) );
+ $available_boxes = $this->get_available_packaging_boxes( $cart_data );
+ $boxes = \DVDoug\BoxPacker\BoxList::fromArray( $available_boxes );
$cost_calculation_mode = $this->get_multiple_shipments_cost_calculation_mode();
$multiple_rules_calculation_mode = $this->get_multiple_rules_cost_calculation_mode();
@@ -551,83 +554,56 @@ public function calculate_shipping( $package = array() ) {
$total_packed_item_map = array();
$total_packed_items = 0;
$packed_boxes = Helper::pack( $package['items_to_pack'], $boxes, 'cart' );
+ $unpacked_items = Helper::get_last_unpacked_items();
+
+ if ( 0 === count( $unpacked_items ) ) {
+ foreach ( $packed_boxes as $box ) {
+ $packaging = $box->getBox();
+ $items = $box->getItems();
+ $total_weight = wc_get_weight( $items->getWeight(), strtolower( get_option( 'woocommerce_weight_unit' ) ), 'g' );
+ $volume = wc_get_dimension( $items->getVolume(), strtolower( get_option( 'woocommerce_dimension_unit' ) ), 'mm' );
+ $item_count = $items->count();
+ $total = 0;
+ $subtotal = 0;
+ $products = array();
+ $shipping_classes = array();
- foreach ( $packed_boxes as $box ) {
- $packaging = $box->getBox();
- $items = $box->getItems();
- $total_weight = wc_get_weight( $items->getWeight(), strtolower( get_option( 'woocommerce_weight_unit' ) ), 'g' );
- $volume = wc_get_dimension( $items->getVolume(), strtolower( get_option( 'woocommerce_dimension_unit' ) ), 'mm' );
- $item_count = $items->count();
- $total = 0;
- $subtotal = 0;
- $products = array();
- $shipping_classes = array();
-
- foreach ( $items as $item ) {
- $cart_item = $item->getItem();
- $total += $cart_item->get_total();
- $subtotal += $cart_item->get_subtotal();
- $product = $cart_item->get_product();
-
- if ( $product && ! array_key_exists( $product->get_id(), $products ) ) {
- $products[ $product->get_id() ] = $product;
-
- if ( ! empty( $product->get_shipping_class_id() ) ) {
- $shipping_classes[] = $product->get_shipping_class_id();
- }
- }
- }
-
- $total = wc_remove_number_precision( $total );
- $subtotal = wc_remove_number_precision( $subtotal );
- $shipping_classes = array_unique( $shipping_classes );
- $package_data = array_merge(
- $cart_data,
- array(
- 'package_total' => $total,
- 'package_subtotal' => $subtotal,
- 'package_weight' => $total_weight,
- 'package_volume' => $volume,
- 'package_item_count' => $item_count,
- 'packaging_id' => $packaging->get_id(),
- 'package_products' => $products,
- 'package_shipping_classes' => $shipping_classes,
- )
- );
-
- $package_applied_rules = array();
- $applicable_rule_costs = array();
+ foreach ( $items as $item ) {
+ $cart_item = $item->getItem();
+ $total += $cart_item->get_total();
+ $subtotal += $cart_item->get_subtotal();
+ $product = $cart_item->get_product();
- foreach ( array_reverse( $this->get_shipping_rules_by_packaging( $packaging->get_id() ) ) as $rule ) {
- $rule = $this->parse_rule( $rule );
- $rule_applies = $this->rule_applies( $rule, $package_data );
+ if ( $product && ! array_key_exists( $product->get_id(), $products ) ) {
+ $products[ $product->get_id() ] = $product;
- if ( $rule_applies ) {
- $applicable_rule_costs[] = $rule['costs'];
- $package_applied_rules[] = $rule['rule_id'];
+ if ( ! empty( $product->get_shipping_class_id() ) ) {
+ $shipping_classes[] = $product->get_shipping_class_id();
+ }
+ }
}
- /**
- * In case a free shipping option is detected, stop + reset.
- */
- if ( $rule_applies && 0.0 === $rule['costs'] ) {
- $applicable_rule_costs = array(
- $rule['costs'],
- );
-
- $package_applied_rules = array(
- $rule['rule_id'],
- );
+ $total = wc_remove_number_precision( $total );
+ $subtotal = wc_remove_number_precision( $subtotal );
+ $shipping_classes = array_unique( $shipping_classes );
+ $package_data = array_merge(
+ $cart_data,
+ array(
+ 'package_total' => $total,
+ 'package_subtotal' => $subtotal,
+ 'package_weight' => $total_weight,
+ 'package_volume' => $volume,
+ 'package_item_count' => $item_count,
+ 'packaging_id' => $packaging->get_id(),
+ 'package_products' => $products,
+ 'package_shipping_classes' => $shipping_classes,
+ )
+ );
- break;
- }
- }
+ $package_applied_rules = array();
+ $applicable_rule_costs = array();
- /**
- * In case no applicable rule has been found, parse fallback rules.
- */
- if ( empty( $package_applied_rules ) ) {
- foreach ( array_reverse( $this->get_fallback_shipping_rules() ) as $rule ) {
+ foreach ( array_reverse( $this->get_shipping_rules_by_packaging( $packaging->get_id() ) ) as $rule ) {
$rule = $this->parse_rule( $rule );
$rule_applies = $this->rule_applies( $rule, $package_data );
@@ -651,87 +627,181 @@ public function calculate_shipping( $package = array() ) {
break;
}
}
- }
- if ( ! empty( $package_applied_rules ) ) {
- $applicable_rules_total_cost = 0.0;
+ /**
+ * In case no applicable rule has been found, parse fallback rules.
+ */
+ if ( empty( $package_applied_rules ) ) {
+ foreach ( array_reverse( $this->get_fallback_shipping_rules() ) as $rule ) {
+ $rule = $this->parse_rule( $rule );
+ $rule_applies = $this->rule_applies( $rule, $package_data );
- if ( 'sum' === $multiple_rules_calculation_mode ) {
- $applicable_rules_total_cost = array_sum( $applicable_rule_costs );
- } elseif ( 'min' === $multiple_rules_calculation_mode ) {
- $applicable_rules_total_cost = min( $applicable_rule_costs );
- } elseif ( 'max' === $multiple_rules_calculation_mode ) {
- $applicable_rules_total_cost = max( $applicable_rule_costs );
- }
+ if ( $rule_applies ) {
+ $applicable_rule_costs[] = $rule['costs'];
+ $package_applied_rules[] = $rule['rule_id'];
+ }
- if ( 'min' === $cost_calculation_mode ) {
- if ( $applicable_rules_total_cost <= $total_cost || 0.0 === $total_cost ) {
- $total_cost = $applicable_rules_total_cost;
- }
- } elseif ( 'max' === $cost_calculation_mode ) {
- if ( $applicable_rules_total_cost >= $total_cost ) {
- $total_cost = $applicable_rules_total_cost;
+ /**
+ * In case a free shipping option is detected, stop + reset.
+ */
+ if ( $rule_applies && 0.0 === $rule['costs'] ) {
+ $applicable_rule_costs = array(
+ $rule['costs'],
+ );
+
+ $package_applied_rules = array(
+ $rule['rule_id'],
+ );
+
+ break;
+ }
}
- } else {
- $total_cost += $applicable_rules_total_cost;
}
- /**
- * Build an item map which contains a map of the cart items
- * included within the package.
- */
- $item_map = array();
- $weight = 0.0;
+ if ( ! empty( $package_applied_rules ) ) {
+ $applicable_rules_total_cost = 0.0;
- foreach ( $items as $item ) {
- $cart_item_wrapper = $item->getItem();
- $product = $cart_item_wrapper->get_product();
- $product_key = $product->get_parent_id() . '_' . $product->get_id();
- $weight += $cart_item_wrapper->getWeight();
+ if ( 'sum' === $multiple_rules_calculation_mode ) {
+ $applicable_rules_total_cost = array_sum( $applicable_rule_costs );
+ } elseif ( 'min' === $multiple_rules_calculation_mode ) {
+ $applicable_rules_total_cost = min( $applicable_rule_costs );
+ } elseif ( 'max' === $multiple_rules_calculation_mode ) {
+ $applicable_rules_total_cost = max( $applicable_rule_costs );
+ }
- if ( array_key_exists( $product_key, $item_map ) ) {
- $item_map[ $product_key ]++;
+ if ( 'min' === $cost_calculation_mode ) {
+ if ( $applicable_rules_total_cost <= $total_cost || 0.0 === $total_cost ) {
+ $total_cost = $applicable_rules_total_cost;
+ }
+ } elseif ( 'max' === $cost_calculation_mode ) {
+ if ( $applicable_rules_total_cost >= $total_cost ) {
+ $total_cost = $applicable_rules_total_cost;
+ }
} else {
- $item_map[ $product_key ] = 1;
+ $total_cost += $applicable_rules_total_cost;
}
- if ( array_key_exists( $product_key, $total_packed_item_map ) ) {
- $total_packed_item_map[ $product_key ]++;
- } else {
- $total_packed_item_map[ $product_key ] = 1;
+ /**
+ * Build an item map which contains a map of the cart items
+ * included within the package.
+ */
+ $item_map = array();
+
+ foreach ( $items as $item ) {
+ $cart_item_wrapper = $item->getItem();
+ $product = $cart_item_wrapper->get_product();
+ $product_key = $product->get_parent_id() . '_' . $product->get_id();
+
+ if ( array_key_exists( $product_key, $item_map ) ) {
+ $item_map[ $product_key ]++;
+ } else {
+ $item_map[ $product_key ] = 1;
+ }
+
+ if ( array_key_exists( $product_key, $total_packed_item_map ) ) {
+ $total_packed_item_map[ $product_key ]++;
+ } else {
+ $total_packed_item_map[ $product_key ] = 1;
+ }
+
+ $total_packed_items++;
}
- $total_packed_items++;
+ $applied_rules[] = array(
+ 'packaging_id' => $packaging->get_id(),
+ 'rules' => $package_applied_rules,
+ 'items' => $item_map,
+ );
+
+ $rule_ids = array_unique( array_merge( $rule_ids, $package_applied_rules ) );
+ $packaging_ids = array_unique( array_merge( $packaging_ids, array( $packaging->get_id() ) ) );
}
+ }
- $applied_rules[] = array(
- 'packaging_id' => $packaging->get_id(),
- 'rules' => $package_applied_rules,
- 'items' => $item_map,
- 'weight' => $weight + $packaging->getEmptyWeight(),
+ if ( ! empty( $applied_rules ) ) {
+ if ( $is_debug_mode ) {
+ $package_count = 0;
+
+ foreach ( $applied_rules as $applied_rule ) {
+ if ( $packaging = wc_gzd_get_packaging( $applied_rule['packaging_id'] ) ) {
+ $package_count++;
+ $debug_notices[] = sprintf( _x( '## Package %1$d/%2$d: %3$s: ', 'shipments', 'woocommerce-germanized-shipments' ), $package_count, count( $applied_rules ), $packaging->get_title() );
+
+ foreach ( $applied_rule['rules'] as $rule ) {
+ if ( $the_rule = $this->get_shipping_rule_by_id( $rule, $applied_rule['packaging_id'] ) ) {
+ $debug_notices[] = sprintf( _x( 'Rule %1$d: %2$s', 'shipments', 'woocommerce-germanized-shipments' ), $rule, wc_price( $the_rule['costs'] ) );
+ }
+ }
+
+ foreach ( $applied_rule['items'] as $item_product_key => $quantity ) {
+ $product_ids = explode( '_', $item_product_key );
+ $product_title = $product_ids[0];
+
+ if ( $product = wc_get_product( $product_ids[1] ) ) {
+ $product_title = $product->get_title();
+ }
+
+ $product_desc = ! empty( $product_ids[0] ) ? sprintf( _x( '%1$s (Parent: %2$s)', 'shipments', 'woocommerce-germanized-shipments' ), $product_title, $product_ids[0] ) : $product_title;
+ $debug_notices[] = sprintf( _x( '%1$s x %2$s', 'shipments', 'woocommerce-germanized-shipments' ), $quantity, $product_desc );
+ }
+ }
+ }
+
+ $debug_notices[] = sprintf( _x( '## Total: %1$s (%2$s, %3$s)', 'shipments', 'woocommerce-germanized-shipments' ), wc_price( $total_cost ), $cost_calculation_mode, $multiple_rules_calculation_mode );
+ }
+
+ $this->add_rate(
+ array(
+ 'cost' => $total_cost,
+ 'label' => $this->get_rate_label( $total_cost ),
+ 'package' => $package,
+ 'meta_data' => array(
+ '_packed_items' => $total_packed_items,
+ '_packed_item_map' => $total_packed_item_map,
+ '_packaging_ids' => $packaging_ids,
+ '_rule_ids' => $rule_ids,
+ '_packages' => $applied_rules,
+ ),
+ )
);
+ } elseif ( $is_debug_mode ) {
+ $debug_notices[] = _x( 'None of the available rules applied.', 'shipments', 'woocommerce-germanized-shipments' );
+ }
+ } elseif ( $is_debug_mode ) {
+ foreach ( $unpacked_items as $item ) {
+ $product_desc = $item->get_id();
- $rule_ids = array_unique( array_merge( $rule_ids, $package_applied_rules ) );
- $packaging_ids = array_unique( array_merge( $packaging_ids, array( $packaging->get_id() ) ) );
+ if ( $product = $item->get_product() ) {
+ $product_desc = $product->get_title();
+ }
+
+ $debug_notices[] = sprintf( _x( '%1$s does not fit the available packaging options', 'shipments', 'woocommerce-germanized-shipments' ), $product_desc );
}
}
}
- if ( ! empty( $applied_rules ) ) {
- $this->add_rate(
- array(
- 'cost' => $total_cost,
- 'label' => $this->get_rate_label( $total_cost ),
- 'package' => $package,
- 'meta_data' => array(
- '_packed_items' => $total_packed_items,
- '_packed_item_map' => $total_packed_item_map,
- '_packaging_ids' => $packaging_ids,
- '_rule_ids' => $rule_ids,
- '_packages' => $applied_rules,
- ),
- )
+ if ( $is_debug_mode && ! Package::is_constant_defined( 'WOOCOMMERCE_CHECKOUT' ) && ! Package::is_constant_defined( 'WC_DOING_AJAX' ) && ! empty( $debug_notices ) ) {
+ $the_notice = '';
+ $available_box_list = array();
+
+ foreach ( $available_boxes as $box ) {
+ $available_box_list[] = $box->get_packaging()->get_title();
+ }
+
+ $general_debug_notices = array(
+ sprintf( _x( '### Debug information for %1$s:', 'shipments', 'woocommerce-germanized-shipments' ), $this->get_title() ),
+ sprintf( _x( 'Available packaging options: %1$s', 'shipments', 'woocommerce-germanized-shipments' ), implode( ', ', $available_box_list ) ),
);
+
+ $debug_notices = array_merge( $general_debug_notices, $debug_notices );
+
+ foreach ( $debug_notices as $notice ) {
+ $the_notice .= $notice . '
';
+ }
+
+ if ( ! wc_has_notice( $the_notice ) ) {
+ wc_add_notice( $the_notice );
+ }
}
}
@@ -1100,7 +1170,7 @@ protected function generate_shipping_rules_html( $option_name, $option ) {