diff --git a/app/Console/Commands/PriceTickCommand.php b/app/Console/Commands/PriceTickCommand.php new file mode 100644 index 0000000..9fa71f1 --- /dev/null +++ b/app/Console/Commands/PriceTickCommand.php @@ -0,0 +1,20 @@ +tick(); + + return self::SUCCESS; + } +} diff --git a/app/Console/Commands/PrunePriceSnapshotsCommand.php b/app/Console/Commands/PrunePriceSnapshotsCommand.php new file mode 100644 index 0000000..751d9c1 --- /dev/null +++ b/app/Console/Commands/PrunePriceSnapshotsCommand.php @@ -0,0 +1,21 @@ +pruneHistory(); + $this->info(json_encode($stats, JSON_UNESCAPED_UNICODE)); + + return self::SUCCESS; + } +} diff --git a/app/Console/Commands/SyncProductPrices.php b/app/Console/Commands/SyncProductPrices.php index 6db79a6..d741b26 100644 --- a/app/Console/Commands/SyncProductPrices.php +++ b/app/Console/Commands/SyncProductPrices.php @@ -2,19 +2,18 @@ namespace App\Console\Commands; -use App\Services\ProductPriceSyncService; +use App\Services\LivePriceTickService; use Illuminate\Console\Command; class SyncProductPrices extends Command { protected $signature = 'product:sync-prices'; - protected $description = 'Fetch zaarbox price board + sync product DB (scheduler: every 30s)'; + protected $description = 'Alias for prices:tick (backward compatible cron)'; - public function handle(ProductPriceSyncService $syncService): int + public function handle(LivePriceTickService $tickService): int { - // کران: GET https://price.zaarbox.ir/api/free (یا zaarbox_api_url) → کش + UPDATE محصولات - $syncService->syncAll(true); + $tickService->tick(); return self::SUCCESS; } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 1f83475..46f9cd2 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,44 +2,38 @@ namespace App\Console; -use App\Console\Commands\Price; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; class Kernel extends ConsoleKernel { protected $commands = [ - Price::class, + Commands\Price::class, ]; - /** - * Define the application's command schedule. - * - * @param \Illuminate\Console\Scheduling\Schedule $schedule - * @return void - */ + protected function schedule(Schedule $schedule) { - // همگام‌سازی قیمت محصولات متغیر (reading_method) — هر ۳۰ ثانیه + // تیک قیمت — هر ۱۰ ثانیه (۶ بار در دقیقه) $schedule->call(function () { - for ($i = 0; $i < 2; $i++) { - \Illuminate\Support\Facades\Artisan::call('product:sync-prices'); - if ($i < 1) { - sleep(30); + for ($i = 0; $i < 6; $i++) { + \Illuminate\Support\Facades\Artisan::call('prices:tick'); + if ($i < 5) { + sleep(10); } } - })->everyMinute()->name('sync_product_prices_30s')->withoutOverlapping(); + })->everyMinute()->name('prices_tick_10s')->withoutOverlapping(); $schedule->command('prices:refresh-zaarbox') ->everyThirtyMinutes() ->name('refresh_zaarbox_prices') ->withoutOverlapping(); + + // پاک‌سازی و downsample تاریخچه — ساعت ۱۲ شب + $schedule->command('prices:prune') + ->dailyAt('00:00') + ->name('prune_price_snapshots'); } - /** - * Register the commands for the application. - * - * @return void - */ protected function commands() { $this->load(__DIR__.'/Commands'); diff --git a/app/Http/Controllers/Admin/PriceSyncLogController.php b/app/Http/Controllers/Admin/PriceSyncLogController.php index 7ff8754..cbeda4f 100644 --- a/app/Http/Controllers/Admin/PriceSyncLogController.php +++ b/app/Http/Controllers/Admin/PriceSyncLogController.php @@ -5,7 +5,7 @@ namespace App\Http\Controllers\Admin; use App\DB\Te\TableEngine; use App\Http\Controllers\Controller; use App\Models\PriceSyncLog; -use App\Services\ProductPriceSyncService; +use App\Services\LivePriceTickService; use Illuminate\Http\Request; class PriceSyncLogController extends Controller @@ -29,14 +29,14 @@ class PriceSyncLogController extends Controller return response()->json($log); } - public function runSync(ProductPriceSyncService $syncService) + public function runSync(LivePriceTickService $tickService) { - $syncService->syncStorePrices(true); + $tickService->tick(); $log = PriceSyncLog::with('items')->orderByDesc('id')->first(); return response()->json([ - 'message' => $log ? 'قیمت‌ها به‌روزرسانی شد' : 'تغییری در قیمت محصولات نبود', + 'message' => $log ? 'قیمت‌ها به‌روزرسانی شد' : 'همگام‌سازی انجام شد', 'data' => $log, ]); } diff --git a/app/Http/Controllers/Admin/ProductController.php b/app/Http/Controllers/Admin/ProductController.php index dc4044a..228f165 100644 --- a/app/Http/Controllers/Admin/ProductController.php +++ b/app/Http/Controllers/Admin/ProductController.php @@ -175,15 +175,12 @@ class ProductController extends SuperController return response()->json($products); } - // آبشده خانگی — ادمین: sync از کش؛ کاربر: enrich بدون UPDATE - if (! str_contains(request()->path(), '/customer/')) { - app(ProductPriceSyncService::class)->syncAll(false); - } - + // آبشده خانگی — کران قیمت را آپدیت می‌کند؛ list فقط از DB می‌خواند $products = Product::with(['file'])->where('active', 1)->get(); if (str_contains(request()->path(), '/customer/')) { $displayPriceService = app(ProductDisplayPriceService::class); + $displayPriceService->warmLivePriceCache(); $displayPriceService->enrichForApi($products); $products->each(function (Product $product) use ($displayPriceService) { if (! $displayPriceService->hasCustomerDisplayPrice($product)) { diff --git a/app/Http/Controllers/Site/ReportController.php b/app/Http/Controllers/Site/ReportController.php index fb5b7d2..9b840e4 100644 --- a/app/Http/Controllers/Site/ReportController.php +++ b/app/Http/Controllers/Site/ReportController.php @@ -21,6 +21,7 @@ use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Mail; use Morilog\Jalali\Jalalian; use App\Services\ConfigService; +use App\Services\LivePriceCacheService; use App\Services\ProductDisplayPriceService; @@ -127,15 +128,37 @@ class ReportController extends Controller $payload['last_historical'] = app(ProductDisplayPriceService::class)->resolveHistoricalBasePrice(); app(ProductDisplayPriceService::class)->cacheLivePricePayload($payload); + if (request()->boolean('force_refresh')) { + return app(LivePriceCacheService::class)->put($payload); + } + return $payload; } - public function lastPrice() + public function lastPrice(Request $request) { $config = app(ConfigService::class); + $cache = app(LivePriceCacheService::class); + + if (! $request->boolean('force_refresh')) { + $cached = $cache->get(); + if ($cached !== null) { + return $cached; + } + + $dbBuilt = $cache->buildFromDatabase(); + if (($dbBuilt['price'] ?? 0) > 0) { + return $dbBuilt; + } + } if ($config->isStore()) { - return $this->storeLastPrice($config); + return $this->appendUpPrices(array_merge([ + 'closed' => false, + 'time' => now(), + 'main_product' => 0, + 'zaarbox' => 0, + ], $this->storeLastPrice($config))); } $closed = false; @@ -361,24 +384,14 @@ class ReportController extends Controller } if ($priceValue <= 0) { - if (!$show_last_price) { - return $this->appendUpPrices([ - 'sell' => 0, - 'buy' => 0, - 'price_last' => 0, - 'price' => 0, - 'main_product' => $pr_price ?? 0, - 'montzar' => $montzar_price ?? 0, - 'zaarbox' => $zaarbox_price ?? 0, - 'closed' => true, - 'time' => now(), - ]); - } - $lastPrice = Price::latest()->first(); $storedPrice = $lastPrice ? (float) $lastPrice->price : 0.0; + $useFallback = $request->boolean('force_refresh') || $show_last_price; - if ($storedPrice <= 0) { + if ($storedPrice > 30_000_000 && $useFallback) { + $priceValue = $storedPrice; + $priceSource = 'database_last'; + } else { return $this->appendUpPrices([ 'sell' => 0, 'buy' => 0, @@ -391,9 +404,6 @@ class ReportController extends Controller 'time' => now(), ]); } - - $priceValue = $storedPrice; - $priceSource = 'database_last'; } /* @@ -406,9 +416,9 @@ class ReportController extends Controller $lastPrice = Price::latest()->first(); if ( - !$closed && - (!$lastPrice || (float) $lastPrice->price != (float) $priceToStore) && - $priceToStore > 1000000 + ! $closed && + (! $lastPrice || (float) $lastPrice->price != (float) $priceToStore) && + $priceToStore > 30_000_000 ) { $price = new Price(); $price->price = $priceToStore; diff --git a/app/Services/LivePriceCacheService.php b/app/Services/LivePriceCacheService.php new file mode 100644 index 0000000..7ad777f --- /dev/null +++ b/app/Services/LivePriceCacheService.php @@ -0,0 +1,89 @@ +diffInSeconds($cached['stored_at']) > self::TTL_SECONDS) { + return null; + } + + return $cached['body']; + } + + public function put(array $body): array + { + Cache::put(self::FULL_RESPONSE_KEY, [ + 'body' => $body, + 'stored_at' => now(), + ], now()->addSeconds(self::TTL_SECONDS + 5)); + + app(ProductDisplayPriceService::class)->cacheLivePricePayload($body); + + return $body; + } + + /** پاسخ سریع بدون API خارجی — از آخرین رکورد prices + تنظیمات */ + public function buildFromDatabase(): array + { + $config = app(ConfigService::class); + $display = app(ProductDisplayPriceService::class); + $last = Price::orderByDesc('id')->first(); + $base = $last ? (int) $last->price : 0; + + if ($base <= 0) { + $payload = [ + 'sell' => 0, + 'buy' => 0, + 'price_last' => 0, + 'price' => 0, + 'main_product' => 0, + 'montzar' => 0, + 'zaarbox' => 0, + 'closed' => true, + 'time' => now(), + ]; + } else { + $diffBuy = (int) $config->displayBuySpreadRial(); + $diffSell = (int) $config->displaySellSpreadRial(); + $buy = (int) ceil($base + $diffBuy); + $sell = max(0, (int) ceil($base - $diffSell)); + + $payload = [ + 'sell' => $sell, + 'buy' => $buy, + 'price_last' => $buy, + 'price' => $base, + 'main_product' => 0, + 'montzar' => 0, + 'zaarbox' => 0, + 'closed' => false, + 'time' => now(), + ]; + } + + $payload['up'] = $config->resolvedDailyBaseExtremes()['up'] > 0 + ? [ + 'sell' => max(0, (int) ceil($config->resolvedDailyBaseExtremes()['down'] - $config->displaySellSpreadRial())), + 'buy' => (int) ceil($config->resolvedDailyBaseExtremes()['up'] + $config->displayBuySpreadRial()), + ] + : ['sell' => $payload['sell'] ?? 0, 'buy' => $payload['buy'] ?? 0]; + $payload['last_historical'] = $display->resolveHistoricalBasePrice(); + + return $payload; + } +} diff --git a/app/Services/LivePriceTickService.php b/app/Services/LivePriceTickService.php new file mode 100644 index 0000000..d680cb4 --- /dev/null +++ b/app/Services/LivePriceTickService.php @@ -0,0 +1,48 @@ +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; + } + + $liquidGold = (int) $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); + + $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)) { + app(PriceSnapshotService::class)->recordTick($payload); + } + } +} diff --git a/app/Services/PriceSnapshotService.php b/app/Services/PriceSnapshotService.php new file mode 100644 index 0000000..529786b --- /dev/null +++ b/app/Services/PriceSnapshotService.php @@ -0,0 +1,173 @@ +first(); + if (! $last || (int) $last->price <= 30_000_000) { + return; + } + $priceValue = (int) $last->price; + } + + Price::create([ + 'price' => $priceValue, + 'date_at' => Carbon::now()->toDateString(), + 'time_at' => Carbon::now()->toTimeString(), + 'user_id' => null, + ]); + + $this->touchCandle($priceValue); + } + + private function touchCandle(int $priceValue): void + { + $candle = PriceCandle::whereDate('date_at', date('Y-m-d'))->first(); + + if ($candle) { + $candle->end = $priceValue; + if ($priceValue < $candle->low) { + $candle->low = $priceValue; + } elseif ($priceValue > $candle->high) { + $candle->high = $priceValue; + } + $candle->save(); + + return; + } + + PriceCandle::create([ + 'start' => $priceValue, + 'end' => $priceValue, + 'high' => $priceValue, + 'low' => $priceValue, + 'date_at' => date('Y-m-d'), + ]); + } + + /** + * پاک‌سازی شبانه: + * - قبل از ۳۱ روز: حذف + * - ۷ تا ۳۱ روز: هر ۱۲ ساعت یک رکورد + * - ۲۴ ساعت تا ۷ روز: هر ۳۰ دقیقه یک رکورد + * - ۲۴ ساعت اخیر: نگه‌داری همه (هر ۱۰ ثانیه) + */ + public function pruneHistory(): array + { + $deletedOld = Price::query() + ->where('created_at', '<', now()->subDays(31)) + ->delete(); + + $deleted7to31 = $this->downsampleRange(now()->subDays(31), now()->subDays(7), 12 * 3600); + $deleted1to7 = $this->downsampleRange(now()->subDays(7), now()->subDay(), 30 * 60); + + return [ + 'deleted_older_than_31d' => $deletedOld, + 'downsampled_7_to_31d' => $deleted7to31, + 'downsampled_1_to_7d' => $deleted1to7, + ]; + } + + private function downsampleRange(Carbon $from, Carbon $to, int $bucketSeconds): int + { + $rows = Price::query() + ->where('created_at', '>=', $from) + ->where('created_at', '<', $to) + ->orderBy('created_at') + ->get(['id', 'created_at']); + + if ($rows->isEmpty()) { + return 0; + } + + $keepIds = []; + $lastBucket = null; + + foreach ($rows as $row) { + $ts = $row->created_at?->timestamp ?? 0; + $bucket = (int) floor($ts / $bucketSeconds); + if ($bucket !== $lastBucket) { + $keepIds[] = $row->id; + $lastBucket = $bucket; + } else { + $keepIds[count($keepIds) - 1] = $row->id; + } + } + + return Price::query() + ->where('created_at', '>=', $from) + ->where('created_at', '<', $to) + ->whereNotIn('id', $keepIds) + ->delete(); + } + + /** @return array{DAILY: array, WEEKLY: array, MONTHLY: array} */ + public function chartFromDatabase(): array + { + $daily = Price::query() + ->where('created_at', '>=', now()->subDay()) + ->orderBy('created_at') + ->get(['price', 'created_at']); + + $dailyPoints = $daily->map(function (Price $row) { + $ts = ($row->created_at ?? now())->timestamp * 1000; + + return ['timestamp' => $ts, 'value' => (int) $row->price]; + })->values()->all(); + + $weekRows = Price::query() + ->where('created_at', '>=', now()->subDays(7)) + ->orderBy('created_at') + ->get(['id', 'price', 'created_at']); + + $weeklyPoints = $this->bucketRows($weekRows, 30 * 60); + + $monthRows = Price::query() + ->where('created_at', '>=', now()->subDays(31)) + ->orderBy('created_at') + ->get(['id', 'price', 'created_at']); + + $monthlyPoints = $this->bucketRows($monthRows, 12 * 3600); + + return [ + 'DAILY' => $dailyPoints, + 'WEEKLY' => $weeklyPoints, + 'MONTHLY' => $monthlyPoints, + ]; + } + + /** @param \Illuminate\Support\Collection $rows */ + private function bucketRows($rows, int $bucketSeconds): array + { + $points = []; + $lastBucket = null; + + foreach ($rows as $row) { + $ts = $row->created_at?->timestamp ?? 0; + $bucket = (int) floor($ts / $bucketSeconds); + $point = [ + 'timestamp' => $ts * 1000, + 'value' => (int) $row->price, + ]; + + if ($bucket !== $lastBucket) { + $points[] = $point; + $lastBucket = $bucket; + } else { + $points[count($points) - 1] = $point; + } + } + + return $points; + } +} diff --git a/app/Services/PriceSyncLogService.php b/app/Services/PriceSyncLogService.php index 09ec0c4..d5254f4 100644 --- a/app/Services/PriceSyncLogService.php +++ b/app/Services/PriceSyncLogService.php @@ -56,4 +56,20 @@ class PriceSyncLogService return $log->load('items'); } + + /** هر تیک کران — حتی بدون تغییر قیمت محصول */ + public function recordTick(string $source, ?string $sourceUrl, int $liquidGoldPrice, int $productsSynced): ?PriceSyncLog + { + if (! $this->isAvailable()) { + return null; + } + + return PriceSyncLog::create([ + 'source' => $source, + 'source_url' => $sourceUrl, + 'liquid_gold_price' => $liquidGoldPrice, + 'products_updated' => $productsSynced, + 'created_at' => now(), + ]); + } } diff --git a/app/Services/ProductDisplayPriceService.php b/app/Services/ProductDisplayPriceService.php index af46687..a1ad5d5 100644 --- a/app/Services/ProductDisplayPriceService.php +++ b/app/Services/ProductDisplayPriceService.php @@ -18,7 +18,7 @@ class ProductDisplayPriceService { public const LIVE_PRICE_CACHE_KEY = 'live_price_api_payload'; - public const LIVE_PRICE_CACHE_SECONDS = 45; + public const LIVE_PRICE_CACHE_SECONDS = 15; public function usesAppPrice(Product $product): bool { @@ -262,6 +262,18 @@ class ProductDisplayPriceService /** @param array> $feed */ private function applyReferenceFeedPrice(Product $product, array $feed, ZaarboxPriceService $zaarbox): void { + if (Product::hasStoredPriceColumns()) { + $stored = (int) ($product->price ?? 0) + (int) ($product->price_profit ?? 0); + if ($stored > 0) { + $product->setAttribute('price', (int) ($product->price ?? 0)); + if (Schema::hasColumn($product->getTable(), 'price_profit')) { + $product->setAttribute('price_profit', (int) ($product->price_profit ?? 0)); + } + + return; + } + } + $row = $zaarbox->findFeedRow($feed, (string) $product->reading_method); if ($row === null) { $useLast = $this->productUsesLastPriceIfZero($product); diff --git a/app/Services/ZaarboxPriceService.php b/app/Services/ZaarboxPriceService.php index 860281a..8c2f55d 100644 --- a/app/Services/ZaarboxPriceService.php +++ b/app/Services/ZaarboxPriceService.php @@ -20,7 +20,7 @@ class ZaarboxPriceService private const CACHE_TTL_MINUTES = 35; /** TTL کش فید — کران هر ۳۰ث refresh می‌کند؛ list فقط از همین می‌خواند */ - private const PRICE_LIST_CACHE_SECONDS = 45; + private const PRICE_LIST_CACHE_SECONDS = 15; private const DEFAULT_HISTORY_ID = 'ca3800a0-1f57-3528-b963-178f9168e04f'; @@ -90,6 +90,13 @@ class ZaarboxPriceService */ public function getAllPrices(): array { + if ($this->config->getBool('chart_use_local_data', false)) { + $local = app(PriceSnapshotService::class)->chartFromDatabase(); + if (! empty($local['DAILY'])) { + return $local; + } + } + $cached = Cache::get($this->cacheKey()); if (is_array($cached) && isset($cached['prices'])) { diff --git a/config/price_providers.php b/config/price_providers.php index 2154c50..a2ac8ae 100644 --- a/config/price_providers.php +++ b/config/price_providers.php @@ -17,6 +17,8 @@ return [ 'zaarbox_price_key' => '', /** UUID نمودار Zaarbox — خالی = پیش‌فرض ca3800a0-... در ZaarboxPriceService */ 'chart_id' => '', + /** false = نمودار از Zaarbox (chart_id) | true = داده ذخیره‌شده خود سایت */ + 'chart_use_local_data' => false, 'register_jibit_verify' => false, 'register_referral_sms_to_referrer' => false, 'register_referral_bonus_message' => false, diff --git a/database/sql/deploy_settings_const.sql b/database/sql/deploy_settings_const.sql index bdf490a..21fd88c 100644 --- a/database/sql/deploy_settings_const.sql +++ b/database/sql/deploy_settings_const.sql @@ -89,8 +89,13 @@ WHERE r.`key` = 'referral_id' -- ============================================================================= -- قیمت zaarbox (اگر از قبل دارید value دست نخورده) -INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`) -SELECT 'chart_id', '', 'UUID نمودار Zaarbox', 1, 1, 'خالی = ca3800a0-1f57-3528-b963-178f9168e04f' +INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) +SELECT 'chart_use_local_data', 'false', 'نمودار از داده خود سایت', 1, 1, + 'خاموش = Zaarbox (chart_id) | روشن = تاریخچه ذخیره‌شده prices', 'switch' +WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'chart_use_local_data' LIMIT 1); + +INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) +SELECT 'chart_id', '', 'UUID نمودار Zaarbox', 1, 1, 'خالی = ca3800a0-1f57-3528-b963-178f9168e04f', 'text' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'chart_id' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`) @@ -451,26 +456,26 @@ UPDATE `settings` SET `type` = 'longtext' WHERE `key` IN ('text_rule', 'text_abo -- select (+ گزینه‌ها در description) UPDATE `settings` SET `type` = 'select', `description` = 'منبع فعال قیمت|montzar,zaarbox,main_product' WHERE `key` = 'price_provider'; -UPDATE `settings` SET `type` = 'select', `description` = 'required = اجباری؛ خالی = اختیاری|required,', `can_edit` = 1 WHERE `key` = 'referral_id'; +UPDATE `settings` SET `type` = 'switch', `title_fa` = 'کد معرف اجباری', `description` = 'روشن = اجباری در ثبت‌نام | خاموش = اختیاری', `can_edit` = 1 WHERE `key` = 'referral_id'; UPDATE `settings` SET `type` = 'select', `description` = 'sepal,' WHERE `key` = 'payping_gateway_name'; UPDATE `settings` SET `type` = 'select', `description` = 'bale,telegram,whatsapp,rubika,eitaa,soroush' WHERE `key` = 'support_messenger'; -- switch UPDATE `settings` SET `type` = 'switch' WHERE `key` IN ( + 'chart_use_local_data', 'jibit_verification', 'register_jibit_verify', 'open_register', 'auto_active_customer', - 'close_price', 'montzar_price', 'main_product_price', 'show_last_price', + 'close_price', 'show_last_price', 'send_to_tahesab', 'profit_gold_api_enabled', 'payping_round_toman', 'payping_strict_failed_withdraw', - 'has_page_earn_money', 'has_page_fund', 'has_page_permission', 'has_page_price_trigger', - 'has_page_physical_gold', 'has_chat', 'charge_notif', 'group_sms', 'display_montzar', + 'has_page_earn_money', 'charge_notif', 'group_sms', 'montzar_closed', 'montzar_open_buy', 'montzar_open_sell', - 'product_update_price_on_list', 'product_auto_close_open_on_list', 'payping_fin_sync_enabled', - 'fee_free', 'external_order_api_enabled', 'is_store' + 'payping_fin_sync_enabled', 'external_order_api_enabled', 'is_store', + 'register_referral_sms_to_referrer', 'register_referral_bonus_message', 'price_from_nasiryan' ); -- number UPDATE `settings` SET `type` = 'number' WHERE `key` IN ( - 'fee_single', 'buy_fee', 'sell_fee', 'fee_cash', 'fee_service_charge_percentage', - 'min_withdraw', 'min_first_buy', 'minimum_sell', 'referral_count_for_gift', + 'fee_single', 'buy_fee', 'sell_fee', 'fee_cash', 'fee_service_charge_percentage', 'fee_free', + 'min_withdraw', 'min_first_buy', 'minimum_sell', 'montzar_product_id', 'balance_report_exclude_customer_id', 'gift_for_referrer', 'gift_for_referral', 'up_price', 'down_price', 'payping_fin_customer_id' ); @@ -580,10 +585,16 @@ WHERE NOT EXISTS (SELECT 1 FROM `const` WHERE `key` = 'liman' LIMIT 1); -- پاکسازی کلیدهای legacy / تست -- --------------------------------------------------------------------------- DELETE FROM `settings` WHERE `key` IN ( - 'test', 'test2', 'test22', 'test3', 'test33', 'longtest', 'longtest2', + 'test', 'test2', 'test22', 'test3', 'test33', 'longtest', 'longtest2', 'test*', 'is_requaire_referral', 'send_to_goldir', 'goldir_price', 'liman_token', 'melted_product_id', 'display_montzar', 'tabanGohar_price', 'etehadie_api_url', - 'price_method', 'price_primary_source' + 'price_method', 'price_primary_source', 'main_product_price', 'montzar_price', + 'has_page_fund', 'has_page_permission', 'has_page_price_trigger', 'has_page_physical_gold', + 'has_chat', 'product_update_price_on_list', 'product_auto_close_open_on_list', + 'referral_count_for_gift', 'store_status', + 'name_en', 'bace_url', 'server_url', 'key', 'color_primary', 'color_secondary', + 'logo_register', 'logo_login', 'title_pwa', 'title_fav', 'text_rule', 'text_about', + 'payping_gateway_item' ); DELETE FROM `const` WHERE `key` = 'log' OR `key` LIKE 'goldir%'; @@ -601,11 +612,48 @@ WHERE `key` = 'price_provider'; UPDATE `settings` SET `value` = 'montzar' WHERE `key` = 'price_provider' AND LOWER(TRIM(`value`)) IN ('taban_gohar', 'etehadie'); -UPDATE `settings` SET `description` = 'required = اجباری|required,', `title_fa` = 'کد معرف', `type` = 'select' +UPDATE `settings` SET + `type` = 'switch', + `title_fa` = 'کد معرف اجباری', + `description` = 'روشن = اجباری در ثبت‌نام | خاموش = اختیاری', + `can_edit` = 1, + `is_active` = 1 WHERE `key` = 'referral_id'; -UPDATE `settings` SET `description` = 'جایگزین: price_provider=main_product' WHERE `key` = 'main_product_price'; -UPDATE `settings` SET `description` = 'true یا price_provider=montzar' WHERE `key` = 'montzar_price'; +UPDATE `settings` SET `value` = 'required' +WHERE `key` = 'referral_id' + AND LOWER(TRIM(COALESCE(`value`, ''))) IN ('required', 'true', '1', 'yes'); + +UPDATE `settings` SET `value` = '' +WHERE `key` = 'referral_id' + AND LOWER(TRIM(COALESCE(`value`, ''))) NOT IN ('required'); + +UPDATE `settings` SET `type` = 'switch', `value` = 'false', `is_active` = 1, `can_edit` = 1 +WHERE `key` IN ('register_referral_sms_to_referrer', 'register_referral_bonus_message') + AND (`type` IS NULL OR TRIM(`type`) = '' OR `type` = 'text') + AND TRIM(COALESCE(`value`, '')) = ''; + +UPDATE `settings` SET `type` = 'switch', `is_active` = 1 +WHERE `key` IN ('register_referral_sms_to_referrer', 'register_referral_bonus_message'); + +UPDATE `settings` SET `value` = 'false' +WHERE `key` IN ('register_referral_sms_to_referrer', 'register_referral_bonus_message') + AND TRIM(COALESCE(`value`, '')) = ''; + +UPDATE `settings` SET + `type` = 'switch', + `title_fa` = 'نمودار از داده خود سایت', + `description` = 'خاموش = Zaarbox (chart_id) | روشن = تاریخچه prices', + `is_active` = 1, + `can_edit` = 1 +WHERE `key` = 'chart_use_local_data'; + +UPDATE `settings` SET `type` = 'number', `title_fa` = 'تعداد سفارش اول بدون کارمزد', `description` = 'عدد — ۰ یعنی غیرفعال' +WHERE `key` = 'fee_free'; + +-- همه تنظیمات قابل ویرایش همیشه فعال +UPDATE `settings` SET `is_active` = 1 WHERE `can_edit` = 1 AND (`is_active` IS NULL OR `is_active` = 0); + UPDATE `settings` SET `description` = 'تعداد سفارش اول بدون کارمزد' WHERE `key` = 'fee_free'; UPDATE `settings` SET `description` = 'id یا reading_method محصول آبشده' WHERE `key` = 'main_product';