From 85988bc21280aafd3313db3070e58e2e97173a27 Mon Sep 17 00:00:00 2001 From: adonis Date: Wed, 10 Jun 2026 18:38:01 +0330 Subject: [PATCH] added merge wallet 5 --- app/Console/Commands/SyncProductPrices.php | 3 +- .../Controllers/Admin/ProductController.php | 85 +---------- app/Services/ProductPriceSyncService.php | 12 +- app/Services/ZaarboxPriceService.php | 139 +++++++++++++++--- routes/web.php | 2 +- 5 files changed, 134 insertions(+), 107 deletions(-) diff --git a/app/Console/Commands/SyncProductPrices.php b/app/Console/Commands/SyncProductPrices.php index 16a7333..81e1198 100644 --- a/app/Console/Commands/SyncProductPrices.php +++ b/app/Console/Commands/SyncProductPrices.php @@ -13,7 +13,8 @@ class SyncProductPrices extends Command public function handle(ProductPriceSyncService $syncService): int { - $syncService->syncAll(); + // کران: همیشه فید تازه از zaarbox + $syncService->syncAll(true); return self::SUCCESS; } diff --git a/app/Http/Controllers/Admin/ProductController.php b/app/Http/Controllers/Admin/ProductController.php index 96cbbb5..287b50d 100644 --- a/app/Http/Controllers/Admin/ProductController.php +++ b/app/Http/Controllers/Admin/ProductController.php @@ -151,8 +151,9 @@ class ProductController extends SuperController public function listProduct() { -// $this->getPrice(); -// $this->auto_close_open(); + // قبل از برگرداندن لیست: قیمت محصولات متغیر از فید zaarbox (با کش کوتاه) sync شود + app(\App\Services\ProductPriceSyncService::class)->syncAll(false); + $products = Product::with(['file'])->where('active', 1)->get(); if (Product::hasPriceOffsetColumn() && str_contains(request()->path(), '/customer/')) { @@ -168,85 +169,7 @@ class ProductController extends SuperController public function getPrice() { -// $RPrices =Http::timeout(40)->get('http://212.23.201.173:8381/price_list', [])->json(); - $RPrices = Http::timeout(40)->get('http://109.122.246.48:4949/api/free', [])->json(); - -// try{ -// $cooper =Http::timeout(40)->get('https://www.livedata.ir/main/static/p.json', [])->json(); -// if(isset($cooper['s_301006']) && isset($cooper['s_200103'])){ -// $CP = (($cooper['s_301006']/1000000)*$cooper['s_200103'])*10; -//// Cnt::where('key', 'cu_price') -// } -// }catch (\Exception $e){} - - $config = app(ConfigService::class); - $mainProductId = app(ConfigService::class)->mainProductId(); - $hasExtremeKeys = Setting::whereIn('key', ['up_price', 'down_price'])->count() === 2; - $products = Product::with([])->whereNotNull('reading_method')->get(); - foreach ($products as $product) { - $collection = collect($RPrices); - $RPrice = $collection->firstWhere('key', $product->reading_method); - if (!empty($RPrice)) { -// foreach ($RPrices as $RPrice) { -// if ($product->reading_method == $RPrice['name']) { - if ($RPrice['name'] == 'TGJU فلز مس') { - $copper = $RPrice['price'] + $RPrice['profit']; - } - if ($RPrice['name'] == 'TGJU دلار') { - $dollar = $RPrice['price'] + $RPrice['profit']; - } - if ($RPrice['name'] == 'گلد دات ای از آبشده - رسمی - نقد فردا') { - $RPrice['price'] = $RPrice['price'] / 4.3318; - } - ProductPriceService::syncFromReference( - $product, - (int) $RPrice['price'], - (int) ($RPrice['profit'] ?? 0) - ); - $productPrice = (float) ProductPriceService::adjustedTotal( - (int) $RPrice['price'], - (int) ($RPrice['profit'] ?? 0), - ProductPriceService::offsetPercent($product) - ); - if ( - $hasExtremeKeys - && $mainProductId - && (int) $product->id === (int) $mainProductId - ) { - $config->trackDailyPriceExtreme($productPrice); - } - - if ($product->bubble == 1) { - $ReportController = new ReportController(); - $liquidGold = $ReportController->lastPrice(); - $p = Product::find($product->id); - $p->amount = $RPrice['price'] / $liquidGold['price']; - $p->save(); - - } - } - } - if (isset($copper) && isset($dollar)) { - $cp = (int) round(($copper / 1000000) * $dollar); - $copperProducts = Product::where('metal_id', 3)->get(); - foreach ($copperProducts as $copperProduct) { - ProductPriceService::syncFromReference($copperProduct, $cp, 0); - } - Product::where('metal_id', 3)->update([ - 'updated_at' => \Carbon\Carbon::now()->format('Y-m-d H:i:s'), - ]); - if ( - $hasExtremeKeys - && $mainProductId - && Product::where('id', $mainProductId)->where('metal_id', 3)->exists() - ) { - $mainCopper = Product::find($mainProductId); - $extremePrice = $mainCopper - ? (float) ($mainCopper->price + ($mainCopper->price_profit ?? 0)) - : (float) $cp; - $config->trackDailyPriceExtreme($extremePrice); - } - } + app(\App\Services\ProductPriceSyncService::class)->syncAll(true); return response()->json(true); } diff --git a/app/Services/ProductPriceSyncService.php b/app/Services/ProductPriceSyncService.php index 8bc10d2..96aef30 100644 --- a/app/Services/ProductPriceSyncService.php +++ b/app/Services/ProductPriceSyncService.php @@ -8,16 +8,22 @@ use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; /** - * همگام‌سازی قیمت محصولاتی که reading_method دارند (قیمت متغیر از API). + * همگام‌سازی قیمت محصولات متغیر از فید zaarbox و فید قدیمی. */ class ProductPriceSyncService { - public function syncAll(): bool + public function __construct( + private readonly ZaarboxPriceService $zaarboxPriceService + ) { + } + + /** @param bool $forceRefresh درخواست تازه از https://price.zaarbox.ir/api/free (کران) */ + public function syncAll(bool $forceRefresh = false): bool { $synced = false; try { - if (app(ZaarboxPriceService::class)->syncProductsFromApi()) { + if ($this->zaarboxPriceService->syncProductsFromApi($forceRefresh)) { $synced = true; } } catch (\Throwable $e) { diff --git a/app/Services/ZaarboxPriceService.php b/app/Services/ZaarboxPriceService.php index 49b9184..30eb944 100644 --- a/app/Services/ZaarboxPriceService.php +++ b/app/Services/ZaarboxPriceService.php @@ -3,6 +3,7 @@ namespace App\Services; use App\Models\Product; +use App\Models\Setting; use Carbon\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; @@ -13,8 +14,14 @@ class ZaarboxPriceService { public const CACHE_KEY = 'zaarbox_gold_prices'; + /** کش فید تابلو — کران و list محصولات از همین استفاده می‌کنند */ + public const PRICE_LIST_CACHE_KEY = 'zaarbox_price_list_feed'; + private const CACHE_TTL_MINUTES = 35; + /** حداکثر فاصلهٔ استفاده مجدد از فید بدون درخواست جدید (ثانیه) */ + private const PRICE_LIST_CACHE_SECONDS = 25; + private const DEFAULT_HISTORY_ID = 'ca3800a0-1f57-3528-b963-178f9168e04f'; private const PERIODS = [ @@ -167,6 +174,30 @@ class ZaarboxPriceService } } + /** + * فید تابلو با کش کوتاه — کران هر ۳۰ث refresh می‌کند؛ list در بازهٔ کش همان فید را مصرف می‌کند. + * + * @return array>|null + */ + public function cachedPriceList(bool $forceRefresh = false): ?array + { + if ($forceRefresh) { + Cache::forget(self::PRICE_LIST_CACHE_KEY); + } + + $cached = Cache::get(self::PRICE_LIST_CACHE_KEY); + if (is_array($cached)) { + return $cached; + } + + $prices = $this->fetchPriceList(); + if ($prices !== null) { + Cache::put(self::PRICE_LIST_CACHE_KEY, $prices, now()->addSeconds(self::PRICE_LIST_CACHE_SECONDS)); + } + + return $prices; + } + /** * @return array */ @@ -228,52 +259,120 @@ class ZaarboxPriceService } } - public function syncProductsFromApi(): bool + public function syncProductsFromApi(bool $forceRefresh = false): bool { - $prices = $this->fetchPriceList(); + if (!Product::hasStoredPriceColumns()) { + return false; + } + + $prices = $this->cachedPriceList($forceRefresh); if ($prices === null) { return false; } - $products = Product::with([])->whereNotNull('reading_method')->get(); + return $this->applyPriceFeedToProducts($prices); + } + + /** + * اعمال فید zaarbox روی محصولات متغیر (reading_method) + مس محاسباتی + bubble + مظنه. + * + * @param array> $prices + */ + public function applyPriceFeedToProducts(array $prices): bool + { + $config = $this->config; + $mainProductId = $config->mainProductId(); + $hasExtremeKeys = Setting::whereIn('key', ['up_price', 'down_price'])->count() === 2; $collection = collect($prices); $copper = null; $dollar = null; + $products = Product::query()->whereNotNull('reading_method')->get(); + $currentTime = now()->format('H:i:s'); + foreach ($products as $product) { $RPrice = $collection->firstWhere('key', $product->reading_method); if (empty($RPrice)) { continue; } - if (($RPrice['name'] ?? '') === 'TGJU فلز مس') { - $copper = ($RPrice['price'] ?? 0) + ($RPrice['profit'] ?? 0); + $row = $this->normalizeFeedRow($RPrice); + + if (($row['name'] ?? '') === 'TGJU فلز مس') { + $copper = ($row['price'] ?? 0) + ($row['profit'] ?? 0); } - if (($RPrice['name'] ?? '') === 'TGJU دلار') { - $dollar = ($RPrice['price'] ?? 0) + ($RPrice['profit'] ?? 0); - } - if (($RPrice['name'] ?? '') === 'گلد دات ای از آبشده - رسمی - نقد فردا') { - $RPrice['price'] = ($RPrice['price'] ?? 0) / 4.3318; + if (($row['name'] ?? '') === 'TGJU دلار') { + $dollar = ($row['price'] ?? 0) + ($row['profit'] ?? 0); } ProductPriceService::syncFromReference( $product, - (int) $RPrice['price'], - (int) ($RPrice['profit'] ?? 0) + (int) $row['price'], + (int) ($row['profit'] ?? 0) ); + + $productPrice = (float) ProductPriceService::adjustedTotal( + (int) $row['price'], + (int) ($row['profit'] ?? 0), + ProductPriceService::offsetPercent($product) + ); + + if ( + $hasExtremeKeys + && $mainProductId + && (int) $product->id === (int) $mainProductId + ) { + $config->trackDailyPriceExtreme($productPrice); + } + + if ((int) ($product->bubble ?? 0) === 1) { + $liquidGold = app(\App\Http\Controllers\Site\ReportController::class)->lastPrice(); + $p = Product::find($product->id); + if ($p && ($liquidGold['price'] ?? 0) > 0) { + $show = ($currentTime >= $product->auto_open_at && $currentTime <= $product->auto_close_at); + $p->amount = $row['price'] / $liquidGold['price']; + $p->show = $show; + $p->save(); + } + } } if ($copper !== null && $dollar !== null) { - $cp = ($copper / 1000000) * $dollar; - $copperProduct = Product::find(33); - if ($copperProduct) { - ProductPriceService::syncFromReference($copperProduct, (int) round($cp), 0); + $cp = (int) round(($copper / 1000000) * $dollar); + $copperProducts = Product::where('metal_id', 3)->get(); + foreach ($copperProducts as $copperProduct) { + ProductPriceService::syncFromReference($copperProduct, $cp, 0); + } + Product::where('metal_id', 3)->update([ + 'updated_at' => Carbon::now()->format('Y-m-d H:i:s'), + ]); + + if ( + $hasExtremeKeys + && $mainProductId + && Product::where('id', $mainProductId)->where('metal_id', 3)->exists() + ) { + $mainCopper = Product::find($mainProductId); + $extremePrice = $mainCopper + ? (float) ($mainCopper->price + ($mainCopper->price_profit ?? 0)) + : (float) $cp; + $config->trackDailyPriceExtreme($extremePrice); } } return true; } + /** @param array $row */ + private function normalizeFeedRow(array $row): array + { + if (($row['name'] ?? '') === 'گلد دات ای از آبشده - رسمی - نقد فردا') { + $row['price'] = ($row['price'] ?? 0) / 4.3318; + } + + return $row; + } + public function syncProductFromApi(Product $product): bool { if (!Product::hasStoredPriceColumns()) { @@ -294,14 +393,12 @@ class ZaarboxPriceService return false; } - if (($RPrice['name'] ?? '') === 'گلد دات ای از آبشده - رسمی - نقد فردا') { - $RPrice['price'] = ($RPrice['price'] ?? 0) / 4.3318; - } + $row = $this->normalizeFeedRow($RPrice); ProductPriceService::syncFromReference( $product, - (int) $RPrice['price'], - (int) ($RPrice['profit'] ?? 0) + (int) $row['price'], + (int) ($row['profit'] ?? 0) ); return true; diff --git a/routes/web.php b/routes/web.php index 99f1892..0a4c940 100644 --- a/routes/web.php +++ b/routes/web.php @@ -16,7 +16,7 @@ use App\Models\Message; use Illuminate\Http\Request; Route::get('/refPricer', function () { - $ok = app(\App\Services\ZaarboxPriceService::class)->syncProductsFromApi(); + $ok = app(\App\Services\ProductPriceSyncService::class)->syncAll(true); return response()->json($ok); });