Files
boursecu_server/app/Services/ProductDisplayPriceService.php
T
2026-06-11 16:41:28 +03:30

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