159 lines
4.7 KiB
PHP
159 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Price;
|
|
use App\Models\Product;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
/**
|
|
* قیمت نمایشی محصولات آبشده با منبع «قیمت اپ» — در DB صفر است، برای API پر میشود.
|
|
*/
|
|
class ProductDisplayPriceService
|
|
{
|
|
public const LIVE_PRICE_CACHE_KEY = 'live_price_api_payload';
|
|
|
|
public const LIVE_PRICE_CACHE_SECONDS = 15;
|
|
|
|
public function usesAppPrice(Product $product): bool
|
|
{
|
|
if ($product->reading_method) {
|
|
return false;
|
|
}
|
|
|
|
if ((int) ($product->direct_price ?? 0) === 1) {
|
|
return false;
|
|
}
|
|
|
|
return $this->isMeltedTradeProduct($product);
|
|
}
|
|
|
|
public function enrichForApi(Collection|iterable $products): void
|
|
{
|
|
$needsLivePrice = false;
|
|
|
|
foreach ($products as $product) {
|
|
if ($product instanceof Product && $this->usesAppPrice($product)) {
|
|
$needsLivePrice = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$needsLivePrice) {
|
|
return;
|
|
}
|
|
|
|
$basePrice = $this->resolveAppBasePrice();
|
|
if ($basePrice <= 0) {
|
|
return;
|
|
}
|
|
|
|
foreach ($products as $product) {
|
|
if (!$product instanceof Product || !$this->usesAppPrice($product)) {
|
|
continue;
|
|
}
|
|
|
|
$offset = Product::hasPriceOffsetColumn()
|
|
? (float) ($product->price_offset_percent ?? 0)
|
|
: 0.0;
|
|
|
|
$computed = ProductPriceService::adjustedTotal($basePrice, 0, $offset);
|
|
if ($computed <= 0) {
|
|
continue;
|
|
}
|
|
|
|
$product->setAttribute('price', $computed);
|
|
if (\Illuminate\Support\Facades\Schema::hasColumn($product->getTable(), 'price_profit')) {
|
|
$product->setAttribute('price_profit', 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @param array<string, mixed> $payload */
|
|
public function cacheLivePricePayload(array $payload): void
|
|
{
|
|
Cache::put(self::LIVE_PRICE_CACHE_KEY, [
|
|
'price' => (int) ($payload['price'] ?? 0),
|
|
'buy' => (int) ($payload['buy'] ?? 0),
|
|
'sell' => (int) ($payload['sell'] ?? 0),
|
|
'price_last' => (int) ($payload['price_last'] ?? 0),
|
|
], now()->addSeconds(self::LIVE_PRICE_CACHE_SECONDS));
|
|
}
|
|
|
|
public function resolveAppBasePrice(): int
|
|
{
|
|
$payload = $this->livePricePayload();
|
|
|
|
$price = (int) ($payload['price'] ?? 0);
|
|
if ($price > 0) {
|
|
return $price;
|
|
}
|
|
|
|
$buy = (int) ($payload['buy'] ?? 0);
|
|
$sell = (int) ($payload['sell'] ?? 0);
|
|
if ($buy > 0 && $sell > 0) {
|
|
return (int) round(($buy + $sell) / 2);
|
|
}
|
|
|
|
return (int) ($payload['price_last'] ?? 0);
|
|
}
|
|
|
|
/** @return array{price: int, buy: int, sell: int, price_last: int} */
|
|
private function livePricePayload(): array
|
|
{
|
|
$cached = Cache::get(self::LIVE_PRICE_CACHE_KEY);
|
|
if (is_array($cached)) {
|
|
return $cached;
|
|
}
|
|
|
|
return $this->resolveFallbackPayload();
|
|
}
|
|
|
|
/** @return array{price: int, buy: int, sell: int, price_last: int} */
|
|
private function resolveFallbackPayload(): array
|
|
{
|
|
$config = app(ConfigService::class);
|
|
$provider = $config->priceProvider();
|
|
$price = 0;
|
|
|
|
if ($provider === 'montzar') {
|
|
$price = $config->getInt('montzar_live_price', 0);
|
|
} elseif ($provider === 'zaarbox') {
|
|
$zaarbox = app(ZaarboxPriceService::class)->fetchPrice();
|
|
$price = (int) ($zaarbox['order_price'] ?? 0);
|
|
} elseif ($provider === 'main_product') {
|
|
$main = $config->mainProduct();
|
|
if ($main) {
|
|
$price = (int) (($main->price ?? 0) + ($main->price_profit ?? 0));
|
|
}
|
|
} elseif ($provider === 'taban_gohar') {
|
|
$price = $config->getInt('taban_gohar_live_price', 0);
|
|
}
|
|
|
|
if ($price <= 0) {
|
|
$last = Price::orderByDesc('id')->first();
|
|
if ($last && (float) $last->price > 0) {
|
|
$price = (int) $last->price;
|
|
}
|
|
}
|
|
|
|
$diffBuy = (int) $config->displayBuySpreadRial();
|
|
$diffSell = (int) $config->displaySellSpreadRial();
|
|
|
|
return [
|
|
'price' => $price,
|
|
'buy' => $price > 0 ? $price + $diffBuy : 0,
|
|
'sell' => $price > 0 ? max(0, $price - $diffSell) : 0,
|
|
'price_last' => $price > 0 ? $price + $diffBuy : 0,
|
|
];
|
|
}
|
|
|
|
private function isMeltedTradeProduct(Product $product): bool
|
|
{
|
|
$group = trim((string) ($product->group_type ?? ''));
|
|
|
|
return in_array($group, ['آبشده', 'کاتد مس'], true);
|
|
}
|
|
}
|