Skip to content

Commit

Permalink
Improved bundles compatibility by:
Browse files Browse the repository at this point in the history
- Storing parent/child hierarchy within shipment items
- Filtering product data while calculating order-related packaging data and syncing items with the shipment
  • Loading branch information
dennisnissle committed Jun 28, 2024
1 parent d44f863 commit 1592b30
Show file tree
Hide file tree
Showing 14 changed files with 290 additions and 73 deletions.
143 changes: 143 additions & 0 deletions src/Compatibility/Bundles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php

namespace Vendidero\Germanized\Shipments\Compatibility;

use Vendidero\Germanized\Shipments\Interfaces\Compatibility;
use Vendidero\Germanized\Shipments\Product;
use Vendidero\Germanized\Shipments\Shipment;

defined( 'ABSPATH' ) || exit;

class Bundles implements Compatibility {

protected static $cart_bundled_by_map = array();

public static function is_active() {
return class_exists( 'WC_Bundles' );
}

public static function init() {
add_action(
'woocommerce_gzd_shipments_before_prepare_cart_contents',
function() {
self::$cart_bundled_by_map = array();
}
);

add_filter( 'woocommerce_gzd_shipments_order_item_product', array( __CLASS__, 'get_product_from_item' ), 10, 2 );
add_filter( 'woocommerce_gzd_shipments_cart_item', array( __CLASS__, 'adjust_cart_item' ), 10, 2 );
add_action( 'woocommerce_gzd_shipment_items_synced', array( __CLASS__, 'apply_bundle_hierarchy' ), 10, 3 );
}

/**
* Add parent bundle id to the child bundles.
*
* @param Shipment $shipment
*
* @return void
*/
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();

if ( wc_pb_is_bundled_order_item( $order_item ) ) {
$container_id = wc_pb_get_bundled_order_item_container( $order_item, false, true );

if ( ! isset( $parents[ $container_id ] ) ) {
$parents[ $container_id ] = array();
}

$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_parent_id( $parent_id );
}
}
}
}

/**
* @param Product $product
* @param \WC_Order_Item_Product $item
*
* @return Product
*/
public static function get_product_from_item( $product, $item ) {
if ( ! $order = $item->get_order() ) {
return $product;
}

$reset_shipping_props = false;

if ( wc_pb_is_bundle_container_order_item( $item ) ) {
if ( $product->needs_shipping() ) {
if ( $bundle_weight = $item->get_meta( '_bundle_weight', true ) ) {
if ( is_null( $bundle_weight ) ) {
$bundle_weight = '';
}

$product->set_weight( $bundle_weight );
}
} else {
$reset_shipping_props = true;
}
} elseif ( wc_pb_is_bundled_order_item( $item, $order ) ) {
if ( $product->needs_shipping() ) {
if ( 'no' === $item->get_meta( '_bundled_item_needs_shipping', true ) ) {
$reset_shipping_props = true;
}
} else {
$reset_shipping_props = true;
}
}

if ( $reset_shipping_props ) {
$product->set_weight( 0 );
$product->set_shipping_width( 0 );
$product->set_shipping_height( 0 );
$product->set_shipping_length( 0 );
}

return $product;
}

/**
* Product Bundles cart item compatibility:
* In case the current item belongs to a parent bundle item (which contains the actual price)
* copy the pricing data from the parent once, e.g. for the first bundled item.
*
* @param $item
* @param $content_key
*
* @return mixed
*/
public static function adjust_cart_item( $item, $content_key ) {
if ( isset( $item['bundled_by'] ) && 0.0 === (float) $item['line_total'] && function_exists( 'wc_pb_get_bundled_cart_item_container' ) ) {
$bundled_by = $item['bundled_by'];

if ( ! in_array( $bundled_by, self::$cart_bundled_by_map, true ) ) {
if ( $container = wc_pb_get_bundled_cart_item_container( $item ) ) {
$item['line_total'] = (float) $container['line_total'];
$item['line_subtotal'] = (float) $container['line_subtotal'];
$item['line_tax'] = (float) $container['line_tax'];
$item['line_subtotal_tax'] = (float) $container['line_subtotal_tax'];

self::$cart_bundled_by_map[] = $bundled_by;
}
}
}

return $item;
}
}
11 changes: 8 additions & 3 deletions src/DataStores/Shipment.php
Original file line number Diff line number Diff line change
Expand Up @@ -577,12 +577,17 @@ public function read_items( $shipment ) {
}

if ( ! empty( $items ) ) {

$shipment_type = $shipment->get_type();

$items = array_map(
function( $item_id ) use ( $shipment_type ) {
return wc_gzd_get_shipment_item( $item_id, $shipment_type );
function( $item_id ) use ( $shipment_type, $shipment ) {
$item = wc_gzd_get_shipment_item( $item_id, $shipment_type );

if ( $item ) {
$item->set_shipment( $shipment );
}

return $item;
},
array_combine( wp_list_pluck( $items, 'shipment_item_id' ), $items )
);
Expand Down
20 changes: 20 additions & 0 deletions src/Interfaces/Compatibility.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Vendidero\Germanized\Shipments\Interfaces;

/**
* Compatibility
*
* @package Germanized/StoreaBill/Interfaces
* @version 1.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}

interface Compatibility {

public static function is_active();

public static function init();
}
49 changes: 31 additions & 18 deletions src/Order.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,21 @@ public function get_default_return_shipping_provider() {
return apply_filters( 'woocommerce_gzd_shipment_order_return_default_shipping_provider', $default_provider, $this );
}

/**
* @param \WC_Order_Item_Product $item
*
* @return Product|null
*/
public function get_order_item_product( $order_item ) {
$s_product = null;

if ( is_callable( array( $order_item, 'get_product' ) ) && ( $product = $order_item->get_product() ) ) {
$s_product = wc_gzd_shipments_get_product( $product );
}

return apply_filters( 'woocommerce_gzd_shipments_order_item_product', $s_product, $order_item );
}

protected function get_package_data() {
if ( is_null( $this->package_data ) ) {
$items = $this->get_available_items_for_shipment();
Expand Down Expand Up @@ -231,19 +246,17 @@ protected function get_package_data() {

$quantity = (int) $item['max_quantity'];

if ( $product = $order_item->get_product() ) {
$s_product = wc_gzd_shipments_get_product( $product );

$width = ( empty( $s_product->get_shipping_width() ) ? 0 : (float) wc_format_decimal( $s_product->get_shipping_width() ) ) * $quantity;
$length = ( empty( $s_product->get_shipping_length() ) ? 0 : (float) wc_format_decimal( $s_product->get_shipping_length() ) ) * $quantity;
$height = ( empty( $s_product->get_shipping_height() ) ? 0 : (float) wc_format_decimal( $s_product->get_shipping_height() ) ) * $quantity;
$weight = ( empty( $s_product->get_weight() ) ? 0 : (float) wc_format_decimal( $product->get_weight() ) ) * $quantity;
if ( $product = $this->get_order_item_product( $order_item ) ) {
$width = ( empty( $product->get_shipping_width() ) ? 0 : (float) wc_format_decimal( $product->get_shipping_width() ) ) * $quantity;
$length = ( empty( $product->get_shipping_length() ) ? 0 : (float) wc_format_decimal( $product->get_shipping_length() ) ) * $quantity;
$height = ( empty( $product->get_shipping_height() ) ? 0 : (float) wc_format_decimal( $product->get_shipping_height() ) ) * $quantity;
$weight = ( empty( $product->get_weight() ) ? 0 : (float) wc_format_decimal( $product->get_weight() ) ) * $quantity;

$package_data['weight'] += $weight;
$package_data['volume'] += ( $width * $length * $height );

if ( $product && ! array_key_exists( $product->get_id(), $package_data['products'] ) ) {
$package_data['products'][ $product->get_id() ] = $product;
if ( ! array_key_exists( $product->get_id(), $package_data['products'] ) ) {
$package_data['products'][ $product->get_id() ] = $product->get_product();

if ( ! empty( $product->get_shipping_class_id() ) ) {
$package_data['shipping_classes'][] = $product->get_shipping_class_id();
Expand Down Expand Up @@ -291,8 +304,7 @@ public function create_shipments( $default_status = 'processing' ) {
}

$items = $this->get_items_to_pack_left_for_shipping();
$boxes = PackagingList::fromArray( $packaging_boxes );
$packed_boxes = Helper::pack( $items, $boxes, 'order' );
$packed_boxes = Helper::pack( $items, $packaging_boxes, 'order' );

if ( empty( $packaging_boxes ) && 0 === count( $packed_boxes ) ) {
$shipment = wc_gzd_create_shipment( $this, array( 'props' => array( 'status' => $default_status ) ) );
Expand Down Expand Up @@ -682,8 +694,8 @@ public function order_item_is_non_returnable( $order_item_id ) {

if ( $order_item ) {
if ( is_callable( array( $order_item, 'get_product' ) ) ) {
if ( $product = $order_item->get_product() ) {
$is_non_returnable = wc_gzd_shipments_get_product( $product )->is_non_returnable();
if ( $product = $this->get_order_item_product( $order_item ) ) {
$is_non_returnable = $product->is_non_returnable();
}
}
}
Expand Down Expand Up @@ -759,7 +771,7 @@ public function get_items_to_pack_left_for_shipping( $legacy_group_by_product_gr

$product_group = '';

if ( $product = $order_item->get_product() ) {
if ( $product = $this->get_order_item_product( $order_item ) ) {
$product_group = '';

if ( 'yes' === get_option( 'woocommerce_gzd_shipments_packing_group_by_shipping_class' ) ) {
Expand Down Expand Up @@ -809,7 +821,7 @@ public function get_available_items_for_shipment( $args = array() ) {
$sku = '';

if ( is_callable( array( $item, 'get_product' ) ) ) {
if ( $product = $item->get_product() ) {
if ( $product = $this->get_order_item_product( $item ) ) {
$sku = $product->get_sku();
}
}
Expand Down Expand Up @@ -989,9 +1001,7 @@ public function get_shippable_items() {
$items = $this->get_order()->get_items( 'line_item' );

foreach ( $items as $key => $item ) {
$product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false;

if ( $product ) {
if ( $product = $this->get_order_item_product( $item ) ) {
if ( $product->is_virtual() || $this->get_shippable_item_quantity( $item ) <= 0 ) {
unset( $items[ $key ] );
}
Expand All @@ -1011,6 +1021,9 @@ public function get_shippable_items() {
* @since 3.0.0
* @package Vendidero/Germanized/Shipments
*/

do_action( 'woocommerce_gzd_shipments_order_after_get_items', $this->get_order() );

return apply_filters( 'woocommerce_gzd_shipment_order_shippable_items', $items, $this->get_order(), $this );
}

Expand Down
18 changes: 18 additions & 0 deletions src/Package.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public static function init() {
self::maybe_set_upload_dir();
self::init_hooks();
self::includes();
self::load_compatibilities();

do_action( 'woocommerce_gzd_shipments_init' );
}
Expand Down Expand Up @@ -92,6 +93,23 @@ function ( $container ) {
return $container;
}

public static function load_compatibilities() {
$compatibilities = apply_filters(
'woocommerce_gzd_shipments_compatibilities',
array(
'bundles' => '\Vendidero\Germanized\Shipments\Compatibility\Bundles',
)
);

foreach ( $compatibilities as $compatibility ) {
if ( is_a( $compatibility, '\Vendidero\Germanized\Shipments\Interfaces\Compatibility', true ) ) {
if ( $compatibility::is_active() ) {
$compatibility::init();
}
}
}
}

public static function manipulate_shipping_rates( $args, $method ) {
if ( $method = wc_gzd_get_shipping_provider_method( $method ) ) {
$args['meta_data']['_shipping_provider'] = $method->get_shipping_provider();
Expand Down
10 changes: 4 additions & 6 deletions src/Packing/CartItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ public function __construct( $item, $incl_taxes = false ) {
throw new \Exception( 'Invalid item' );
}

$s_product = wc_gzd_shipments_get_product( $this->get_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() );
$depth = empty( $s_product->get_shipping_height() ) ? 0 : (float) wc_format_decimal( $s_product->get_shipping_height() );
$width = empty( $this->get_product()->get_shipping_width() ) ? 0 : (float) wc_format_decimal( $this->get_product()->get_shipping_width() );
$length = empty( $this->get_product()->get_shipping_length() ) ? 0 : (float) wc_format_decimal( $this->get_product()->get_shipping_length() );
$depth = empty( $this->get_product()->get_shipping_height() ) ? 0 : (float) wc_format_decimal( $this->get_product()->get_shipping_height() );

$this->dimensions = array(
'width' => (int) wc_get_dimension( $width, 'mm' ),
Expand All @@ -54,7 +52,7 @@ public function __construct( $item, $incl_taxes = false ) {
}

protected function load_product() {
$this->product = $this->item['data'];
$this->product = wc_gzd_shipments_get_product( $this->item['data'] );
}

/**
Expand Down
11 changes: 10 additions & 1 deletion src/Packing/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Vendidero\Germanized\Shipments\Packing;

use Vendidero\Germanized\Shipments\Interfaces\PackingItem;
use Vendidero\Germanized\Shipments\Product;

defined( 'ABSPATH' ) || exit;

Expand Down Expand Up @@ -36,7 +37,7 @@ protected function load_product() {
}

/**
* @return null|\WC_Product
* @return null|Product
*/
public function get_product() {
if ( is_null( $this->product ) ) {
Expand Down Expand Up @@ -99,9 +100,13 @@ public function getDescription(): string {
$description = $this->get_id();

if ( $product = $this->get_product() ) {
$title = $product->get_title();

if ( $product->get_sku() ) {
$description = $this->get_product()->get_sku();
}

$description = $title . ' (' . $description . ')';
}

return apply_filters( 'woocommerce_gzd_packing_item_description', $description, $this );
Expand Down Expand Up @@ -135,6 +140,10 @@ public function getWeight(): int {
return apply_filters( 'woocommerce_gzd_packing_item_weight_in_g', $this->weight, $this );
}

public function get_dimensions() {
return $this->dimensions;
}

/**
* Item total in cents.
*
Expand Down
Loading

0 comments on commit 1592b30

Please sign in to comment.