From a4e98d8047481f909353ed47f2f063e53269549d Mon Sep 17 00:00:00 2001 From: adonis Date: Wed, 8 Jul 2026 12:45:14 +0330 Subject: [PATCH] fix some handling 3 --- .../Controllers/Admin/ProductController.php | 78 +++++-- app/Models/Product.php | 8 +- app/Services/PriceChannelBroadcastService.php | 195 +++++++++++++++--- database/sql/deploy_settings_const.sql | 45 +++- ...ngs_const_preserve_value_sync_can_edit.sql | 16 ++ database/sql/price_channel_settings.sql | 30 ++- 6 files changed, 311 insertions(+), 61 deletions(-) diff --git a/app/Http/Controllers/Admin/ProductController.php b/app/Http/Controllers/Admin/ProductController.php index eb49dd4..5d1beea 100644 --- a/app/Http/Controllers/Admin/ProductController.php +++ b/app/Http/Controllers/Admin/ProductController.php @@ -611,29 +611,32 @@ class ProductController extends SuperController if (!Product::hasOrderLimitColumns()) { unset($data['order_limit_enabled'], $data['min_order_cash'], $data['max_order_cash']); - } elseif (empty($data['order_limit_enabled'])) { - $data['order_limit_enabled'] = false; - $data['min_order_cash'] = null; - $data['max_order_cash'] = null; } else { - $min = $data['min_order_cash'] ?? null; - $max = $data['max_order_cash'] ?? null; - $hasMin = $min !== null && $min !== ''; - $hasMax = $max !== null && $max !== ''; + $min = $this->normalizeOrderLimitCash($data['min_order_cash'] ?? null); + $max = $this->normalizeOrderLimitCash($data['max_order_cash'] ?? null); + $orderLimitEnabled = filter_var($data['order_limit_enabled'] ?? false, FILTER_VALIDATE_BOOLEAN) + || $min !== null + || $max !== null; - if (!$hasMin && !$hasMax) { - throw new UnprocessableEntityHttpException( - 'با فعال بودن محدودیت مبلغ سفارش، حداقل یکی از حداقل یا حداکثر مبلغ باید وارد شود' - ); + if (!$orderLimitEnabled) { + $data['order_limit_enabled'] = false; + $data['min_order_cash'] = null; + $data['max_order_cash'] = null; + } else { + if ($min === null && $max === null) { + throw new UnprocessableEntityHttpException( + 'با فعال بودن محدودیت مبلغ سفارش، حداقل یکی از حداقل یا حداکثر مبلغ باید وارد شود' + ); + } + + if ($min !== null && $max !== null && $min > $max) { + throw new UnprocessableEntityHttpException('حداقل مبلغ نمی‌تواند بیشتر از حداکثر باشد'); + } + + $data['order_limit_enabled'] = true; + $data['min_order_cash'] = $min; + $data['max_order_cash'] = $max; } - - if ($hasMin && $hasMax && (float) $min > (float) $max) { - throw new UnprocessableEntityHttpException('حداقل مبلغ نمی‌تواند بیشتر از حداکثر باشد'); - } - - $data['order_limit_enabled'] = true; - $data['min_order_cash'] = $hasMin ? (int) $min : null; - $data['max_order_cash'] = $hasMax ? (int) $max : null; } if (!Product::hasShowInAssetsColumn()) { @@ -704,4 +707,39 @@ class ProductController extends SuperController return (float) $value; } + + private function normalizeOrderLimitCash(mixed $value): ?int + { + if ($value === null || $value === '') { + return null; + } + + if (is_int($value)) { + return $value >= 0 ? $value : null; + } + + if (is_float($value)) { + return $value >= 0 ? (int) $value : null; + } + + if (! is_string($value)) { + return null; + } + + $value = $this->normalizeAsciiDigits(trim(str_replace([' ', ',', '٬'], '', $value))); + if ($value === '' || ! ctype_digit($value)) { + return null; + } + + return (int) $value; + } + + private function normalizeAsciiDigits(string $value): string + { + $persian = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']; + $arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩']; + $latin = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + + return str_replace(array_merge($persian, $arabic), array_merge($latin, $latin), $value); + } } diff --git a/app/Models/Product.php b/app/Models/Product.php index 73d57d9..f729df7 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -146,10 +146,10 @@ class Product extends Model } try { - static::$orderLimitColumnsExist = Schema::hasColumn( - (new static)->getTable(), - 'order_limit_enabled' - ); + $table = (new static)->getTable(); + static::$orderLimitColumnsExist = Schema::hasColumn($table, 'order_limit_enabled') + && Schema::hasColumn($table, 'min_order_cash') + && Schema::hasColumn($table, 'max_order_cash'); } catch (\Throwable) { static::$orderLimitColumnsExist = false; } diff --git a/app/Services/PriceChannelBroadcastService.php b/app/Services/PriceChannelBroadcastService.php index 2412efc..b51ce08 100644 --- a/app/Services/PriceChannelBroadcastService.php +++ b/app/Services/PriceChannelBroadcastService.php @@ -4,6 +4,7 @@ namespace App\Services; use App\Http\Controllers\Controller; use App\Models\Product; +use Hekmatinasser\Verta\Verta; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; @@ -29,6 +30,22 @@ class PriceChannelBroadcastService /** وزن هر مثقال به گرم — ضریب تبدیل قیمت هر گرم به هر مثقال (مثقال = گرم × این عدد) */ private const DEFAULT_CHANGE_MESGHAL = 4.3318; + /** قالب پیش‌فرض پیام کانال — وقتی price_channel_message_text خالی باشد */ + private const DEFAULT_MESSAGE_TEMPLATE = <<<'TXT' +سلام 👋 +%عنوان +📅 %تاریخ 🕐 %ساعت + +🔴 خرید گرم: %گرم_خرید +🟢 فروش گرم: %گرم_فروش +🔴 خرید مثقال: %مثقال_خرید +🟢 فروش مثقال: %مثقال_فروش + +📞 %شماره +%آیدی +%لینک +TXT; + public function __construct(private readonly ConfigService $config) { } @@ -66,19 +83,19 @@ class PriceChannelBroadcastService } $products = $this->eligibleProducts(); - if ($products === []) { - Log::debug('PriceChannel: محصول واجد شرایطی نیست (active/قیمت/ساعت کاری)'); + $boardProduct = $this->resolveBoardProduct($products); + if ($boardProduct === null || (int) ($boardProduct->price ?? 0) <= 0) { + Log::debug('PriceChannel: محصول تابلو (آبشده) واجد شرایطی نیست'); return; } - // شرط ۲: قیمتِ نمایشی نسبت به آخرین ارسال واقعاً تغییر کرده باشد؛ وگرنه چیزی نفرست - // و تایمر را هم دست نزن (تا سرِ اولین تغییرِ بعدی بلافاصله بفرستد). - $signature = $this->priceSignature($products); + // شرط ۲: قیمت تابلو نسبت به آخرین ارسال واقعاً تغییر کرده باشد + $signature = $this->priceSignature($boardProduct); if ($signature === Cache::get(self::SIGNATURE_CACHE_KEY)) { return; } - $message = $this->buildMessage($products); + $message = $this->buildMessage($products, $boardProduct); if ($message === '') { return; } @@ -111,9 +128,16 @@ class PriceChannelBroadcastService * * @param array $products */ - private function priceSignature(array $products): string + private function priceSignature(Product $boardProduct): string { - return md5($this->buildPriceBody($products)); + $prices = $this->computeDisplayPrices($boardProduct); + + return md5(implode('|', [ + $prices['gram_buy'], + $prices['gram_sell'], + $prices['mesghal_buy'], + $prices['mesghal_sell'], + ])); } /** @@ -137,8 +161,9 @@ class PriceChannelBroadcastService if ($message !== '' && $targets !== []) { $this->markSent(); $products = $this->eligibleProducts(); - if ($products !== []) { - Cache::put(self::SIGNATURE_CACHE_KEY, $this->priceSignature($products), now()->addDay()); + $boardProduct = $this->resolveBoardProduct($products); + if ($boardProduct !== null) { + Cache::put(self::SIGNATURE_CACHE_KEY, $this->priceSignature($boardProduct), now()->addDay()); } } @@ -239,27 +264,135 @@ class PriceChannelBroadcastService } /** - * ساخت متن پیام قیمت — مرتب و بر اساس داده‌ی هر محصول. + * ساخت متن پیام قیمت — قالب از price_channel_message_text (یا پیش‌فرض داخلی). */ - public function buildMessage(?array $products = null): string + public function buildMessage(?array $products = null, ?Product $boardProduct = null): string { $products = $products ?? $this->eligibleProducts(); - $body = $this->buildPriceBody($products); - if ($body === '') { + $boardProduct = $boardProduct ?? $this->resolveBoardProduct($products); + if ($boardProduct === null || (int) ($boardProduct->price ?? 0) <= 0) { return ''; } - return trim($this->header() . "\n\n" . $body); + return $this->renderMessageTemplate($this->messageTemplate(), $products, $boardProduct); + } + + private function messageTemplate(): string + { + $fromConfig = trim((string) $this->config->getString('price_channel_message_text', '')); + + return $fromConfig !== '' ? $fromConfig : self::DEFAULT_MESSAGE_TEMPLATE; } /** - * بدنهٔ قیمت (بدون هدر/ساعت) — همان چیزی که «تغییر قیمت» را می‌سازد. - * امضای تشخیص تغییر روی همین بدنه‌ی نمایشیِ رُندشده گرفته می‌شود تا اختلاف چند ریالی - * که به یک عدد نمایشیِ یکسان می‌رسد، پیام تکراری نفرستد. + * جایگزینی متغیرهای قالب. + * قیمت تابلو: %گرم_خرید %گرم_فروش %مثقال_خرید %مثقال_فروش + * زمان: %تاریخ %ساعت — اپ: %اسم_اپ %نام %عنوان + * تماس: %آیدی %شماره %لینک — اختیاری: %محصولات %فوتر * * @param array $products */ - private function buildPriceBody(array $products): string + private function renderMessageTemplate(string $template, array $products, Product $boardProduct): string + { + $name = trim((string) $this->config->getString('name_fa', '')); + $title = $name !== '' ? "📊 قیمت لحظه‌ای {$name}" : '📊 قیمت لحظه‌ای'; + $prices = $this->computeDisplayPrices($boardProduct); + + $message = $this->applyTemplatePlaceholders($template, [ + 'مثقال_فروش' => $prices['mesghal_sell'], + 'مثقال_خرید' => $prices['mesghal_buy'], + 'گرم_فروش' => $prices['gram_sell'], + 'گرم_خرید' => $prices['gram_buy'], + 'اسم_اپ' => $name, + 'محصولات' => $this->buildProductLines($products), + 'عنوان' => $title, + 'تاریخ' => Verta::now()->format('Y/n/j'), + 'ساعت' => now()->format('H:i'), + 'آیدی' => trim((string) $this->config->getString('price_channel_footer_id', '')), + 'شماره' => trim((string) $this->config->getString('price_channel_footer_phone', '')), + 'لینک' => trim((string) $this->config->getString('price_channel_footer_link', '')), + 'فوتر' => $this->buildFooterBlock(), + 'نام' => $name, + ]); + + return preg_replace("/\n{3,}/", "\n\n", trim($message)) ?? trim($message); + } + + /** @param array $replacements */ + private function applyTemplatePlaceholders(string $template, array $replacements): string + { + $keys = array_keys($replacements); + usort($keys, static fn (string $a, string $b): int => mb_strlen($b) <=> mb_strlen($a)); + + $message = $template; + foreach ($keys as $key) { + $message = preg_replace( + '/[%٪]\s*' . preg_quote($key, '/') . '/u', + $replacements[$key], + $message + ) ?? $message; + } + + return $message; + } + + /** + * محصول مرجع قیمت تابلو — اول آبشده (گرم)، بعد اولین محصول گرم، بعد اولین واجد شرایط. + * + * @param array $products + */ + private function resolveBoardProduct(array $products): ?Product + { + if ($products === []) { + return null; + } + + foreach ($products as $product) { + if (trim((string) ($product->group_type ?? '')) === 'آبشده' && $this->isGramUnit($product)) { + return $product; + } + } + + foreach ($products as $product) { + if ($this->isGramUnit($product)) { + return $product; + } + } + + return $products[0]; + } + + /** + * قیمت‌های نمایشی تابلو (گرم + مثقال) — همان منطق اپ + price_channel_diff. + * + * @return array{gram_buy: string, gram_sell: string, mesghal_buy: string, mesghal_sell: string} + */ + private function computeDisplayPrices(Product $product): array + { + $channelDiff = (float) $this->config->getInt('price_channel_diff', 0); + $diffBuy = (float) $this->config->displayBuyPriceDiffRial(); + $diffSell = (float) $this->config->displaySellPriceDiffRial(); + $mesghal = $this->changeMesghal(); + $base = (float) ($product->price ?? 0); + + // 🔴 خرید (مشتری می‌فروشد، پایین‌تر) — 🟢 فروش (مشتری می‌خرد، بالاتر) + $gramBuy = $base - $diffSell - $channelDiff; + $gramSell = $base + $diffBuy + $channelDiff; + + return [ + 'gram_buy' => $this->formatPrice($gramBuy), + 'gram_sell' => $this->formatPrice($gramSell), + 'mesghal_buy' => $mesghal > 0 ? $this->formatPrice($gramBuy * $mesghal) : '', + 'mesghal_sell' => $mesghal > 0 ? $this->formatPrice($gramSell * $mesghal) : '', + ]; + } + + /** + * بدنهٔ قیمت محصولات (بدون فوتر) — مبنای تشخیص تغییر قیمت. + * + * @param array $products + */ + private function buildProductLines(array $products): string { if ($products === []) { return ''; @@ -283,7 +416,6 @@ class PriceChannelBroadcastService $lines[] = '🔴 خرید ' . $this->formatPrice($low) . ' 🟢 فروش ' . $this->formatPrice($high); if ($this->isGramUnit($product) && $mesghal > 0) { - // قیمت پایه «هر گرم» است؛ مثقال = گرم × ضریب (کنوانسیون اپ: مثقال = گرم × 4.3318) $lines[] = '💰 هر مثقال: ' . $this->formatPrice($low * $mesghal) . ' / ' . $this->formatPrice($high * $mesghal); } @@ -291,25 +423,22 @@ class PriceChannelBroadcastService $lines[] = ''; } - $footer = $this->footerLines(); - if ($footer !== []) { - $lines[] = '➖➖➖➖➖➖'; - foreach ($footer as $line) { - $lines[] = $line; - } - } - return trim(implode("\n", $lines)); } - private function header(): string + private function buildFooterBlock(): string { - $name = trim((string) $this->config->getString('name_fa', '')); - $time = now()->format('H:i'); + $footer = $this->footerLines(); + if ($footer === []) { + return ''; + } - $title = $name !== '' ? "📊 قیمت لحظه‌ای {$name}" : '📊 قیمت لحظه‌ای'; + $lines = ['➖➖➖➖➖➖']; + foreach ($footer as $line) { + $lines[] = $line; + } - return $title . "\n🕐 ساعت " . $time; + return implode("\n", $lines); } /** diff --git a/database/sql/deploy_settings_const.sql b/database/sql/deploy_settings_const.sql index 62f81d9..24a8793 100644 --- a/database/sql/deploy_settings_const.sql +++ b/database/sql/deploy_settings_const.sql @@ -42,6 +42,22 @@ SET @invite_link_desc = 'متن پیام اشتراک‌گذاری دعوت در SET @deposit_guide_desc = 'متن راهنمای واریز در مودال شارژ حساب. متغیرها: ٪نام یا %نام = نام صاحب حساب؛ ٪کارت یا %کارت = شماره کارت؛ ٪شبا یا %شبا = شبا. فاصله بعد از ٪ اختیاری است. اگر خالی باشد از متن پیش‌فرض اپ استفاده می‌شود.'; SET @deposit_support_msg_desc = 'متن پیام هنگام کلیک روی «پیام به پشتیبانی» و «پیام به پشتیبانی (sms)» در مودال واریز. همان متغیرهای ٪نام، ٪کارت و ٪شبا. پیش‌فرض: «شماره حساب».'; +SET @price_channel_message_desc = 'قالب متن پیام ارسالی به کانال. متغیرهای قیمت تابلو: ٪گرم_خرید ٪گرم_فروش ٪مثقال_خرید ٪مثقال_فروش (یا با %). زمان: ٪تاریخ ٪ساعت. اپ: ٪اسم_اپ یا ٪نام (نام فارسی)؛ ٪عنوان = خط «📊 قیمت لحظه‌ای + نام». تماس جدا: ٪آیدی ٪شماره ٪لینک. اختیاری: ٪محصولات (لیست همه محصولات)؛ ٪فوتر (ترکیب آیدی+شماره+لینک). فاصله بعد از ٪ اختیاری است. خالی = قالب پیش‌فرض.'; +SET @price_channel_default_text = CONCAT( + 'سلام 👋', CHAR(10), + '%عنوان', CHAR(10), + '📅 %تاریخ 🕐 %ساعت', CHAR(10), + CHAR(10), + '🔴 خرید گرم: %گرم_خرید', CHAR(10), + '🟢 فروش گرم: %گرم_فروش', CHAR(10), + '🔴 خرید مثقال: %مثقال_خرید', CHAR(10), + '🟢 فروش مثقال: %مثقال_فروش', CHAR(10), + CHAR(10), + '📞 %شماره', CHAR(10), + '%آیدی', CHAR(10), + '%لینک' +); + -- ستون‌های اختیاری settings (بعضی DBهای قدیمی ندارند) SET @sql = IF( (SELECT COUNT(*) FROM information_schema.COLUMNS @@ -379,6 +395,10 @@ SELECT 'price_channel_min_seconds', '120', 'حداقل فاصله ارسال (ث 'حداقل فاصله بین دو ارسال به کانال؛ جلوی سیل پیام را می‌گیرد. صفر = هر تغییر قیمت.', 'number' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_min_seconds' LIMIT 1); +INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) +SELECT 'price_channel_message_text', @price_channel_default_text, 'قالب متن پیام کانال', 1, 1, @price_channel_message_desc, 'longtext' +WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_message_text' LIMIT 1); + INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) SELECT 'price_channel_footer_id', '', 'آیدی کانال در پیام', 1, 1, 'اگر پر باشد در انتهای پیام نمایش داده می‌شود (مثلاً یوزرنیم کانال). خالی = نمایش داده نمی‌شود.', 'text' @@ -706,7 +726,7 @@ WHERE `key` = 'main_product'; -- longtext UPDATE `settings` SET `type` = 'longtext' WHERE `key` IN ( 'text_rule', 'text_about', 'support_messenger_text', 'invite_link_text', - 'deposit_support_message_text', + 'deposit_support_message_text', 'price_channel_message_text', 'montzar_order_response', 'montzar_last_product_log' ); @@ -1127,6 +1147,13 @@ UPDATE `settings` SET `description` = 'نوع پیام‌رسان برای دک UPDATE `settings` SET `description` = 'شناسه تماس پشتیبانی: یوزرنیم (تلگرام)، شماره (واتساپ/بله) یا آیدی بسته به پیام‌رسان انتخاب‌شده.' WHERE `key` = 'support_messenger_id'; UPDATE `settings` SET `description` = @deposit_guide_desc WHERE `key` = 'support_messenger_text'; UPDATE `settings` SET `description` = @deposit_support_msg_desc WHERE `key` = 'deposit_support_message_text'; +UPDATE `settings` SET `description` = @price_channel_message_desc WHERE `key` = 'price_channel_message_text'; +UPDATE `settings` SET + `title_fa` = 'قالب متن پیام کانال', + `type` = 'longtext', + `can_edit` = 1, + `description` = @price_channel_message_desc +WHERE `key` = 'price_channel_message_text'; UPDATE `settings` SET `description` = 'متن پیام اشتراک‌گذاری دعوت در اپ کاربر (دکمه «اشتراک با دوستان» در صفحه اصلی، بخش معرف در پروفایل، صفحه کسب درآمد و مودال اشتراک). متغیرهای جایگزین: ٪نام یا %نام = نام کامل کاربر دعوت‌کننده؛ ٪لینک یا %لینک = آدرس کامل صفحه ثبت‌نام همراه با کد معرف (بر اساس تنظیم app_url یا دامنه فعلی مرورگر). فاصله اختیاری بعد از ٪ یا % مجاز است (مثلاً ٪ نام). اگر این فیلد خالی باشد، اپ از متن پیش‌فرض داخلی استفاده می‌کند.' WHERE `key` = 'invite_link_text'; UPDATE `settings` SET `description` = 'شماره تماس پشتیبانی؛ در صفحه واریز، درباره ما و قوانین نمایش داده می‌شود. متن پیامک/پشتیبانی از «متن پیام به پشتیبانی (واریز)» خوانده می‌شود.' WHERE `key` = 'deposit_sms_support_number'; @@ -1166,10 +1193,21 @@ UPDATE `settings` SET `description` = @deposit_support_msg_desc WHERE `key` = 'deposit_support_message_text'; +INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) +SELECT 'price_channel_message_text', @price_channel_default_text, 'قالب متن پیام کانال', 1, 1, @price_channel_message_desc, 'longtext' +WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_message_text' LIMIT 1); + +UPDATE `settings` SET + `title_fa` = 'قالب متن پیام کانال', + `type` = 'longtext', + `can_edit` = 1, + `description` = @price_channel_message_desc +WHERE `key` = 'price_channel_message_text'; + UPDATE `settings` SET `type` = 'longtext' WHERE `key` IN ( 'text_rule', 'text_about', 'support_messenger_text', 'invite_link_text', - 'deposit_support_message_text', + 'deposit_support_message_text', 'price_channel_message_text', 'montzar_order_response', 'montzar_last_product_log' ); @@ -1360,7 +1398,8 @@ UPDATE `settings` SET `can_edit` = 1 WHERE `key` IN ( 'deposit_support_message_text', 'deposit_account_holder', 'deposit_card_number', 'deposit_sheba', 'text_about', 'text_rule', 'price_channel_enabled', 'price_channel_messengers', 'price_channel_diff', - 'price_channel_min_seconds', 'price_channel_footer_id', 'price_channel_footer_phone', + 'price_channel_min_seconds', 'price_channel_message_text', + 'price_channel_footer_id', 'price_channel_footer_phone', 'price_channel_footer_link', 'change_mesghal' ); diff --git a/database/sql/deploy_settings_const_preserve_value_sync_can_edit.sql b/database/sql/deploy_settings_const_preserve_value_sync_can_edit.sql index 6e31a8e..f80696d 100644 --- a/database/sql/deploy_settings_const_preserve_value_sync_can_edit.sql +++ b/database/sql/deploy_settings_const_preserve_value_sync_can_edit.sql @@ -41,6 +41,22 @@ SET @invite_link_desc = 'متن پیام اشتراک‌گذاری دعوت در SET @deposit_guide_desc = 'متن راهنمای واریز در مودال شارژ حساب. متغیرها: ٪نام یا %نام = نام صاحب حساب؛ ٪کارت یا %کارت = شماره کارت؛ ٪شبا یا %شبا = شبا. فاصله بعد از ٪ اختیاری است. اگر خالی باشد از متن پیش‌فرض اپ استفاده می‌شود.'; SET @deposit_support_msg_desc = 'متن پیام هنگام کلیک روی «پیام به پشتیبانی» و «پیام به پشتیبانی (sms)» در مودال واریز. همان متغیرهای ٪نام، ٪کارت و ٪شبا. پیش‌فرض: «شماره حساب».'; +SET @price_channel_message_desc = 'قالب متن پیام ارسالی به کانال. متغیرهای قیمت تابلو: ٪گرم_خرید ٪گرم_فروش ٪مثقال_خرید ٪مثقال_فروش (یا با %). زمان: ٪تاریخ ٪ساعت. اپ: ٪اسم_اپ یا ٪نام (نام فارسی)؛ ٪عنوان = خط «📊 قیمت لحظه‌ای + نام». تماس جدا: ٪آیدی ٪شماره ٪لینک. اختیاری: ٪محصولات (لیست همه محصولات)؛ ٪فوتر (ترکیب آیدی+شماره+لینک). فاصله بعد از ٪ اختیاری است. خالی = قالب پیش‌فرض.'; +SET @price_channel_default_text = CONCAT( + 'سلام 👋', CHAR(10), + '%عنوان', CHAR(10), + '📅 %تاریخ 🕐 %ساعت', CHAR(10), + CHAR(10), + '🔴 خرید گرم: %گرم_خرید', CHAR(10), + '🟢 فروش گرم: %گرم_فروش', CHAR(10), + '🔴 خرید مثقال: %مثقال_خرید', CHAR(10), + '🟢 فروش مثقال: %مثقال_فروش', CHAR(10), + CHAR(10), + '📞 %شماره', CHAR(10), + '%آیدی', CHAR(10), + '%لینک' +); + -- ستون‌های اختیاری settings (بعضی DBهای قدیمی ندارند) SET @sql = IF( (SELECT COUNT(*) FROM information_schema.COLUMNS diff --git a/database/sql/price_channel_settings.sql b/database/sql/price_channel_settings.sql index 99d6c6d..37dff5b 100644 --- a/database/sql/price_channel_settings.sql +++ b/database/sql/price_channel_settings.sql @@ -11,6 +11,22 @@ START TRANSACTION; SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci; +SET @price_channel_message_desc = 'قالب متن پیام ارسالی به کانال. متغیرهای قیمت تابلو: ٪گرم_خرید ٪گرم_فروش ٪مثقال_خرید ٪مثقال_فروش (یا با %). زمان: ٪تاریخ ٪ساعت. اپ: ٪اسم_اپ یا ٪نام (نام فارسی)؛ ٪عنوان = خط «📊 قیمت لحظه‌ای + نام». تماس جدا: ٪آیدی ٪شماره ٪لینک. اختیاری: ٪محصولات (لیست همه محصولات)؛ ٪فوتر (ترکیب آیدی+شماره+لینک). فاصله بعد از ٪ اختیاری است. خالی = قالب پیش‌فرض.'; +SET @price_channel_default_text = CONCAT( + 'سلام 👋', CHAR(10), + '%عنوان', CHAR(10), + '📅 %تاریخ 🕐 %ساعت', CHAR(10), + CHAR(10), + '🔴 خرید گرم: %گرم_خرید', CHAR(10), + '🟢 فروش گرم: %گرم_فروش', CHAR(10), + '🔴 خرید مثقال: %مثقال_خرید', CHAR(10), + '🟢 فروش مثقال: %مثقال_فروش', CHAR(10), + CHAR(10), + '📞 %شماره', CHAR(10), + '%آیدی', CHAR(10), + '%لینک' +); + -- توکن روبیکا (توکن بله/تلگرام از قبل موجودند) — سیستمی (can_edit=0) INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`) SELECT 'rubika_bot_token', '', 'توکن بات روبیکا', 0, 1, NULL @@ -39,6 +55,17 @@ SELECT 'price_channel_min_seconds', '120', 'حداقل فاصله ارسال (ث 'حداقل فاصله بین دو ارسال به کانال؛ جلوی سیل پیام را می‌گیرد. صفر = هر تغییر قیمت.', 'number' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_min_seconds' LIMIT 1); +INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) +SELECT 'price_channel_message_text', @price_channel_default_text, 'قالب متن پیام کانال', 1, 1, @price_channel_message_desc, 'longtext' +WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_message_text' LIMIT 1); + +UPDATE `settings` SET + `title_fa` = 'قالب متن پیام کانال', + `type` = 'longtext', + `can_edit` = 1, + `description` = @price_channel_message_desc +WHERE `key` = 'price_channel_message_text'; + INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) SELECT 'price_channel_footer_id', '', 'آیدی کانال در پیام', 1, 1, 'اگر پر باشد در انتهای پیام نمایش داده می‌شود (مثلاً یوزرنیم کانال). خالی = نمایش داده نمی‌شود.', 'text' @@ -82,7 +109,8 @@ UPDATE `settings` SET `can_edit` = 0 WHERE `key` IN ( ); UPDATE `settings` SET `can_edit` = 1 WHERE `key` IN ( 'price_channel_enabled', 'price_channel_messengers', 'price_channel_diff', - 'price_channel_min_seconds', 'price_channel_footer_id', 'price_channel_footer_phone', + 'price_channel_min_seconds', 'price_channel_message_text', + 'price_channel_footer_id', 'price_channel_footer_phone', 'price_channel_footer_link', 'change_mesghal' );