added some keys into setting
This commit is contained in:
@@ -262,6 +262,7 @@ class ProductController extends SuperController
|
|||||||
|
|
||||||
dispatch(function () {
|
dispatch(function () {
|
||||||
app(PriceBroadcastService::class)->broadcastAfterPriceUpdate();
|
app(PriceBroadcastService::class)->broadcastAfterPriceUpdate();
|
||||||
|
app(\App\Services\PriceChannelBroadcastService::class)->broadcastIfEligible();
|
||||||
})->afterResponse();
|
})->afterResponse();
|
||||||
|
|
||||||
return response()->json(true);
|
return response()->json(true);
|
||||||
|
|||||||
@@ -86,7 +86,12 @@ class LivePriceTickService
|
|||||||
app(LivePriceCacheService::class)->markTick();
|
app(LivePriceCacheService::class)->markTick();
|
||||||
|
|
||||||
// last از put داخل lastPrice؛ list بعد از sync محصولات
|
// last از put داخل lastPrice؛ list بعد از sync محصولات
|
||||||
app(PriceBroadcastService::class)->broadcastListIfChanged();
|
$listChanged = app(PriceBroadcastService::class)->broadcastListIfChanged();
|
||||||
|
|
||||||
|
// بعد از هر تغییر قیمت، قیمتها را به کانالهای پیامرسان بفرست (با cooldown داخلی)
|
||||||
|
if ($listChanged) {
|
||||||
|
app(PriceChannelBroadcastService::class)->broadcastIfEligible();
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
$lock->release();
|
$lock->release();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,323 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Product;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ارسال قیمت لحظهای به کانالهای پیامرسان (بله، تلگرام، روبیکا).
|
||||||
|
*
|
||||||
|
* اصول (طبق rule ساعت کاری):
|
||||||
|
* • هیچ تنظیمی را بازنویسی نمیکند — فقط میخواند.
|
||||||
|
* • فقط پیامرسانهایی که ادمین انتخاب کرده و توکن + مقصد دارند ارسال میشود.
|
||||||
|
* • قیمت هر محصول از قیمت پایه ذخیرهشده + کارمزد نمایش همان اپ ساخته میشود.
|
||||||
|
*/
|
||||||
|
class PriceChannelBroadcastService
|
||||||
|
{
|
||||||
|
private const COOLDOWN_CACHE_KEY = 'price_channel:last_sent_at';
|
||||||
|
|
||||||
|
private const SUPPORTED_MESSENGERS = ['bale', 'telegram', 'rubika'];
|
||||||
|
|
||||||
|
/** مثقال بازار آبشده (گرم) — وقتی تنظیم change_mesghal خالی باشد */
|
||||||
|
private const DEFAULT_CHANGE_MESGHAL = 4.3318;
|
||||||
|
|
||||||
|
public function __construct(private readonly ConfigService $config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* نقطهی ورود — بعد از تغییر قیمت صدا زده میشود.
|
||||||
|
* فقط وقتی قابلیت روشن است، پیامرسانی انتخاب شده و فاصلهی مجاز گذشته باشد ارسال میکند.
|
||||||
|
*/
|
||||||
|
public function broadcastIfEligible(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (! $this->config->getBool('price_channel_enabled', false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$targets = $this->resolveActiveTargets();
|
||||||
|
if ($targets === []) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $this->cooldownElapsed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = $this->buildMessage();
|
||||||
|
if ($message === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($targets as $messenger => $target) {
|
||||||
|
$this->dispatchToMessenger($messenger, $target['token'], $target['chat_ids'], $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->markSent();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Log::warning('PriceChannelBroadcast failed', ['message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* پیامرسانهای قابل ارسال: انتخابشده + توکن معتبر + حداقل یک مقصد.
|
||||||
|
*
|
||||||
|
* @return array<string, array{token: string, chat_ids: array<int, string>}>
|
||||||
|
*/
|
||||||
|
private function resolveActiveTargets(): array
|
||||||
|
{
|
||||||
|
$selected = $this->selectedMessengers();
|
||||||
|
if ($selected === []) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$targets = [];
|
||||||
|
foreach ($selected as $messenger) {
|
||||||
|
$token = trim((string) $this->config->getString($this->tokenKey($messenger), ''));
|
||||||
|
$chatIds = $this->parseList($this->config->getString($this->chatIdsKey($messenger), ''));
|
||||||
|
|
||||||
|
if ($token === '' || $chatIds === []) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$targets[$messenger] = ['token' => $token, 'chat_ids' => $chatIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $targets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array<int, string> */
|
||||||
|
private function selectedMessengers(): array
|
||||||
|
{
|
||||||
|
$raw = $this->parseList($this->config->getString('price_channel_messengers', ''));
|
||||||
|
|
||||||
|
return array_values(array_filter(
|
||||||
|
array_map(static fn ($m) => strtolower(trim($m)), $raw),
|
||||||
|
static fn ($m) => in_array($m, self::SUPPORTED_MESSENGERS, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function tokenKey(string $messenger): string
|
||||||
|
{
|
||||||
|
return match ($messenger) {
|
||||||
|
'bale' => 'bale_bot_token',
|
||||||
|
'telegram' => 'telegram_bot_token',
|
||||||
|
'rubika' => 'rubika_bot_token',
|
||||||
|
default => '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function chatIdsKey(string $messenger): string
|
||||||
|
{
|
||||||
|
return "price_channel_{$messenger}_to";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ساخت متن پیام قیمت — مرتب و بر اساس دادهی هر محصول.
|
||||||
|
*/
|
||||||
|
public function buildMessage(): string
|
||||||
|
{
|
||||||
|
$products = $this->eligibleProducts();
|
||||||
|
if ($products === []) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$channelDiff = (float) $this->config->getInt('price_channel_diff', 0);
|
||||||
|
$diffBuy = (float) $this->config->displayBuyPriceDiffRial();
|
||||||
|
$diffSell = (float) $this->config->displaySellPriceDiffRial();
|
||||||
|
$mesghal = $this->changeMesghal();
|
||||||
|
|
||||||
|
$lines = [];
|
||||||
|
$lines[] = $this->header();
|
||||||
|
$lines[] = '';
|
||||||
|
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$base = (float) ($product->price ?? 0);
|
||||||
|
|
||||||
|
// 🔴 خرید (مشتری میفروشد، پایینتر) — 🟢 فروش (مشتری میخرد، بالاتر)
|
||||||
|
$low = $base - $diffSell - $channelDiff;
|
||||||
|
$high = $base + $diffBuy + $channelDiff;
|
||||||
|
|
||||||
|
$lines[] = '🛒 ' . trim((string) $product->title);
|
||||||
|
$lines[] = '🔴 خرید ' . $this->formatPrice($low) . ' 🟢 فروش ' . $this->formatPrice($high);
|
||||||
|
|
||||||
|
if ($this->isGramUnit($product) && $mesghal > 0) {
|
||||||
|
$lines[] = '💰 هر گرم: ' . $this->formatPrice($low / $mesghal)
|
||||||
|
. ' / ' . $this->formatPrice($high / $mesghal);
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines[] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$footer = $this->footerLines();
|
||||||
|
if ($footer !== []) {
|
||||||
|
$lines[] = '➖➖➖➖➖➖';
|
||||||
|
foreach ($footer as $line) {
|
||||||
|
$lines[] = $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim(implode("\n", $lines));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function header(): string
|
||||||
|
{
|
||||||
|
$name = trim((string) $this->config->getString('name_fa', ''));
|
||||||
|
$time = now()->format('H:i');
|
||||||
|
|
||||||
|
$title = $name !== '' ? "📊 قیمت لحظهای {$name}" : '📊 قیمت لحظهای';
|
||||||
|
|
||||||
|
return $title . "\n🕐 ساعت " . $time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, Product>
|
||||||
|
*/
|
||||||
|
private function eligibleProducts(): array
|
||||||
|
{
|
||||||
|
$products = Product::query()
|
||||||
|
->where('active', 1)
|
||||||
|
->orderBy('id')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$eligible = [];
|
||||||
|
foreach ($products as $product) {
|
||||||
|
if ((int) ($product->price ?? 0) <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (! ($product->open_buy || $product->open_sell)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (! $this->config->isProductWithinTradingHours($product)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$eligible[] = $product;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $eligible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isGramUnit(Product $product): bool
|
||||||
|
{
|
||||||
|
return trim((string) ($product->unit ?? '')) === 'گرم';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** قیمت را به واحد نمایش (تقسیم بر ۱۰٬۰۰۰) با جداکنندهی هزارگان میبرد */
|
||||||
|
private function formatPrice(float $value): string
|
||||||
|
{
|
||||||
|
return number_format(max(0, $value) / 10000, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function changeMesghal(): float
|
||||||
|
{
|
||||||
|
$fromConfig = $this->config->get('change_mesghal');
|
||||||
|
$value = (float) ($fromConfig ?: config('change_mesghal', self::DEFAULT_CHANGE_MESGHAL));
|
||||||
|
|
||||||
|
return $value > 0 ? $value : self::DEFAULT_CHANGE_MESGHAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* خطوط پایانی — فقط مقادیر پرشده نمایش داده میشوند (آیدی چنل، شماره، لینک).
|
||||||
|
*
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
private function footerLines(): array
|
||||||
|
{
|
||||||
|
$lines = [];
|
||||||
|
|
||||||
|
foreach (['price_channel_footer_id', 'price_channel_footer_phone', 'price_channel_footer_link'] as $key) {
|
||||||
|
$value = trim((string) $this->config->getString($key, ''));
|
||||||
|
if ($value !== '') {
|
||||||
|
$lines[] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function dispatchToMessenger(string $messenger, string $token, array $chatIds, string $message): void
|
||||||
|
{
|
||||||
|
foreach ($chatIds as $chatId) {
|
||||||
|
try {
|
||||||
|
match ($messenger) {
|
||||||
|
'bale' => $this->sendBale($token, $chatId, $message),
|
||||||
|
'telegram' => $this->sendTelegram($token, $chatId, $message),
|
||||||
|
'rubika' => $this->sendRubika($token, $chatId, $message),
|
||||||
|
default => null,
|
||||||
|
};
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Log::warning("PriceChannel {$messenger} send failed", [
|
||||||
|
'chat_id' => $chatId,
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendBale(string $token, string $chatId, string $message): void
|
||||||
|
{
|
||||||
|
Http::withOptions(Controller::httpClientOptions())
|
||||||
|
->withoutVerifying()
|
||||||
|
->timeout(6)
|
||||||
|
->post("https://tapi.bale.ai/bot{$token}/sendMessage", [
|
||||||
|
'chat_id' => $chatId,
|
||||||
|
'text' => $message,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendTelegram(string $token, string $chatId, string $message): void
|
||||||
|
{
|
||||||
|
Http::withOptions(Controller::httpClientOptions())
|
||||||
|
->timeout(6)
|
||||||
|
->post("https://api.telegram.org/bot{$token}/sendMessage", [
|
||||||
|
'chat_id' => $chatId,
|
||||||
|
'text' => $message,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendRubika(string $token, string $chatId, string $message): void
|
||||||
|
{
|
||||||
|
Http::withOptions(Controller::httpClientOptions())
|
||||||
|
->withoutVerifying()
|
||||||
|
->timeout(6)
|
||||||
|
->post("https://botapi.rubika.ir/v3/{$token}/sendMessage", [
|
||||||
|
'chat_id' => $chatId,
|
||||||
|
'text' => $message,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** حداقل فاصلهی مجاز بین دو ارسال — جلوگیری از سیل پیام در هر تیک ۱۰ثانیهای */
|
||||||
|
private function cooldownElapsed(): bool
|
||||||
|
{
|
||||||
|
$minSeconds = max(0, $this->config->getInt('price_channel_min_seconds', 120));
|
||||||
|
if ($minSeconds === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastSent = Cache::get(self::COOLDOWN_CACHE_KEY);
|
||||||
|
if ($lastSent === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return now()->timestamp - (int) $lastSent >= $minSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function markSent(): void
|
||||||
|
{
|
||||||
|
Cache::put(self::COOLDOWN_CACHE_KEY, now()->timestamp, now()->addDay());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array<int, string> */
|
||||||
|
private function parseList(string $raw): array
|
||||||
|
{
|
||||||
|
$parts = preg_split('/[,\n]+/', trim($raw)) ?: [];
|
||||||
|
|
||||||
|
return array_values(array_filter(array_map('trim', $parts), static fn ($p) => $p !== ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -343,6 +343,71 @@ INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `de
|
|||||||
SELECT 'bale_bot_token', '', 'توکن بات بله', 0, 1, NULL
|
SELECT 'bale_bot_token', '', 'توکن بات بله', 0, 1, NULL
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'bale_bot_token' LIMIT 1);
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'bale_bot_token' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`)
|
||||||
|
SELECT 'rubika_bot_token', '', 'توکن بات روبیکا', 0, 1, NULL
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'rubika_bot_token' LIMIT 1);
|
||||||
|
|
||||||
|
-- ===========================================================================
|
||||||
|
-- ارسال قیمت به کانالهای پیامرسان (بله / تلگرام / روبیکا)
|
||||||
|
-- • محتوا (can_edit=1): روشن/خاموش، انتخاب پیامرسان، اختلاف، خطوط پایانی، فاصله
|
||||||
|
-- • سیستمی (can_edit=0): مقصد ارسال هر پیامرسان (آیدی چنل/گروه)
|
||||||
|
-- • توکنها همان bale_bot_token / telegram_bot_token / rubika_bot_token (can_edit=0)
|
||||||
|
-- ===========================================================================
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_enabled', 'false', 'ارسال قیمت به کانال', 1, 1,
|
||||||
|
'روشن: بعد از هر تغییر قیمت، مظنه به کانالهای پیامرسان انتخابشده ارسال میشود.', 'switch'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_enabled' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_messengers', '', 'پیامرسانهای ارسال قیمت', 1, 1,
|
||||||
|
'کدام پیامرسانها قیمت بگیرند؟ با ویرگول جدا کنید. گزینهها: bale,telegram,rubika', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_messengers' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_diff', '0', 'اختلاف قیمت کانال (ریال)', 1, 1,
|
||||||
|
'مبلغی که به قیمت خرید کانال اضافه و از قیمت فروش کم میشود (اسپرد اضافه فقط برای کانال).', 'price'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_diff' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_min_seconds', '120', 'حداقل فاصله ارسال (ثانیه)', 1, 1,
|
||||||
|
'حداقل فاصله بین دو ارسال به کانال؛ جلوی سیل پیام را میگیرد. صفر = هر تغییر قیمت.', '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_footer_id', '', 'آیدی کانال در پیام', 1, 1,
|
||||||
|
'اگر پر باشد در انتهای پیام نمایش داده میشود (مثلاً یوزرنیم کانال). خالی = نمایش داده نمیشود.', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_footer_id' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_footer_phone', '', 'شماره تماس در پیام', 1, 1,
|
||||||
|
'اگر پر باشد در انتهای پیام نمایش داده میشود. خالی = نمایش داده نمیشود.', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_footer_phone' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_footer_link', '', 'لینک در پیام', 1, 1,
|
||||||
|
'اگر پر باشد در انتهای پیام نمایش داده میشود. خالی = نمایش داده نمیشود.', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_footer_link' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_bale_to', '', 'مقصد ارسال بله', 0, 1,
|
||||||
|
'آیدی چنل/گروه بله برای ارسال قیمت (چند مقصد با ویرگول).', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_bale_to' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_telegram_to', '', 'مقصد ارسال تلگرام', 0, 1,
|
||||||
|
'آیدی چنل/گروه تلگرام برای ارسال قیمت (چند مقصد با ویرگول).', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_telegram_to' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_rubika_to', '', 'مقصد ارسال روبیکا', 0, 1,
|
||||||
|
'آیدی چنل/گروه روبیکا برای ارسال قیمت (چند مقصد با ویرگول).', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_rubika_to' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'change_mesghal', '4.3318', 'وزن مثقال (گرم)', 1, 1,
|
||||||
|
'ضریب تبدیل قیمت مثقال به گرم برای نمایش خط «هر گرم» در پیام کانال.', 'number'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'change_mesghal' LIMIT 1);
|
||||||
|
|
||||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`)
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`)
|
||||||
SELECT 'support_messenger_id', '', 'شناسه پشتیبانی پیامرسان', 1, 0, 'یوزرنیم یا شماره تماس بسته به پیامرسان انتخابشده'
|
SELECT 'support_messenger_id', '', 'شناسه پشتیبانی پیامرسان', 1, 0, 'یوزرنیم یا شماره تماس بسته به پیامرسان انتخابشده'
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'support_messenger_id' LIMIT 1);
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'support_messenger_id' LIMIT 1);
|
||||||
@@ -1191,7 +1256,8 @@ UPDATE `settings` SET `can_edit` = 0 WHERE `key` IN (
|
|||||||
'send_to_tahesab', 'service_charge_percentage',
|
'send_to_tahesab', 'service_charge_percentage',
|
||||||
'sse_path',
|
'sse_path',
|
||||||
'tahesab_bank_account', 'tahesab_db', 'tahesab_host', 'tahesab_port', 'tahesab_token',
|
'tahesab_bank_account', 'tahesab_db', 'tahesab_host', 'tahesab_port', 'tahesab_token',
|
||||||
'telegram_bot_token',
|
'telegram_bot_token', 'rubika_bot_token',
|
||||||
|
'price_channel_bale_to', 'price_channel_telegram_to', 'price_channel_rubika_to',
|
||||||
'unit',
|
'unit',
|
||||||
'up_price', 'down_price',
|
'up_price', 'down_price',
|
||||||
'wss_enabled',
|
'wss_enabled',
|
||||||
@@ -1217,7 +1283,10 @@ UPDATE `settings` SET `can_edit` = 1 WHERE `key` IN (
|
|||||||
'register_jibit_verify', 'register_referral_bonus_message', 'register_referral_sms_to_referrer',
|
'register_jibit_verify', 'register_referral_bonus_message', 'register_referral_sms_to_referrer',
|
||||||
'sell_fee', 'show_last_price', 'startDay',
|
'sell_fee', 'show_last_price', 'startDay',
|
||||||
'support_messenger', 'support_messenger_id', 'support_messenger_text',
|
'support_messenger', 'support_messenger_id', 'support_messenger_text',
|
||||||
'text_about', 'text_rule'
|
'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_footer_link', 'change_mesghal'
|
||||||
);
|
);
|
||||||
|
|
||||||
-- تفکیک نهایی type (بعد از همه batchها — override روی دیتابیس موجود)
|
-- تفکیک نهایی type (بعد از همه batchها — override روی دیتابیس موجود)
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
-- =============================================================================
|
||||||
|
-- price_channel_settings.sql — کلیدهای «ارسال قیمت به کانال» برای نصبهای موجود
|
||||||
|
--
|
||||||
|
-- این کلیدها در deploy_settings_const.sql هم هستند (روی هر deploy اجرا میشوند).
|
||||||
|
-- این فایل فقط برای افزودن سریع به یک DB موجود، بدون اجرای کل deploy، است.
|
||||||
|
--
|
||||||
|
-- قبل از اجرا: USE `نام_دیتابیس`; + بکاپ
|
||||||
|
-- idempotent — چند بار قابل اجرا (value ردیف موجود دست نمیخورد).
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
START TRANSACTION;
|
||||||
|
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- توکن روبیکا (توکن بله/تلگرام از قبل موجودند) — سیستمی (can_edit=0)
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`)
|
||||||
|
SELECT 'rubika_bot_token', '', 'توکن بات روبیکا', 0, 1, NULL
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'rubika_bot_token' LIMIT 1);
|
||||||
|
|
||||||
|
-- محتوا — قابل ویرایش (can_edit=1)
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_enabled', 'false', 'ارسال قیمت به کانال', 1, 1,
|
||||||
|
'روشن: بعد از هر تغییر قیمت، مظنه به کانالهای پیامرسان انتخابشده ارسال میشود.', 'switch'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_enabled' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_messengers', '', 'پیامرسانهای ارسال قیمت', 1, 1,
|
||||||
|
'کدام پیامرسانها قیمت بگیرند؟ با ویرگول جدا کنید. گزینهها: bale,telegram,rubika', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_messengers' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_diff', '0', 'اختلاف قیمت کانال (ریال)', 1, 1,
|
||||||
|
'مبلغی که به قیمت خرید کانال اضافه و از قیمت فروش کم میشود (اسپرد اضافه فقط برای کانال).', 'price'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_diff' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_min_seconds', '120', 'حداقل فاصله ارسال (ثانیه)', 1, 1,
|
||||||
|
'حداقل فاصله بین دو ارسال به کانال؛ جلوی سیل پیام را میگیرد. صفر = هر تغییر قیمت.', '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_footer_id', '', 'آیدی کانال در پیام', 1, 1,
|
||||||
|
'اگر پر باشد در انتهای پیام نمایش داده میشود (مثلاً یوزرنیم کانال). خالی = نمایش داده نمیشود.', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_footer_id' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_footer_phone', '', 'شماره تماس در پیام', 1, 1,
|
||||||
|
'اگر پر باشد در انتهای پیام نمایش داده میشود. خالی = نمایش داده نمیشود.', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_footer_phone' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_footer_link', '', 'لینک در پیام', 1, 1,
|
||||||
|
'اگر پر باشد در انتهای پیام نمایش داده میشود. خالی = نمایش داده نمیشود.', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_footer_link' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'change_mesghal', '4.3318', 'وزن مثقال (گرم)', 1, 1,
|
||||||
|
'ضریب تبدیل قیمت مثقال به گرم برای نمایش خط «هر گرم» در پیام کانال.', 'number'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'change_mesghal' LIMIT 1);
|
||||||
|
|
||||||
|
-- مقصد ارسال هر پیامرسان (آیدی چنل/گروه) — سیستمی (can_edit=0)
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_bale_to', '', 'مقصد ارسال بله', 0, 1,
|
||||||
|
'آیدی چنل/گروه بله برای ارسال قیمت (چند مقصد با ویرگول).', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_bale_to' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_telegram_to', '', 'مقصد ارسال تلگرام', 0, 1,
|
||||||
|
'آیدی چنل/گروه تلگرام برای ارسال قیمت (چند مقصد با ویرگول).', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_telegram_to' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||||
|
SELECT 'price_channel_rubika_to', '', 'مقصد ارسال روبیکا', 0, 1,
|
||||||
|
'آیدی چنل/گروه روبیکا برای ارسال قیمت (چند مقصد با ویرگول).', 'text'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_channel_rubika_to' LIMIT 1);
|
||||||
|
|
||||||
|
-- استانداردسازی can_edit
|
||||||
|
UPDATE `settings` SET `can_edit` = 0 WHERE `key` IN (
|
||||||
|
'rubika_bot_token',
|
||||||
|
'price_channel_bale_to', 'price_channel_telegram_to', 'price_channel_rubika_to'
|
||||||
|
);
|
||||||
|
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_footer_link', 'change_mesghal'
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
Reference in New Issue
Block a user