Files
boursecu_server/app/Services/SuperAdminProgramSettingsOverlay.php
T
mohmdsdgandCursor b21b136711 fix(settings): honor last-price switch and overlay only SuperAdmin access flags
Stored DB prices were treated as live quotes, and SuperAdmin overlay overwrote tenant keys like trading hours. Keep overlay to the 14 access flags and hide fallback prices when the panel says so.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 03:01:07 +03:30

295 lines
8.5 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
/**
* تنظیمات پیشرفته سوپرادمین برای ConfigService و get_settings.
* در هر درخواست یک بار fetch می‌شود؛ آخرین پاسخ سالم برای قطعی لحظه‌ای کش می‌ماند.
*/
class SuperAdminProgramSettingsOverlay
{
/**
* آخرین پاسخ سالم سوپرادمین — فقط کلیدهای دسترسی (SUPERADMIN_OWNED_KEYS).
* پاسخ remote ممکن است کلیدهای دیگری هم داشته باشد؛ آن‌ها ذخیره و اعمال نمی‌شوند.
*/
private const LAST_GOOD_CACHE_KEY = 'superadmin:program_settings:last_good';
private const LAST_GOOD_CACHE_MINUTES = 1440;
/**
* فقط این ۱۴ دسترسی از سوپرادمین خوانده می‌شود.
* هر کلید دیگری (قیمت، ساعت کاری، برندینگ، …) مال پنل خانگی است.
*/
public const SUPERADMIN_OWNED_KEYS = [
'customer_direct_sms',
'customer_special_pricing',
'enable_automation',
'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',
];
/** کلیدهایی که هنوز صفحهٔ اختصاصی ادمین خانگی مالک‌شان است — از overlay دور انداخته می‌شوند */
public const LOCAL_OWNED_KEYS = [
'tracking_systems',
];
/** لاگ/قیمت لحظه‌ای همکار — can_edit=1 در DB؛ کد مستقیم UpdateConfig می‌زند، نه سوپرادمین */
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;
/** پاک کردن کش last-good و memo درخواست — برای دکمهٔ همگام‌سازی تنظیمات پیشرفته */
public function flushCache(): void
{
self::$memo = null;
self::$loaded = false;
try {
Cache::forget(self::LAST_GOOD_CACHE_KEY);
} catch (\Throwable $e) {
// کش در دسترس نیست
}
}
/**
* کش را پاک می‌کند و دوباره از سوپرادمین می‌خواند.
*
* @return array{ok: bool, count: int, items: array<string, string>, source: string}
*/
public function refreshFromSuperAdmin(): array
{
$this->flushCache();
$map = $this->catalogMap();
if ($map === null) {
return [
'ok' => false,
'count' => 0,
'items' => [],
'source' => 'unavailable',
];
}
$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;
}
return [
'ok' => true,
'count' => count($items),
'items' => $items,
'source' => 'superadmin',
];
}
/**
* همهٔ کلیدهای سوپرادمین (حتی value خالی). null = سوپرادمین در دسترس نبود.
*
* @return array<string, array<string, mixed>>|null
*/
public function catalogMap(): ?array
{
return $this->load();
}
/**
* فقط کلیدهایی که سوپرادمین مقدار غیرخالی دارد — برای ConfigService.
*
* @return array<string, array<string, mixed>>|null
*/
public function map(): ?array
{
$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
{
if (self::$loaded) {
return self::$memo;
}
self::$loaded = true;
$items = app(SuperAdminProgramSettingsClient::class)->fetchItems();
if ($items !== null) {
$this->rememberLastGood($items);
} else {
$items = $this->lastGoodItems();
if ($items !== null) {
\Illuminate\Support\Facades\Log::warning('SuperAdmin program-settings using last-good cache', [
'count' => count($items),
]);
}
}
if ($items === null) {
self::$memo = null;
return null;
}
$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
{
$map = [];
foreach ($items as $row) {
if (! is_array($row)) {
continue;
}
$key = trim((string) ($row['key'] ?? ''));
if ($key === '' || ! self::isSuperAdminOwned($key)) {
continue;
}
$map[$key] = $row;
}
return $map;
}
/** @param array<int, array<string, mixed>> $items */
private function rememberLastGood(array $items): void
{
$owned = array_values(self::ownedItemsMap($items));
if ($owned === []) {
return;
}
try {
Cache::put(
self::LAST_GOOD_CACHE_KEY,
$owned,
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;
}
/**
* @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 === '' || ! self::isSuperAdminOwned($key) || ! array_key_exists($key, $map)) {
return null;
}
return $map[$key];
}
public static function isRuntime(string $key): bool
{
return in_array($key, self::RUNTIME_KEYS, true);
}
/**
* کلیدهای صفحهٔ «ساعت کاری» هم مالکشان پنل خانگی است — اگر از overlay خوانده شوند
* مقدار ذخیره‌شده در پنل هیچ‌وقت روی قیمت کاربر اعمال نمی‌شود.
*/
public static function isLocalOwned(string $key): bool
{
return in_array($key, self::LOCAL_OWNED_KEYS, true)
|| in_array($key, ConfigService::TRADING_HOURS_CLIENT_KEYS, true);
}
public static function isSuperAdminOwned(string $key): bool
{
return in_array(trim($key), self::SUPERADMIN_OWNED_KEYS, true);
}
}