get($name, false); } /** * مقدار setting؛ اگر نبود از config/price_providers.php یا default پارامتر. */ public function get(string $key, $default = null) { $row = Setting::where('key', $key)->first(); if ($row !== null && $row->is_active && $row->value !== null && $row->value !== '') { return $row->value; } $fromFile = config("price_providers.{$key}"); return $fromFile !== null ? $fromFile : $default; } public function getString(string $key, string $default = ''): string { $value = $this->get($key, $default); return trim((string) ($value === false ? $default : $value)); } public function getBool(string $key, bool $default = false): bool { $value = $this->get($key, $default); if ($value === false || $value === null || $value === '') { return $default; } return filter_var($value, FILTER_VALIDATE_BOOLEAN); } public function getInt(string $key, int $default = 0): int { $value = $this->get($key, $default); return (int) ($value === false || $value === null || $value === '' ? $default : $value); } /** X-Client-Id برای API خارجی (HMAC) — اول settings، بعد .env NODE_CLIENT_ID */ public function nodeClientId(): string { $fromDb = $this->getString('node_client_id', ''); return $fromDb !== '' ? $fromDb : (string) env('NODE_CLIENT_ID', ''); } /** کلید امضای HMAC — اول settings، بعد .env NODE_SHARED_SECRET */ public function nodeSharedSecret(): string { $fromDb = $this->getString('node_shared_secret', ''); return $fromDb !== '' ? $fromDb : (string) env('NODE_SHARED_SECRET', ''); } /** اختلاف خرید نمایش (/api/price/last) — fee_single / buy_fee */ public function displayBuySpreadRial(): float { $feeSingle = (float) $this->get('fee_single', 0); $buyFee = (float) $this->get('buy_fee', $feeSingle); return $buyFee > 0 ? $buyFee : $feeSingle; } /** اختلاف فروش نمایش — fee_single / sell_fee */ public function displaySellSpreadRial(): float { $feeSingle = (float) $this->get('fee_single', 0); $sellFee = (float) $this->get('sell_fee', $feeSingle); return $sellFee > 0 ? $sellFee : $feeSingle; } /** * تنها منبع فعال قیمت — montzar | taban_gohar | main_product | zaarbox * * اولویت: * 1) price_provider (یا price_primary_source قدیمی) * 2) montzar_price=true → montzar (ابشده خانگی و پروژه‌های فعلی) * 3) پیش‌فرض فایل: montzar */ public function priceProvider(): string { foreach (['price_provider', 'price_primary_source'] as $key) { $explicit = strtolower($this->getString($key, '')); if (in_array($explicit, self::PRICE_PROVIDERS, true)) { return $explicit; } } if ($this->getBool('montzar_price', false)) { return 'montzar'; } $default = strtolower((string) config('price_providers.price_provider', 'montzar')); return in_array($default, self::PRICE_PROVIDERS, true) ? $default : 'montzar'; } /** * محصولات متصل به کیف اصلی — setting `main_wallet_products`. * مقدار: idها با کاما (مثل «13,25») یا آرایه JSON (مثل «[13,25]»). * موجودی این محصولات = gold کیف اصلی (دارایی جدا ندارند). * فقط opt-in: اگر ست نباشد آرایه خالی برمی‌گردد و رفتار قبلی حفظ می‌شود. */ public function mainWalletProductIds(): array { $raw = trim($this->getString('main_wallet_products', '')); if ($raw === '') { return []; } $decoded = json_decode($raw, true); $parts = is_array($decoded) ? $decoded : explode(',', $raw); $ids = []; foreach ($parts as $part) { $id = (int) trim((string) $part); if ($id > 0) { $ids[] = $id; } } return array_values(array_unique($ids)); } public function isMainWalletProduct(int $productId): bool { return in_array($productId, $this->mainWalletProductIds(), true); } /** * شناسه محصول آبشده: اول settings، بعد const. * مقدار settings می‌تواند id عددی (مثل 13) یا reading_method (مثل estjt_...) باشد. */ public function mainProductId(): ?int { $product = $this->mainProduct(); return $product?->id; } public function mainProduct(): ?Product { foreach ([$this->getString('main_product', ''), (string) (Cnt::where('key', 'main_product')->value('value') ?? '')] as $raw) { $raw = trim($raw); if ($raw === '') { continue; } if (is_numeric($raw)) { $product = Product::find((int) $raw); if ($product) { return $product; } } $byMethod = Product::where('reading_method', $raw)->first(); if ($byMethod) { return $byMethod; } } return null; } /** @deprecated از priceProvider() استفاده کن */ public function pricePrimarySource(): string { $provider = $this->priceProvider(); return in_array($provider, ['montzar'], true) ? $provider : 'montzar'; } public function usesMontzarPricing(): bool { return $this->priceProvider() === 'montzar'; } /** @deprecated منبع etehadie حذف شده */ public function usesEtehadiePricing(): bool { return false; } public function usesMainProductPricing(): bool { return $this->priceProvider() === 'main_product'; } public function usesZaarboxPricing(): bool { return $this->priceProvider() === 'zaarbox'; } public function UpdateConfig($name, $value) { return Setting::updateOrCreate( ['key' => $name], ['value' => $value] ); } public function trackDailyPriceExtreme(float $price): void { if ($price <= 0) { return; } $upSetting = Setting::where('key', 'up_price')->first(); $downSetting = Setting::where('key', 'down_price')->first(); if (!$upSetting || !$downSetting) { return; } $priceInt = (int) round($price); $today = now()->toDateString(); $extremeDate = $this->Config('price_extreme_date'); if ($extremeDate !== $today) { $this->UpdateConfig('up_price', $priceInt); $this->UpdateConfig('down_price', $priceInt); $this->UpdateConfig('price_extreme_date', $today); return; } $currentUp = (float) ($upSetting->value ?: 0); $currentDown = (float) ($downSetting->value ?: 0); if ($currentUp <= 0 || $priceInt > $currentUp) { $this->UpdateConfig('up_price', $priceInt); } if ($currentDown <= 0 || $priceInt < $currentDown) { $this->UpdateConfig('down_price', $priceInt); } } }