getSourceItemsBySku = $getSourceItemsBySku; $this->customerSession = $customerSession; $this->sourceCustomerRepository = $sourceCustomerRepository; } /** * Validate shipping address * * @param AddressInterface|null $address * @return void * @throws StateException */ private function validateAddress(?AddressInterface $address): void { if (!$address || !$address->getCountryId()) { throw new StateException(__('The shipping address is missing. Set the address and try again.')); } } /** * Prepare shipping assignment. * * @param CartInterface $quote * @param AddressInterface $address * @param string $method * @return CartInterface */ private function prepareShippingAssignment( CartInterface $quote, AddressInterface $address, string $method ): CartInterface { $cartExtension = $quote->getExtensionAttributes(); if ($cartExtension === null) { $cartExtension = $this->cartExtensionFactory->create(); } $shippingAssignments = $cartExtension->getShippingAssignments(); if (empty($shippingAssignments)) { $shippingAssignment = $this->shippingAssignmentFactory->create(); } else { $shippingAssignment = $shippingAssignments[0]; } $shipping = $shippingAssignment->getShipping(); if ($shipping === null) { $shipping = $this->shippingFactory->create(); } $shipping->setAddress($address); $shipping->setMethod($method); $shippingAssignment->setShipping($shipping); $cartExtension->setShippingAssignments([$shippingAssignment]); return $quote->setExtensionAttributes($cartExtension); } /** * Save address information. * * @param int $cartId * @param ShippingInformationInterface $addressInformation * @return PaymentDetailsInterface * @throws InputException * @throws NoSuchEntityException * @throws StateException */ public function saveAddressInformation( $cartId, ShippingInformationInterface $addressInformation ): PaymentDetailsInterface { /** @var Quote $quote */ $quote = $this->quoteRepository->getActive($cartId); $this->addressInformation = $addressInformation; $this->validateQuote($quote); $address = $addressInformation->getShippingAddress(); $this->validateAddress($address); if (!$address->getCustomerAddressId()) { $address->setCustomerAddressId(null); } try { $billingAddress = $addressInformation->getBillingAddress(); if ($billingAddress) { if (!$billingAddress->getCustomerAddressId()) { $billingAddress->setCustomerAddressId(null); } $this->addressValidator->validateForCart($quote, $billingAddress); $quote->setBillingAddress($billingAddress); } $this->addressValidator->validateForCart($quote, $address); $carrierCode = $addressInformation->getShippingCarrierCode(); $address->setLimitCarrier($carrierCode); $methodCode = $addressInformation->getShippingMethodCode(); $quote = $this->prepareShippingAssignment($quote, $address, $carrierCode . '_' . $methodCode); $quote->setIsMultiShipping(false); $this->quoteRepository->save($quote); } catch (LocalizedException $e) { $this->logger->critical($e); throw new InputException( __( 'The shipping information was unable to be saved. Error: "%message"', ['message' => $e->getMessage()] ) ); } catch (\Exception $e) { $this->logger->critical($e); throw new InputException( __('The shipping information was unable to be saved. Verify the input data and try again.') ); } $shippingAddress = $quote->getShippingAddress(); if (!$quote->getIsVirtual() && !$shippingAddress->getShippingRateByCode($shippingAddress->getShippingMethod()) ) { $errorMessage = $methodCode ? __('Carrier with such method not found: %1, %2', $carrierCode, $methodCode) : __('The shipping method is missing. Select the shipping method and try again.'); throw new NoSuchEntityException( $errorMessage ); } /** @var PaymentDetailsInterface $paymentDetails */ $paymentDetails = $this->paymentDetailsFactory->create(); $paymentDetails->setPaymentMethods($this->paymentMethodManagement->getList($cartId)); $paymentDetails->setTotals($this->cartTotalsRepository->get($cartId)); return $paymentDetails; } /** * @return SourceCustomerInterface * @throws \Magento\Framework\Exception\LocalizedException */ protected function getMySource() { if ($this->mySource) { return $this->mySource; } return $this->mySource = $this->sourceCustomerRepository->getFromCustomerId($this->customerSession->getId()); } /** * @param string $sku * @return float|int * @throws LocalizedException */ protected function getProductStock(string $sku) { foreach ($this->getSourceItemsBySku->execute($sku) as $sourceItem) { if ($sourceItem->getSourceCode() == $this->getMySource()->getSourceCode()) { return $sourceItem->getQuantity(); } } return 0; } /** * @param Quote $quote * @return void * @throws InputException * @throws LocalizedException */ protected function validateProductStock(Quote $quote) { list(, $methodCode) = explode('_', InStorePickup::DELIVERY_METHOD); if ($this->addressInformation->getShippingMethodCode()!=$methodCode){ return; } $overStocks = []; $quoteItems = $quote->getAllVisibleItems(); foreach ($quoteItems as $item) { //$this->logger->debug('validateProductStock: ', ['sku' => $item->getSku(), 'stock' => $this->getProductStock($item->getSku()), 'my_preferred'=>$this->getMySource()->getSourceCode()]); if ($item->getQty() > $this->getProductStock($item->getSku())) { $overStocks[] = $item->getName(); } } if (!empty($overStocks)) { throw new InputException( __('Products "%1" out of stock from your preferred warehouse.', implode(', ', $overStocks)) ); } } protected function validateQuote(Quote $quote): void { parent::validateQuote($quote); try { $this->validateProductStock($quote); } catch (LocalizedException $e) { throw new InputException( __($e->getMessage()) ); } } }