Files
ltsecurityinc/app/code/Lts/Checkout/Model/ShippingInformationManagement.php
T

286 lines
10 KiB
PHP

<?php
namespace Lts\Checkout\Model;
use Lts\Inventory\Api\Data\SourceCustomerInterface;
use Lts\Inventory\Api\SourceCustomerRepositoryInterface;
use Magento\Checkout\Api\Data\PaymentDetailsInterface;
use Magento\Checkout\Api\Data\ShippingInformationInterface;
use Magento\Checkout\Model\PaymentDetailsFactory;
use Magento\Customer\Api\AddressRepositoryInterface;
use Magento\Customer\Model\Session;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Exception\StateException;
use Magento\InventoryInStorePickupShippingApi\Model\Carrier\InStorePickup;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Api\CartTotalRepositoryInterface;
use Magento\Quote\Api\Data\AddressInterface;
use Magento\Quote\Api\Data\CartExtensionFactory;
use Magento\Quote\Api\Data\CartInterface;
use Magento\Quote\Api\PaymentMethodManagementInterface;
use Magento\Quote\Model\Quote;
use Magento\InventoryApi\Api\GetSourceItemsBySkuInterface;
use Magento\Quote\Model\Quote\TotalsCollector;
use Magento\Quote\Model\QuoteAddressValidator;
use Magento\Quote\Model\ShippingAssignmentFactory;
use Magento\Quote\Model\ShippingFactory;
use Psr\Log\LoggerInterface as Logger;
class ShippingInformationManagement extends \Magento\Checkout\Model\ShippingInformationManagement
{
private GetSourceItemsBySkuInterface $getSourceItemsBySku;
private Session $customerSession;
private SourceCustomerRepositoryInterface $sourceCustomerRepository;
private ?SourceCustomerInterface $mySource = null;
/**
* @var CartExtensionFactory
*/
protected CartExtensionFactory $cartExtensionFactory;
/**
* @var ShippingFactory
*/
protected $shippingFactory;
protected ShippingInformationInterface $addressInformation;
public function __construct(
PaymentMethodManagementInterface $paymentMethodManagement,
PaymentDetailsFactory $paymentDetailsFactory,
CartTotalRepositoryInterface $cartTotalsRepository,
CartRepositoryInterface $quoteRepository,
QuoteAddressValidator $addressValidator,
Logger $logger,
AddressRepositoryInterface $addressRepository,
ScopeConfigInterface $scopeConfig,
TotalsCollector $totalsCollector,
CartExtensionFactory $cartExtensionFactory = null,
ShippingAssignmentFactory $shippingAssignmentFactory = null,
ShippingFactory $shippingFactory = null,
GetSourceItemsBySkuInterface $getSourceItemsBySku,
Session $customerSession,
SourceCustomerRepositoryInterface $sourceCustomerRepository,
) {
parent::__construct(
$paymentMethodManagement,
$paymentDetailsFactory,
$cartTotalsRepository,
$quoteRepository,
$addressValidator,
$logger,
$addressRepository,
$scopeConfig,
$totalsCollector,
$cartExtensionFactory,
$shippingAssignmentFactory,
$shippingFactory
);
$this->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())
);
}
}
}