175 lines
5.1 KiB
PHP
175 lines
5.1 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Esun\FreeGift\Model;
|
|
|
|
use Magento\Framework\App\Config\ScopeConfigInterface;
|
|
use Magento\Framework\Serialize\Serializer\Json;
|
|
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
|
|
use Magento\Store\Model\ScopeInterface;
|
|
|
|
class Config
|
|
{
|
|
private const XML_PATH_ENABLED = 'esun_free_gift/general/enabled';
|
|
private const XML_PATH_GIFT_SKU = 'esun_free_gift/general/gift_sku';
|
|
private const XML_PATH_START_DATE = 'esun_free_gift/general/start_date';
|
|
private const XML_PATH_END_DATE = 'esun_free_gift/general/end_date';
|
|
private const XML_PATH_TIER_ITEMS = 'esun_free_gift/tiers/items';
|
|
private const XML_PATH_TIER_AMOUNT = 'esun_free_gift/tiers/tier_%d_amount';
|
|
private const XML_PATH_TIER_QTY = 'esun_free_gift/tiers/tier_%d_qty';
|
|
|
|
public function __construct(
|
|
private readonly ScopeConfigInterface $scopeConfig,
|
|
private readonly TimezoneInterface $timezone,
|
|
private readonly Json $serializer
|
|
) {
|
|
}
|
|
|
|
public function isEnabled(?int $storeId = null): bool
|
|
{
|
|
return $this->scopeConfig->isSetFlag(
|
|
self::XML_PATH_ENABLED,
|
|
ScopeInterface::SCOPE_STORE,
|
|
$storeId
|
|
);
|
|
}
|
|
|
|
public function getGiftSku(?int $storeId = null): string
|
|
{
|
|
return trim((string)$this->scopeConfig->getValue(
|
|
self::XML_PATH_GIFT_SKU,
|
|
ScopeInterface::SCOPE_STORE,
|
|
$storeId
|
|
));
|
|
}
|
|
|
|
public function isGiftSku(string $sku, ?int $storeId = null): bool
|
|
{
|
|
$giftSku = $this->getGiftSku($storeId);
|
|
|
|
return $giftSku !== '' && strcasecmp($giftSku, trim($sku)) === 0;
|
|
}
|
|
|
|
public function isActive(?int $storeId = null): bool
|
|
{
|
|
if (!$this->isEnabled($storeId) || $this->getGiftSku($storeId) === '') {
|
|
return false;
|
|
}
|
|
|
|
$today = $this->timezone->scopeDate($storeId)->format('Y-m-d');
|
|
$startDate = $this->normalizeDate($this->getValue(self::XML_PATH_START_DATE, $storeId));
|
|
$endDate = $this->normalizeDate($this->getValue(self::XML_PATH_END_DATE, $storeId));
|
|
|
|
return ($startDate === '' || $today >= $startDate)
|
|
&& ($endDate === '' || $today <= $endDate);
|
|
}
|
|
|
|
public function getTargetQuantity(float $eligibleBaseSubtotal, ?int $storeId = null): int
|
|
{
|
|
if (!$this->isActive($storeId)) {
|
|
return 0;
|
|
}
|
|
|
|
$targetQuantity = 0;
|
|
$subtotal = round(max(0.0, $eligibleBaseSubtotal), 2);
|
|
|
|
foreach ($this->getTiers($storeId) as $tier) {
|
|
if ($subtotal + 0.0001 >= $tier['amount']) {
|
|
$targetQuantity = $tier['qty'];
|
|
}
|
|
}
|
|
|
|
return $targetQuantity;
|
|
}
|
|
|
|
/** @return array<int, array{amount: float, qty: int}> */
|
|
public function getTiers(?int $storeId = null): array
|
|
{
|
|
$configuredTiers = $this->getConfiguredTiers($storeId);
|
|
if ($configuredTiers !== []) {
|
|
return $configuredTiers;
|
|
}
|
|
|
|
$tiers = [];
|
|
|
|
for ($index = 1; $index <= 3; $index++) {
|
|
$amount = max(0.0, (float)$this->getValue(sprintf(self::XML_PATH_TIER_AMOUNT, $index), $storeId));
|
|
$quantity = max(0, (int)$this->getValue(sprintf(self::XML_PATH_TIER_QTY, $index), $storeId));
|
|
|
|
if ($quantity > 0) {
|
|
$tiers[] = ['amount' => $amount, 'qty' => $quantity];
|
|
}
|
|
}
|
|
|
|
usort(
|
|
$tiers,
|
|
static fn (array $left, array $right): int => $left['amount'] <=> $right['amount']
|
|
);
|
|
|
|
return $tiers;
|
|
}
|
|
|
|
/** @return array<int, array{amount: float, qty: int}> */
|
|
private function getConfiguredTiers(?int $storeId): array
|
|
{
|
|
$value = $this->scopeConfig->getValue(
|
|
self::XML_PATH_TIER_ITEMS,
|
|
ScopeInterface::SCOPE_STORE,
|
|
$storeId
|
|
);
|
|
|
|
try {
|
|
$items = is_array($value)
|
|
? $value
|
|
: (trim((string)$value) === '' ? [] : $this->serializer->unserialize((string)$value));
|
|
} catch (\InvalidArgumentException) {
|
|
return [];
|
|
}
|
|
|
|
if (!is_array($items)) {
|
|
return [];
|
|
}
|
|
|
|
$tiers = [];
|
|
foreach ($items as $item) {
|
|
if (!is_array($item)) {
|
|
continue;
|
|
}
|
|
|
|
$quantity = max(0, (int)($item['qty'] ?? 0));
|
|
if ($quantity <= 0) {
|
|
continue;
|
|
}
|
|
|
|
$tiers[] = [
|
|
'amount' => max(0.0, (float)($item['amount'] ?? 0)),
|
|
'qty' => $quantity,
|
|
];
|
|
}
|
|
|
|
usort($tiers, static fn (array $left, array $right): int => $left['amount'] <=> $right['amount']);
|
|
|
|
return $tiers;
|
|
}
|
|
|
|
private function getValue(string $path, ?int $storeId = null): string
|
|
{
|
|
return trim((string)$this->scopeConfig->getValue(
|
|
$path,
|
|
ScopeInterface::SCOPE_STORE,
|
|
$storeId
|
|
));
|
|
}
|
|
|
|
private function normalizeDate(string $value): string
|
|
{
|
|
if ($value === '') {
|
|
return '';
|
|
}
|
|
|
|
$timestamp = strtotime($value);
|
|
|
|
return $timestamp === false ? '' : date('Y-m-d', $timestamp);
|
|
}
|
|
}
|