context = adp_context(); $this->listener = new ProductCalculatorListener(); if($this->context->isDebug()) { $this->listener->subscribe(new ProductCalculatorListener()); } } public function withCart(Cart $cart) { $this->cart = $cart; } protected function isCartExists(): bool { return isset($this->cart); } public function withContext(Context $context) { $this->context = $context; } /** * @param WC_Product|int $theProduct * @param float $qty * @param array $cartItemData * * @return ProcessedProductSimple|ProcessedVariableProduct|ProcessedGroupedProduct|null */ public function calculateProduct($theProduct, $qty = 1.0, $cartItemData = array()) { if (is_numeric($theProduct)) { $product = CacheHelper::getWcProduct($theProduct); } elseif ($theProduct instanceof WC_Product) { $product = clone $theProduct; } else { $this->context->handleError(new Exception("Product does not exists")); return null; } return $this->calculateWithProductWrapper( new WcProductCalculationWrapper($product, $cartItemData, []), $qty ); } /** * @param WcProductCalculationWrapper $wrapper * @param float $qty * * @return ProcessedGroupedProduct|ProcessedProductSimple|ProcessedVariableProduct|null */ public function calculateWithProductWrapper(WcProductCalculationWrapper $wrapper, float $qty = 1.0){ $product = $wrapper->getWcProduct(); $cartItemData = $wrapper->getCartItemData(); if ($product instanceof \WC_Product_Grouped) { /** @var $processed ProcessedGroupedProduct */ $processed = Factory::get("PriceDisplay_ProcessedGroupedProduct", $product, $qty); $children = array_filter( array_map('wc_get_product', $product->get_children()), 'wc_products_array_filter_visible_grouped' ); foreach ($children as $childId) { $processedChild = $this->calculateSimpleProductWrapper( new WcProductCalculationWrapper( WcProductProcessorHelper::buildWcProductFromChildId($childId, $product), $cartItemData, [] ), $qty ); if (is_null($processedChild)) { continue; } $processed->useChild($processedChild); } } elseif ($product instanceof \WC_Product_Variable) { /** @var $processed ProcessedVariableProduct */ $processed = Factory::get("PriceDisplay_ProcessedVariableProduct", $this->context, $product, $qty); $children = $product->get_visible_children(); foreach ($children as $childId) { $processedChild = $this->calculateSimpleProductWrapper( new WcProductCalculationWrapper( WcProductProcessorHelper::buildWcProductFromChildId($childId, $product), $cartItemData, [] ), $qty ); if (is_null($processedChild)) { continue; } $processed->useChild($processedChild); } } elseif ( WcProductProcessorHelper::isCalculatingPartOfContainerProduct($product) ) { $containerProduct = WcProductProcessorHelper::getBundleProductFromBundled($product); $processedParent = $this->calculateSimpleProductWrapper( new WcProductCalculationWrapper($containerProduct, $cartItemData, []), $qty ); $processed = null; if ($processedParent instanceof ProcessedProductContainer) { foreach ($processedParent->getContainerItemsByPos() as $containerItem) { if ($containerItem->getProduct()->get_id() === $product->get_id()) { $processed = $containerItem; } } } } else { $processed = $this->calculateSimpleProductWrapper( new WcProductCalculationWrapper($product, $cartItemData, []), $qty ); } return $processed; } /** * @param WcProductCalculationWrapper $wrapper * @param float $qty * * @return ProcessedProductSimple|ProcessedProductContainer|null */ protected function calculateSimpleProductWrapper( WcProductCalculationWrapper $wrapper, float $qty = 1.0 ): ?ProcessedProductSimple { if (!$this->isCartExists()) { return null; } $product = $wrapper->getWcProduct(); $cartItemData = $wrapper->getCartItemData(); $addons = $wrapper->getAddons(); $tmpItems = []; $currentQty = 0.0; $qtyAlreadyInCart = floatval(0); $cartItems = []; foreach ( $this->cart->getItems() as $loopItem ) { $cartItems[] = clone $loopItem; } if ( has_filter("adp_in_cart_wc_product_processor_cart_items") ) { $cartItems = apply_filters( "adp_in_cart_wc_product_processor_cart_items", $cartItems ); } else { if ($this->context->getOption("process_product_strategy_after_use_price") === "first") { $cartItems = InCartWcProductProcessorPredefinedSortCallbacks::cartItemsAsIs($cartItems); } elseif ($this->context->getOption("process_product_strategy_after_use_price") === "last") { $cartItems = InCartWcProductProcessorPredefinedSortCallbacks::cartItemsInReverseOrder($cartItems); } elseif ($this->context->getOption("process_product_strategy_after_use_price") === "cheapest") { $cartItems = InCartWcProductProcessorPredefinedSortCallbacks::sortCartItemsByPriceAsc($cartItems); } elseif ($this->context->getOption("process_product_strategy_after_user_price") === "most_expensive") { $cartItems = InCartWcProductProcessorPredefinedSortCallbacks::sortCartItemsByPriceDesc($cartItems); } } foreach ($cartItems as $loopItem) { $loopProduct = $loopItem->getWcItem()->getProduct(); $condition = $loopItem->getWcItem()->getProduct()->get_id() === $product->get_id(); if ($product instanceof \WC_Product_Variation && $loopProduct instanceof \WC_Product_Variation) { $loopProductVariationAttributes = $loopProduct->get_variation_attributes(); foreach ($product->get_variation_attributes() as $key => $value) { $key_item = strtolower($key); if( !isset($loopProductVariationAttributes[$key_item]) || $loopProductVariationAttributes[$key_item] !== $value ) $condition = false; } } // cart item data foreach ($loopItem->getWcItem()->getThirdPartyData() as $key => $value) { if( !isset($cartItemData[$key]) || $cartItemData[$key] !== $value ) $condition = false; } // addons $condition &= count($loopItem->getAddons()) == count($addons); foreach ($loopItem->getAddons() as $loopAddon) { $match = false; foreach ($addons as $addon) { if ($loopAddon->getKey() == $addon->getKey()) { $match = true; $condition &= $loopAddon->getPrice() == $addon->getPrice(); break; } } $condition &= $match; } if ($condition) { $requiredQty = $qty - $currentQty; if ($requiredQty > $loopItem->getQty()) { $tmpItems[] = clone $loopItem; $currentQty += $loopItem->getQty(); } elseif ($requiredQty === $loopItem->getQty()) { $tmpItems[] = clone $loopItem; break; } else { $newLoopItem = clone $loopItem; $newLoopItem->setQty($requiredQty); $tmpItems[] = $newLoopItem; break; } } if ($loopProduct->get_id() === $product->get_id()) { $qtyAlreadyInCart += $loopItem->getQty(); } } $qtyAlreadyInCart -= array_sum( array_map( function ($item) { return $item->getQty(); }, $tmpItems ) ); if (count($tmpItems) === 0) { return null; } $tmpItems = apply_filters("adp_before_processed_product", $tmpItems, $this); $processedProduct = WcProductProcessorHelper::tmpItemsToProcessedProduct( $this->context, $product, $tmpItems, [], [] ); $processedProduct->setQtyAlreadyInCart($qtyAlreadyInCart); if( $this->context->getOption("show_debug_bar") ) $this->listener->processedProduct($processedProduct); return $processedProduct; } /** * @return ProductCalculatorListener */ public function getListener(): ProductCalculatorListener { return $this->listener; } /** * @return Cart|null */ public function getCart(): ?Cart { return $this->cart; } }