fix price force refresh 2

This commit is contained in:
2026-06-14 12:33:29 +03:30
parent 1abddfbab8
commit db0cc5f1a6
8 changed files with 246 additions and 120 deletions
+48
View File
@@ -102,6 +102,54 @@ class ConfigService
return $sellFee > 0 ? $sellFee : $feeSingle;
}
/**
* sell / buy / price_last — یک منبع حقیقت برای lastPrice و buildFromDatabase.
*
* @param float $priceValue قیمت پایه (ریال/گرم) — از API یا DB
* @param string|null $priceSource montzar | zaarbox | main_product | database_last | null
* @param array{montzar_open_buy?:bool,montzar_open_sell?:bool} $montzarFlags فقط وقتی API تازه خوانده شده
* @return array{sell:int,buy:int,priceLast:int}
*/
public function buildTradeDisplayPrices(
float $priceValue,
?string $priceSource = null,
array $montzarFlags = []
): array {
$diffBuy = (float) $this->displayBuySpreadRial();
$diffSell = (float) $this->displaySellSpreadRial();
$feeSingle = (float) $this->get('fee_single', 0);
$openBuy = true;
$openSell = true;
if ($priceSource === 'montzar') {
$montzarProfit = (float) $this->get('montzar_diff', 0);
$finalBuyDiff = $diffBuy + $montzarProfit;
$finalSellDiff = $diffSell + $montzarProfit;
$openBuy = $montzarFlags['montzar_open_buy'] ?? $this->getBool('montzar_open_buy', true);
$openSell = $montzarFlags['montzar_open_sell'] ?? $this->getBool('montzar_open_sell', true);
$sell = $openSell ? (int) ceil($priceValue - $finalSellDiff) : 0;
$buy = $openBuy ? (int) ceil($priceValue + $finalBuyDiff) : 0;
$priceLast = (int) ceil($priceValue + $finalBuyDiff);
return compact('sell', 'buy', 'priceLast');
}
$sell = $openSell ? (int) ceil($priceValue - $feeSingle) : 0;
$buy = $openBuy ? (int) ceil($priceValue + $feeSingle) : 0;
$priceLast = (int) ceil($priceValue + $feeSingle);
$provider = $this->priceProvider();
if (in_array($provider, ['main_product', 'zaarbox'], true)) {
$sell = $openSell ? (int) ceil($priceValue - $diffSell) : 0;
$buy = $openBuy ? (int) ceil($priceValue + $diffBuy) : 0;
$priceLast = (int) ceil($priceValue + $diffBuy);
}
return compact('sell', 'buy', 'priceLast');
}
/**
* تنها منبع فعال قیمت — montzar | main_product | zaarbox
*
+20 -29
View File
@@ -37,19 +37,15 @@ class LivePriceCacheService
return $body;
}
/** پاسخ سریع بدون API خارجی — از آخرین رکورد prices + تنظیمات */
/** پاسخ سریع بدون API خارجی — از آخرین رکورد prices + تنظیمات (همان فرمول lastPrice) */
public function buildFromDatabase(): array
{
$config = app(ConfigService::class);
$display = app(ProductDisplayPriceService::class);
$last = Price::orderByDesc('id')->first();
$base = $last ? (int) $last->price : 0;
$base = $last ? (float) $last->price : 0.0;
$provider = $config->priceProvider();
$montzarPrice = 0;
$zaarboxPrice = 0;
$mainProductPrice = 0;
if ($base <= 0) {
$payload = [
'sell' => 0,
@@ -63,35 +59,32 @@ class LivePriceCacheService
'time' => now(),
];
} else {
$diffBuy = (int) $config->displayBuySpreadRial();
$diffSell = (int) $config->displaySellSpreadRial();
$openBuy = true;
$openSell = true;
$montzarSource = 0;
$zaarboxSource = 0;
$mainProductSource = 0;
$priceSource = 'database_last';
if ($provider === 'montzar') {
$montzarPrice = $config->getInt('montzar_live_price', 0) ?: $base;
$montzarDiff = (int) $config->getInt('montzar_diff', 0);
$diffBuy += $montzarDiff;
$diffSell += $montzarDiff;
$openBuy = $config->getBool('montzar_open_buy', true);
$openSell = $config->getBool('montzar_open_sell', true);
$liveMontzar = (float) $config->get('montzar_live_price', 0);
$montzarSource = (int) ($liveMontzar > 0 ? $liveMontzar : $base);
// DB از آخرین tick montzar پر شده — همان فرمول نمایش معامله
$priceSource = 'montzar';
} elseif ($provider === 'zaarbox') {
$zaarboxPrice = $base;
$zaarboxSource = (int) $base;
} elseif ($provider === 'main_product') {
$mainProductPrice = $base;
$mainProductSource = (int) $base;
}
$buy = $openBuy ? (int) ceil($base + $diffBuy) : 0;
$sell = $openSell ? max(0, (int) ceil($base - $diffSell)) : 0;
$trade = $config->buildTradeDisplayPrices($base, $priceSource);
$payload = [
'sell' => $sell,
'buy' => $buy,
'price_last' => $buy,
'price' => $base,
'main_product' => $mainProductPrice,
'montzar' => $montzarPrice,
'zaarbox' => $zaarboxPrice,
'sell' => $trade['sell'],
'buy' => $trade['buy'],
'price_last' => $trade['priceLast'],
'price' => (int) $base,
'main_product' => $mainProductSource,
'montzar' => $montzarSource,
'zaarbox' => $zaarboxSource,
'closed' => false,
'time' => now(),
];
@@ -105,8 +98,6 @@ class LivePriceCacheService
: ['sell' => $payload['sell'] ?? 0, 'buy' => $payload['buy'] ?? 0];
$payload['last_historical'] = $display->resolveHistoricalBasePrice();
$display->cacheLivePricePayload($payload);
return $payload;
}
}
+62 -27
View File
@@ -5,44 +5,79 @@ namespace App\Services;
use App\Http\Controllers\Site\ReportController;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class LivePriceTickService
{
private const LOCK_SECONDS = 25;
public function tick(): void
{
$config = app(ConfigService::class);
$sync = app(ProductPriceSyncService::class);
if ($config->isStore()) {
$sync->syncStorePrices(true);
$source = 'zaarbox';
$sourceUrl = app(ZaarboxPriceService::class)->apiUrl();
} else {
$sync->syncAll(true);
$source = $config->priceProvider() ?: 'legacy';
$sourceUrl = $source === 'zaarbox'
? app(ZaarboxPriceService::class)->apiUrl()
: null;
$lock = Cache::lock('prices:tick', self::LOCK_SECONDS);
if (! $lock->get()) {
return;
}
$liquidGold = (int) $config->getInt('montzar_live_price', 0);
if ($liquidGold <= 0) {
$liquidGold = app(ProductDisplayPriceService::class)->resolveHistoricalBasePrice();
}
try {
$config = app(ConfigService::class);
$sync = app(ProductPriceSyncService::class);
$zaarbox = app(ZaarboxPriceService::class);
$activeProducts = Product::query()
->where('active', 1)
->whereNotNull('reading_method')
->count();
/*
| ۱. montzar / zaarbox زنده + کش ۱۵ثانیه‌ای /api/price/last
| (قبل از sync محصولات تا آبشدهٔ «قیمت اپ» تازه باشد)
*/
$request = Request::create('/api/price/last', 'GET', ['force_refresh' => '1']);
$response = app(ReportController::class)->lastPrice($request);
$payload = json_decode($response->getContent(), true);
if (! is_array($payload)) {
$payload = [];
}
app(PriceSyncLogService::class)->recordTick($source, $sourceUrl, $liquidGold, $activeProducts);
/*
| ۲. فید zaarbox برای محصولات متغیر (reading_method)
*/
if ($zaarbox->isEnabled() || Product::query()->whereNotNull('reading_method')->exists()) {
try {
$zaarbox->cachedPriceList(true);
} catch (\Throwable $e) {
Log::warning('Zaarbox feed refresh in tick failed', ['message' => $e->getMessage()]);
}
}
$request = Request::create('/api/price/last', 'GET', ['force_refresh' => '1']);
$response = app(ReportController::class)->lastPrice($request);
$payload = json_decode($response->getContent(), true);
/*
| ۳. همگام‌سازی قیمت محصولات
*/
if ($config->isStore()) {
$sync->syncStorePrices(true);
$source = 'zaarbox';
$sourceUrl = $zaarbox->apiUrl();
} else {
$sync->syncAll(true);
$source = $config->priceProvider() ?: 'legacy';
$sourceUrl = $source === 'zaarbox'
? $zaarbox->apiUrl()
: null;
}
if (is_array($payload)) {
app(PriceSnapshotService::class)->recordTick($payload);
$liquidGold = (int) ($payload['price'] ?? $config->getInt('montzar_live_price', 0));
if ($liquidGold <= 0) {
$liquidGold = app(ProductDisplayPriceService::class)->resolveHistoricalBasePrice();
}
$activeProducts = Product::query()
->where('active', 1)
->whereNotNull('reading_method')
->count();
app(PriceSyncLogService::class)->recordTick($source, $sourceUrl, $liquidGold, $activeProducts);
if ($payload !== []) {
app(PriceSnapshotService::class)->recordTick($payload);
}
} finally {
$lock->release();
}
}
}