Files
esun3d/app/code/Esun/FreeGift/Model/Config.php
T
2026-09-15 10:35:56 +08:00

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);
}
}