286 lines
10 KiB
PHP
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())
|
|
);
|
|
}
|
|
}
|
|
} |