147 lines
4.5 KiB
PHP
147 lines
4.5 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Esun\Cart\Model;
|
|
|
|
use Magento\Framework\App\Config\ScopeConfigInterface;
|
|
use Magento\Framework\Pricing\PriceCurrencyInterface;
|
|
use Magento\Quote\Model\Quote;
|
|
use Magento\Quote\Model\Quote\Item\AbstractItem;
|
|
use Magento\SalesRule\Model\ResourceModel\Rule\CollectionFactory as RuleCollectionFactory;
|
|
use Magento\Store\Model\ScopeInterface;
|
|
|
|
class ShippingEstimate
|
|
{
|
|
private const XML_PATH_FLATRATE_ACTIVE = 'carriers/flatrate/active';
|
|
private const XML_PATH_FLATRATE_PRICE = 'carriers/flatrate/price';
|
|
private const XML_PATH_FLATRATE_TITLE = 'carriers/flatrate/title';
|
|
private const XML_PATH_FLATRATE_NAME = 'carriers/flatrate/name';
|
|
|
|
public function __construct(
|
|
private readonly ScopeConfigInterface $scopeConfig,
|
|
private readonly PriceCurrencyInterface $priceCurrency,
|
|
private readonly RuleCollectionFactory $ruleCollectionFactory
|
|
) {
|
|
}
|
|
|
|
public function getData(Quote $quote): array
|
|
{
|
|
$storeId = (int)$quote->getStoreId();
|
|
$available = $this->hasPhysicalItems($quote)
|
|
&& $this->scopeConfig->isSetFlag(
|
|
self::XML_PATH_FLATRATE_ACTIVE,
|
|
ScopeInterface::SCOPE_STORE,
|
|
$storeId
|
|
);
|
|
$freeShipping = $available && $this->isFreeShipping($quote);
|
|
$baseAmount = $available && !$freeShipping
|
|
? (float)$this->scopeConfig->getValue(
|
|
self::XML_PATH_FLATRATE_PRICE,
|
|
ScopeInterface::SCOPE_STORE,
|
|
$storeId
|
|
)
|
|
: 0.0;
|
|
$amount = $available
|
|
? (float)$this->priceCurrency->convertAndRound($baseAmount, $quote->getStore())
|
|
: 0.0;
|
|
|
|
return [
|
|
'available' => $available,
|
|
'free_shipping' => $freeShipping,
|
|
'quantity' => $this->getPhysicalQuantity($quote),
|
|
'base_amount' => $baseAmount,
|
|
'amount' => $amount,
|
|
'description' => $available ? $this->getDescription($storeId, $freeShipping) : '',
|
|
];
|
|
}
|
|
|
|
public function isFreeShipping(Quote $quote): bool
|
|
{
|
|
if (!$this->hasPhysicalItems($quote) || !$quote->getStoreId()) {
|
|
return false;
|
|
}
|
|
|
|
$address = clone $quote->getShippingAddress();
|
|
$address->setTotalQty($this->getPhysicalQuantity($quote))
|
|
->setSubtotal((float)$quote->getSubtotal())
|
|
->setBaseSubtotal((float)$quote->getBaseSubtotal());
|
|
|
|
$collection = $this->ruleCollectionFactory->create();
|
|
$collection->setValidationFilter(
|
|
(int)$quote->getStore()->getWebsiteId(),
|
|
(int)$quote->getCustomerGroupId(),
|
|
(string)$quote->getCouponCode(),
|
|
null,
|
|
$address
|
|
);
|
|
|
|
foreach ($collection as $rule) {
|
|
if ((int)$rule->getSimpleFreeShipping() > 0
|
|
&& $rule->getConditions()->validate($address)
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param AbstractItem[] $items
|
|
*/
|
|
public function isFreeShippingForItems(array $items): bool
|
|
{
|
|
foreach ($items as $item) {
|
|
$quote = $item->getQuote();
|
|
if ($quote instanceof Quote) {
|
|
return $this->isFreeShipping($quote);
|
|
}
|
|
|
|
$addressQuote = $item->getAddress()?->getQuote();
|
|
if ($addressQuote instanceof Quote) {
|
|
return $this->isFreeShipping($addressQuote);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function hasPhysicalItems(Quote $quote): bool
|
|
{
|
|
return $this->getPhysicalQuantity($quote) > 0;
|
|
}
|
|
|
|
private function getPhysicalQuantity(Quote $quote): float
|
|
{
|
|
$quantity = 0.0;
|
|
foreach ($quote->getAllVisibleItems() as $item) {
|
|
if ($item->getProduct()->isVirtual()) {
|
|
continue;
|
|
}
|
|
$quantity += (float)$item->getQty();
|
|
}
|
|
|
|
return $quantity;
|
|
}
|
|
|
|
private function getDescription(int $storeId, bool $freeShipping): string
|
|
{
|
|
if ($freeShipping) {
|
|
return (string)__('Free Shipping');
|
|
}
|
|
|
|
$title = (string)$this->scopeConfig->getValue(
|
|
self::XML_PATH_FLATRATE_TITLE,
|
|
ScopeInterface::SCOPE_STORE,
|
|
$storeId
|
|
);
|
|
$name = (string)$this->scopeConfig->getValue(
|
|
self::XML_PATH_FLATRATE_NAME,
|
|
ScopeInterface::SCOPE_STORE,
|
|
$storeId
|
|
);
|
|
|
|
return trim($title . ($title !== '' && $name !== '' ? ' - ' : '') . $name);
|
|
}
|
|
}
|