2026-08-18 16:10:37 +03:30
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
2026-08-22 18:06:35 +03:30
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
|
|
2026-08-18 16:10:37 +03:30
|
|
|
/**
|
2026-08-19 22:02:10 +03:30
|
|
|
* تنظیمات پیشرفته سوپرادمین برای ConfigService و get_settings.
|
2026-08-22 18:06:35 +03:30
|
|
|
* در هر درخواست یک بار fetch میشود؛ آخرین پاسخ سالم برای قطعی لحظهای کش میماند.
|
2026-08-18 16:10:37 +03:30
|
|
|
*/
|
|
|
|
|
class SuperAdminProgramSettingsOverlay
|
|
|
|
|
{
|
2026-08-22 18:06:35 +03:30
|
|
|
/**
|
|
|
|
|
* آخرین پاسخ سالم سوپرادمین.
|
|
|
|
|
*
|
|
|
|
|
* کلیدهای can_edit=0 مالکشان سوپرادمین است و کپیشان در جدول settings لوکال
|
|
|
|
|
* ممکن است ماندهٔ deploy باشد. بدون این کش، یک timeout لحظهای باعث میشود
|
|
|
|
|
* ConfigService به آن کپی سقوط کند — مثلاً price_provider از zaarbox به montzar
|
|
|
|
|
* میپرید و مظنهٔ قدیمی montzar_live_price بهجای قیمت زنده نمایش داده میشد.
|
|
|
|
|
*/
|
|
|
|
|
private const LAST_GOOD_CACHE_KEY = 'superadmin:program_settings:last_good';
|
|
|
|
|
|
|
|
|
|
private const LAST_GOOD_CACHE_MINUTES = 1440;
|
|
|
|
|
|
2026-08-23 22:34:18 +03:30
|
|
|
/**
|
2026-08-24 16:15:52 +03:30
|
|
|
* کلیدهایی که فقط سوپرادمین ویرایش میکند (پنل خانگی 403).
|
|
|
|
|
* این لیست فیلتر overlay نیست — برای load از blacklist زیر استفاده میشود
|
|
|
|
|
* تا مثلاً price_provider از سوپرادمین/کش last-good حذف نشود.
|
2026-08-23 22:34:18 +03:30
|
|
|
*/
|
|
|
|
|
public const SUPERADMIN_OWNED_KEYS = [
|
|
|
|
|
'customer_direct_sms',
|
|
|
|
|
'customer_special_pricing',
|
2026-08-24 16:15:52 +03:30
|
|
|
'enable_automation',
|
2026-08-23 22:34:18 +03:30
|
|
|
'enable_conditional_order',
|
|
|
|
|
'enable_customer_level_profit',
|
|
|
|
|
'enable_product_funds',
|
|
|
|
|
'group_sms',
|
|
|
|
|
'has_page_earn_money',
|
|
|
|
|
'has_page_gift_card',
|
|
|
|
|
'has_page_notification',
|
|
|
|
|
'has_page_price_trigger',
|
|
|
|
|
'jibit_enabled',
|
|
|
|
|
'permision__enabled',
|
|
|
|
|
'show_to_users_chat',
|
|
|
|
|
];
|
|
|
|
|
|
2026-08-24 16:15:52 +03:30
|
|
|
/** کلیدهایی که هنوز صفحهٔ اختصاصی ادمین خانگی مالکشان است — از overlay دور انداخته میشوند */
|
2026-08-18 16:10:37 +03:30
|
|
|
public const LOCAL_OWNED_KEYS = [
|
|
|
|
|
'tracking_systems',
|
|
|
|
|
];
|
|
|
|
|
|
2026-08-19 19:55:29 +03:30
|
|
|
/** لاگ/قیمت لحظهای همکار — can_edit=1 در DB؛ کد مستقیم UpdateConfig میزند، نه سوپرادمین */
|
2026-08-18 16:10:37 +03:30
|
|
|
public const RUNTIME_KEYS = [
|
|
|
|
|
'montzar_last_product_log',
|
|
|
|
|
'montzar_order_response',
|
|
|
|
|
'montzar_live_price',
|
|
|
|
|
'montzar_mazaneh',
|
|
|
|
|
'montzar_diff',
|
|
|
|
|
'montzar_truly_buy_mazaneh',
|
|
|
|
|
'montzar_truly_sell_mazaneh',
|
|
|
|
|
'montzar_token',
|
|
|
|
|
'montzar_closed',
|
|
|
|
|
'up_price',
|
|
|
|
|
'down_price',
|
|
|
|
|
'price_extreme_date',
|
|
|
|
|
'do_send_liman',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
/** @var array<string, array<string, mixed>>|null */
|
|
|
|
|
private static ?array $memo = null;
|
|
|
|
|
|
|
|
|
|
private static bool $loaded = false;
|
|
|
|
|
|
|
|
|
|
/**
|
2026-08-19 22:02:10 +03:30
|
|
|
* همهٔ کلیدهای سوپرادمین (حتی value خالی). null = سوپرادمین در دسترس نبود.
|
|
|
|
|
*
|
|
|
|
|
* @return array<string, array<string, mixed>>|null
|
|
|
|
|
*/
|
|
|
|
|
public function catalogMap(): ?array
|
|
|
|
|
{
|
|
|
|
|
return $this->load();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* فقط کلیدهایی که سوپرادمین مقدار غیرخالی دارد — برای ConfigService.
|
|
|
|
|
*
|
|
|
|
|
* @return array<string, array<string, mixed>>|null
|
2026-08-18 16:10:37 +03:30
|
|
|
*/
|
|
|
|
|
public function map(): ?array
|
2026-08-19 22:02:10 +03:30
|
|
|
{
|
|
|
|
|
$full = $this->load();
|
|
|
|
|
if ($full === null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$withValue = [];
|
|
|
|
|
foreach ($full as $key => $row) {
|
|
|
|
|
$value = is_array($row) ? ($row['value'] ?? null) : null;
|
|
|
|
|
if ($value === null || $value === '') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$withValue[$key] = $row;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $withValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<string, array<string, mixed>>|null
|
|
|
|
|
*/
|
|
|
|
|
private function load(): ?array
|
2026-08-18 16:10:37 +03:30
|
|
|
{
|
|
|
|
|
if (self::$loaded) {
|
|
|
|
|
return self::$memo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$loaded = true;
|
|
|
|
|
|
|
|
|
|
$items = app(SuperAdminProgramSettingsClient::class)->fetchItems();
|
2026-08-22 18:06:35 +03:30
|
|
|
|
|
|
|
|
if ($items !== null) {
|
|
|
|
|
$this->rememberLastGood($items);
|
|
|
|
|
} else {
|
|
|
|
|
$items = $this->lastGoodItems();
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-18 16:10:37 +03:30
|
|
|
if ($items === null) {
|
|
|
|
|
self::$memo = null;
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$map = [];
|
|
|
|
|
foreach ($items as $row) {
|
|
|
|
|
if (! is_array($row)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$key = trim((string) ($row['key'] ?? ''));
|
2026-08-24 16:15:52 +03:30
|
|
|
// blacklist: فقط کلیدهای لوکال/runtime را دور بریز — نه whitelist قابلیتها
|
|
|
|
|
// (whitelist قبلی price_provider را حذف میکرد و با قطعی SA به montzar لوکال میپرید)
|
|
|
|
|
if ($key === '' || self::isLocalOwned($key) || self::isRuntime($key)) {
|
2026-08-18 16:10:37 +03:30
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$map[$key] = $row;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self::$memo = $map;
|
|
|
|
|
|
|
|
|
|
return $map;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-22 18:06:35 +03:30
|
|
|
/** @param array<int, array<string, mixed>> $items */
|
|
|
|
|
private function rememberLastGood(array $items): void
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
Cache::put(
|
|
|
|
|
self::LAST_GOOD_CACHE_KEY,
|
|
|
|
|
$items,
|
|
|
|
|
now()->addMinutes(self::LAST_GOOD_CACHE_MINUTES)
|
|
|
|
|
);
|
|
|
|
|
} catch (\Throwable $e) {
|
|
|
|
|
// کش در دسترس نیست — همان رفتار قبلی
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<int, array<string, mixed>>|null
|
|
|
|
|
*/
|
|
|
|
|
private function lastGoodItems(): ?array
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$cached = Cache::get(self::LAST_GOOD_CACHE_KEY);
|
|
|
|
|
} catch (\Throwable $e) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return is_array($cached) && $cached !== [] ? $cached : null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-18 16:10:37 +03:30
|
|
|
/**
|
|
|
|
|
* @return array<int, array<string, mixed>>
|
|
|
|
|
*/
|
|
|
|
|
public function items(): array
|
|
|
|
|
{
|
|
|
|
|
$map = $this->map();
|
|
|
|
|
if ($map === null || $map === []) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return array_values($map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<string, mixed>|null
|
|
|
|
|
*/
|
|
|
|
|
public function row(string $key): ?array
|
|
|
|
|
{
|
|
|
|
|
$map = $this->map();
|
|
|
|
|
if ($map === null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
$key = trim($key);
|
|
|
|
|
if ($key === '' || ! array_key_exists($key, $map)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $map[$key];
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-18 18:52:29 +03:30
|
|
|
public static function isRuntime(string $key): bool
|
|
|
|
|
{
|
|
|
|
|
return in_array($key, self::RUNTIME_KEYS, true);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-18 16:10:37 +03:30
|
|
|
public static function isLocalOwned(string $key): bool
|
|
|
|
|
{
|
|
|
|
|
return in_array($key, self::LOCAL_OWNED_KEYS, true);
|
|
|
|
|
}
|
2026-08-23 22:34:18 +03:30
|
|
|
|
|
|
|
|
public static function isSuperAdminOwned(string $key): bool
|
|
|
|
|
{
|
|
|
|
|
return in_array(trim($key), self::SUPERADMIN_OWNED_KEYS, true);
|
|
|
|
|
}
|
2026-08-18 16:10:37 +03:30
|
|
|
}
|