checkoutSession->getQuote(); $removedOrphan = $this->removeOrphanedChildItems($quote); $quote->setTotalsCollectedFlag(false)->collectTotals(); if ($removedOrphan) { $this->quoteRepository->save($quote); } $result['items'] = $this->addItemPrices($result['items'] ?? [], $quote); $result['drawer_totals'] = $this->getTotalsData($quote); $result['purchase_progress'] = $this->milestoneProvider->getData($quote); return $result; } private function removeOrphanedChildItems(Quote $quote): bool { $removed = false; foreach ($quote->getAllItems() as $item) { $parentItemId = (int)$item->getParentItemId(); if ($parentItemId > 0 && !$quote->getItemById($parentItemId)) { $quote->removeItem((int)$item->getId()); $removed = true; } } return $removed; } private function getTotalsData(Quote $quote): array { $address = $quote->getShippingAddress(); $subtotal = (float)$quote->getSubtotal(); $discount = (float)$address->getDiscountAmount(); $estimate = $this->shippingEstimate->getData($quote); $shipping = (float)$estimate['amount']; $grandTotal = (float)$quote->getGrandTotal() - (float)$address->getShippingAmount() + $shipping; return [ 'subtotal' => $this->checkoutHelper->formatPrice($subtotal), 'discount' => $this->checkoutHelper->formatPrice($discount), 'shipping' => $this->checkoutHelper->formatPrice($shipping), 'grand_total' => $this->checkoutHelper->formatPrice($grandTotal), 'has_shipping_estimate' => (bool)$estimate['available'], 'shipping_description' => (string)$estimate['description'], 'coupon_code' => (string)$quote->getCouponCode(), ]; } private function addItemPrices(array $items, Quote $quote): array { $quoteItems = []; foreach ($quote->getAllVisibleItems() as $quoteItem) { $quoteItems[(int)$quoteItem->getId()] = $quoteItem; } foreach ($items as &$item) { $itemId = (int)($item['item_id'] ?? 0); if (!isset($quoteItems[$itemId])) { continue; } $quoteItem = $quoteItems[$itemId]; $simpleProductOption = $quoteItem->getOptionByCode('simple_product'); $childProduct = $simpleProductOption?->getProduct(); $item['parent_product_id'] = (int)$quoteItem->getProductId(); $item['child_product_id'] = $childProduct && (int)$childProduct->getId() > 0 ? (int)$childProduct->getId() : (int)$quoteItem->getProductId(); $this->replaceWithChildProductImage($item, $quoteItem); $item['min_sale_qty'] = $this->getMinSaleQty($quoteItem, $quote); $currentPrice = (float)$quoteItem->getCalculationPrice(); $originalPrice = (float)$quoteItem->getOriginalPrice(); $item['line_total'] = $this->checkoutHelper->formatPrice( $currentPrice * (float)$quoteItem->getQty() ); $item['original_price'] = $originalPrice > $currentPrice + 0.0001 ? $this->checkoutHelper->formatPrice($originalPrice) : ''; } unset($item); return $items; } private function getMinSaleQty(\Magento\Quote\Model\Quote\Item $quoteItem, Quote $quote): float { $productIds = [(int)$quoteItem->getProductId()]; $simpleProductOption = $quoteItem->getOptionByCode('simple_product'); $childProduct = $simpleProductOption?->getProduct(); if ($childProduct && (int)$childProduct->getId() > 0) { $productIds[] = (int)$childProduct->getId(); } $minimumQty = 1.0; foreach (array_unique(array_filter($productIds)) as $productId) { try { $stockItem = $this->stockRegistry->getStockItem( $productId, (int)$quote->getStore()->getWebsiteId() ); if (method_exists($stockItem, 'setCustomerGroupId')) { $stockItem->setCustomerGroupId((int)$quote->getCustomerGroupId()); } $minimumQty = max($minimumQty, (float)$stockItem->getMinSaleQty()); } catch (\Magento\Framework\Exception\LocalizedException) { continue; } } return $minimumQty; } private function replaceWithChildProductImage(array &$item, \Magento\Quote\Model\Quote\Item $quoteItem): void { $simpleProductOption = $quoteItem->getOptionByCode('simple_product'); $childProduct = $simpleProductOption?->getProduct(); if (!$childProduct || !(int)$childProduct->getId()) { return; } $imageFile = $this->getChildImageFile($childProduct); if ($imageFile === '') { return; } $image = $this->imageHelper ->init($childProduct, 'mini_cart_product_thumbnail') ->setImageFile($imageFile); $item['product_image'] = [ 'src' => $image->getUrl(), 'alt' => $image->getLabel() ?: (string)$childProduct->getName(), 'width' => $image->getWidth(), 'height' => $image->getHeight(), ]; } private function getChildImageFile(\Magento\Catalog\Model\Product $childProduct): string { foreach (['thumbnail', 'small_image', 'image'] as $imageAttribute) { $imageFile = (string)$childProduct->getData($imageAttribute); if ($imageFile !== '' && $imageFile !== 'no_selection') { return $imageFile; } } return ''; } }