2026-08-18 16:10:37 +03:30
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
2026-08-29 23:35:37 +03:30
|
|
|
use App\Models\Setting;
|
|
|
|
|
|
2026-08-18 16:10:37 +03:30
|
|
|
/**
|
2026-08-19 22:02:10 +03:30
|
|
|
* تنظیمات پیشرفته سوپرادمین برای ConfigService و get_settings.
|
2026-08-29 22:39:08 +03:30
|
|
|
* هر درخواست HTTP یک بار از سوپرادمین میخواند (memo فقط داخل همان درخواست) — بدون کش Redis.
|
2026-08-18 16:10:37 +03:30
|
|
|
*/
|
|
|
|
|
class SuperAdminProgramSettingsOverlay
|
|
|
|
|
{
|
2026-08-23 22:34:18 +03:30
|
|
|
/**
|
2026-09-05 17:01:39 +03:30
|
|
|
* فقط این ۱۶ دسترسی از سوپرادمین خوانده میشود.
|
2026-08-25 03:01:07 +03:30
|
|
|
* هر کلید دیگری (قیمت، ساعت کاری، برندینگ، …) مال پنل خانگی است.
|
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',
|
2026-08-30 00:17:01 +03:30
|
|
|
'enable_gold_credit',
|
2026-08-23 22:34:18 +03:30
|
|
|
'enable_product_funds',
|
|
|
|
|
'group_sms',
|
2026-09-05 17:01:39 +03:30
|
|
|
'has_landing',
|
2026-08-23 22:34:18 +03:30
|
|
|
'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-25 14:19:22 +03:30
|
|
|
/**
|
|
|
|
|
* دسترسیهای سوپرادمین که منو/مسیر اپ کاربر را کنترل میکنند.
|
|
|
|
|
* باید همیشه در api/get_settings مشتری برسند (show_to_user).
|
|
|
|
|
*/
|
|
|
|
|
public const CLIENT_FEATURE_KEYS = [
|
|
|
|
|
'enable_conditional_order',
|
2026-08-30 00:17:01 +03:30
|
|
|
'enable_gold_credit',
|
2026-08-25 14:19:22 +03:30
|
|
|
'enable_product_funds',
|
2026-09-05 17:01:39 +03:30
|
|
|
'has_landing',
|
2026-08-25 14:19:22 +03:30
|
|
|
'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-26 12:56:57 +03:30
|
|
|
/**
|
|
|
|
|
* فقط کلیدهایی که هنوز از پنل قابل ویرایش نیستند و کد tenant مینویسد.
|
|
|
|
|
* بقیهٔ سابق (montzar_* / up_price / …) can_edit=0 و فقط در تنظیمات پیشرفته ویرایش میشوند.
|
|
|
|
|
*/
|
2026-08-18 16:10:37 +03:30
|
|
|
public const RUNTIME_KEYS = [
|
|
|
|
|
'do_send_liman',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
/** @var array<string, array<string, mixed>>|null */
|
|
|
|
|
private static ?array $memo = null;
|
|
|
|
|
|
|
|
|
|
private static bool $loaded = false;
|
|
|
|
|
|
2026-08-29 22:39:08 +03:30
|
|
|
/** پاک کردن memo درخواست — برای دکمهٔ همگامسازی / بروزرسانی */
|
2026-08-24 21:22:44 +03:30
|
|
|
public function flushCache(): void
|
|
|
|
|
{
|
|
|
|
|
self::$memo = null;
|
|
|
|
|
self::$loaded = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-08-29 22:39:08 +03:30
|
|
|
* دوباره از سوپرادمین میخواند (بدون کش پایدار).
|
2026-08-24 21:22:44 +03:30
|
|
|
*
|
2026-08-29 22:39:08 +03:30
|
|
|
* @return array{ok: bool, count: int, items: array<string, string>, source: string, meta?: array<string, mixed>}
|
2026-08-24 21:22:44 +03:30
|
|
|
*/
|
|
|
|
|
public function refreshFromSuperAdmin(): array
|
|
|
|
|
{
|
|
|
|
|
$this->flushCache();
|
2026-08-29 22:39:08 +03:30
|
|
|
$client = app(SuperAdminProgramSettingsClient::class);
|
2026-08-24 21:22:44 +03:30
|
|
|
$map = $this->catalogMap();
|
|
|
|
|
if ($map === null) {
|
|
|
|
|
return [
|
|
|
|
|
'ok' => false,
|
|
|
|
|
'count' => 0,
|
2026-08-24 21:46:13 +03:30
|
|
|
'items' => [],
|
2026-08-24 21:22:44 +03:30
|
|
|
'source' => 'unavailable',
|
2026-08-29 22:39:08 +03:30
|
|
|
'meta' => $client->lastFetchMeta(),
|
2026-08-24 21:22:44 +03:30
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-24 21:46:13 +03:30
|
|
|
$items = [];
|
|
|
|
|
foreach ($map as $key => $row) {
|
|
|
|
|
if (! is_array($row)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$value = $row['value'] ?? null;
|
|
|
|
|
if ($value === null || $value === '') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$items[(string) $key] = (string) $value;
|
|
|
|
|
}
|
2026-08-24 21:22:44 +03:30
|
|
|
|
2026-08-29 23:35:37 +03:30
|
|
|
// در DB لوکال هم بنویس تا اگر درخواست بعدی به سوپرادمین نرسد، منو/فلگها از آخرین مقدار درست بمانند
|
|
|
|
|
$this->persistOwnedToLocal($map);
|
|
|
|
|
|
2026-08-24 21:22:44 +03:30
|
|
|
return [
|
|
|
|
|
'ok' => true,
|
2026-08-24 21:46:13 +03:30
|
|
|
'count' => count($items),
|
|
|
|
|
'items' => $items,
|
2026-08-24 21:22:44 +03:30
|
|
|
'source' => 'superadmin',
|
2026-08-29 22:39:08 +03:30
|
|
|
'meta' => $client->lastFetchMeta(),
|
2026-08-24 21:22:44 +03:30
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-29 23:35:37 +03:30
|
|
|
/**
|
2026-09-05 17:01:39 +03:30
|
|
|
* آخرین مقادیر ۱۶ دسترسی را در settings لوکال ذخیره میکند (can_edit=0).
|
2026-08-29 23:35:37 +03:30
|
|
|
*
|
|
|
|
|
* @param array<string, array<string, mixed>> $map
|
|
|
|
|
*/
|
|
|
|
|
private function persistOwnedToLocal(array $map): void
|
|
|
|
|
{
|
|
|
|
|
foreach ($map as $key => $row) {
|
|
|
|
|
if (! is_array($row) || ! self::isSuperAdminOwned((string) $key)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$value = $row['value'] ?? null;
|
|
|
|
|
if ($value === null || $value === '') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$setting = Setting::query()->firstOrNew(['key' => (string) $key]);
|
|
|
|
|
$setting->value = (string) $value;
|
|
|
|
|
$setting->can_edit = 0;
|
|
|
|
|
$setting->is_active = 1;
|
|
|
|
|
if (Setting::hasTypeColumn()) {
|
|
|
|
|
$setting->type = (string) ($row['type'] ?? $setting->type ?? 'switch');
|
|
|
|
|
}
|
|
|
|
|
if (! $setting->exists || trim((string) ($setting->title_fa ?? '')) === '') {
|
|
|
|
|
$setting->title_fa = (string) ($row['title_fa'] ?? $key);
|
|
|
|
|
}
|
|
|
|
|
if (array_key_exists('description', $row) && $row['description'] !== null && $row['description'] !== '') {
|
|
|
|
|
$setting->description = (string) $row['description'];
|
|
|
|
|
}
|
|
|
|
|
$setting->save();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-18 16:10:37 +03:30
|
|
|
/**
|
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
|
|
|
|
2026-08-18 16:10:37 +03:30
|
|
|
if ($items === null) {
|
|
|
|
|
self::$memo = null;
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-25 03:01:07 +03:30
|
|
|
$map = self::ownedItemsMap($items);
|
|
|
|
|
self::$memo = $map;
|
|
|
|
|
|
|
|
|
|
return $map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* فقط کلیدهای دسترسی سوپرادمین — بقیهٔ پاسخ remote دور ریخته میشود.
|
|
|
|
|
*
|
|
|
|
|
* @param array<int, array<string, mixed>> $items
|
|
|
|
|
* @return array<string, array<string, mixed>>
|
|
|
|
|
*/
|
|
|
|
|
public static function ownedItemsMap(array $items): array
|
|
|
|
|
{
|
2026-08-18 16:10:37 +03:30
|
|
|
$map = [];
|
|
|
|
|
foreach ($items as $row) {
|
|
|
|
|
if (! is_array($row)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$key = trim((string) ($row['key'] ?? ''));
|
2026-08-25 03:01:07 +03:30
|
|
|
if ($key === '' || ! self::isSuperAdminOwned($key)) {
|
2026-08-18 16:10:37 +03:30
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$map[$key] = $row;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @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);
|
2026-08-25 03:01:07 +03:30
|
|
|
if ($key === '' || ! self::isSuperAdminOwned($key) || ! array_key_exists($key, $map)) {
|
2026-08-18 16:10:37 +03:30
|
|
|
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-25 03:01:07 +03:30
|
|
|
/**
|
|
|
|
|
* کلیدهای صفحهٔ «ساعت کاری» هم مالکشان پنل خانگی است — اگر از overlay خوانده شوند
|
|
|
|
|
* مقدار ذخیرهشده در پنل هیچوقت روی قیمت کاربر اعمال نمیشود.
|
|
|
|
|
*/
|
2026-08-18 16:10:37 +03:30
|
|
|
public static function isLocalOwned(string $key): bool
|
|
|
|
|
{
|
2026-08-25 03:01:07 +03:30
|
|
|
return in_array($key, self::LOCAL_OWNED_KEYS, true)
|
|
|
|
|
|| in_array($key, ConfigService::TRADING_HOURS_CLIENT_KEYS, true);
|
2026-08-18 16:10:37 +03:30
|
|
|
}
|
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-25 14:19:22 +03:30
|
|
|
|
|
|
|
|
public static function isClientFeatureKey(string $key): bool
|
|
|
|
|
{
|
|
|
|
|
return in_array(trim($key), self::CLIENT_FEATURE_KEYS, true);
|
|
|
|
|
}
|
2026-08-18 16:10:37 +03:30
|
|
|
}
|