fixed some bugs
This commit is contained in:
@@ -20,7 +20,7 @@ class PriceChannelTest extends Command
|
|||||||
$this->line('قابلیت روشن (price_channel_enabled): ' . ($info['enabled'] ? 'بله' : 'خیر'));
|
$this->line('قابلیت روشن (price_channel_enabled): ' . ($info['enabled'] ? 'بله' : 'خیر'));
|
||||||
$this->line('پیامرسانهای انتخابشده: ' . (implode(', ', $info['selected_messengers']) ?: '— (خالی)'));
|
$this->line('پیامرسانهای انتخابشده: ' . (implode(', ', $info['selected_messengers']) ?: '— (خالی)'));
|
||||||
$this->line('حداقل فاصله ارسال (ثانیه): ' . $info['min_seconds']);
|
$this->line('حداقل فاصله ارسال (ثانیه): ' . $info['min_seconds']);
|
||||||
$this->line('فاصله cooldown گذشته؟ ' . ($info['cooldown_elapsed'] ? 'بله' : 'خیر (هنوز زوده)'));
|
$this->line('فاصله cooldown گذشته؟ ' . ($info['cooldown_elapsed'] ? 'بله' : 'خیر (هنوز ' . ($info['cooldown_seconds_remaining'] ?? 0) . ' ثانیه مانده)'));
|
||||||
$this->line('منبع قالب: ' . ($info['template_source'] === 'db' ? 'تنظیمات ادمین' : 'پیشفرض داخلی'));
|
$this->line('منبع قالب: ' . ($info['template_source'] === 'db' ? 'تنظیمات ادمین' : 'پیشفرض داخلی'));
|
||||||
if (! empty($info['live_trade_buy_rial'])) {
|
if (! empty($info['live_trade_buy_rial'])) {
|
||||||
$this->line('قیمت فروش اپ (buy API): ' . number_format((int) $info['live_trade_buy_rial']) . ' ریال');
|
$this->line('قیمت فروش اپ (buy API): ' . number_format((int) $info['live_trade_buy_rial']) . ' ریال');
|
||||||
|
|||||||
@@ -76,9 +76,8 @@ TXT;
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// شرط ۱: از آخرین «ارسال واقعی» حداقل price_channel_min_seconds گذشته باشد.
|
// شرط ۱: حداقل price_channel_min_seconds از آخرین ارسال گذشته باشد (اتمی — جلوی race و چند worker)
|
||||||
// چون فقط روی ارسال واقعی markSent میکنیم، یک بررسیِ بیارسال تایمر را ریست نمیکند.
|
if (! $this->acquireSendCooldown()) {
|
||||||
if (! $this->cooldownElapsed()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,8 +110,7 @@ TXT;
|
|||||||
$results[$messenger] = $this->dispatchToMessenger($messenger, $target['token'], $target['chat_ids'], $message);
|
$results[$messenger] = $this->dispatchToMessenger($messenger, $target['token'], $target['chat_ids'], $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// فقط بعد از ارسال واقعی: تایمر cooldown و امضای قیمت بهروزرسانی میشوند
|
// فقط بعد از ارسال واقعی: امضا بهروزرسانی میشود (cooldown در acquireSendCooldown ست شد)
|
||||||
$this->markSent();
|
|
||||||
Cache::put(self::SIGNATURE_CACHE_KEY, $signature, now()->addDay());
|
Cache::put(self::SIGNATURE_CACHE_KEY, $signature, now()->addDay());
|
||||||
|
|
||||||
Log::info('PriceChannel: قیمت به کانال ارسال شد', [
|
Log::info('PriceChannel: قیمت به کانال ارسال شد', [
|
||||||
@@ -176,6 +174,11 @@ TXT;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $this->acquireSendCooldown()) {
|
||||||
|
Log::debug('PriceChannel: قالب عوض شد ولی cooldown هنوز تمام نشده');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$message = $this->buildMessage($products, $boardProduct);
|
$message = $this->buildMessage($products, $boardProduct);
|
||||||
if ($message === '') {
|
if ($message === '') {
|
||||||
return;
|
return;
|
||||||
@@ -187,10 +190,9 @@ TXT;
|
|||||||
}
|
}
|
||||||
|
|
||||||
$signature = $this->broadcastSignature();
|
$signature = $this->broadcastSignature();
|
||||||
$this->markSent();
|
|
||||||
Cache::put(self::SIGNATURE_CACHE_KEY, $signature, now()->addDay());
|
Cache::put(self::SIGNATURE_CACHE_KEY, $signature, now()->addDay());
|
||||||
|
|
||||||
Log::info('PriceChannel: قالب پیام تغییر کرد — ارسال فوری به کانال', [
|
Log::info('PriceChannel: قالب پیام تغییر کرد — ارسال به کانال', [
|
||||||
'targets' => array_keys($targets),
|
'targets' => array_keys($targets),
|
||||||
'results' => $results,
|
'results' => $results,
|
||||||
]);
|
]);
|
||||||
@@ -221,10 +223,8 @@ TXT;
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($message !== '' && $targets !== []) {
|
if ($message !== '' && $targets !== []) {
|
||||||
$this->markSent();
|
$this->acquireSendCooldown(true);
|
||||||
if ($this->resolveLiveTradePrices() !== null) {
|
Cache::put(self::SIGNATURE_CACHE_KEY, $this->broadcastSignature(), now()->addDay());
|
||||||
Cache::put(self::SIGNATURE_CACHE_KEY, $this->broadcastSignature(), now()->addDay());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@@ -266,6 +266,7 @@ TXT;
|
|||||||
'selected_messengers' => $selected,
|
'selected_messengers' => $selected,
|
||||||
'min_seconds' => $this->config->getInt('price_channel_min_seconds', 120),
|
'min_seconds' => $this->config->getInt('price_channel_min_seconds', 120),
|
||||||
'cooldown_elapsed' => $this->cooldownElapsed(),
|
'cooldown_elapsed' => $this->cooldownElapsed(),
|
||||||
|
'cooldown_seconds_remaining' => $this->cooldownSecondsRemaining(),
|
||||||
'eligible_products' => count($this->eligibleProducts()),
|
'eligible_products' => count($this->eligibleProducts()),
|
||||||
'messengers' => $messengers,
|
'messengers' => $messengers,
|
||||||
'active_targets' => array_keys($this->resolveActiveTargets()),
|
'active_targets' => array_keys($this->resolveActiveTargets()),
|
||||||
@@ -718,25 +719,39 @@ TXT;
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** حداقل فاصلهی مجاز بین دو ارسال — جلوگیری از سیل پیام در هر تیک ۱۰ثانیهای */
|
/** حداقل فاصلهٔ مجاز بین دو ارسال — Cache::add اتمی (TTL = min_seconds) */
|
||||||
private function cooldownElapsed(): bool
|
private function acquireSendCooldown(bool $force = false): bool
|
||||||
{
|
{
|
||||||
$minSeconds = max(0, $this->config->getInt('price_channel_min_seconds', 120));
|
$minSeconds = max(0, $this->config->getInt('price_channel_min_seconds', 120));
|
||||||
if ($minSeconds === 0) {
|
if ($minSeconds === 0 || $force) {
|
||||||
|
if ($minSeconds > 0) {
|
||||||
|
Cache::put(self::COOLDOWN_CACHE_KEY, now()->timestamp, $minSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$lastSent = Cache::get(self::COOLDOWN_CACHE_KEY);
|
return Cache::add(self::COOLDOWN_CACHE_KEY, now()->timestamp, $minSeconds);
|
||||||
if ($lastSent === null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return now()->timestamp - (int) $lastSent >= $minSeconds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function markSent(): void
|
private function cooldownElapsed(): bool
|
||||||
{
|
{
|
||||||
Cache::put(self::COOLDOWN_CACHE_KEY, now()->timestamp, now()->addDay());
|
return $this->cooldownSecondsRemaining() === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cooldownSecondsRemaining(): int
|
||||||
|
{
|
||||||
|
$minSeconds = max(0, $this->config->getInt('price_channel_min_seconds', 120));
|
||||||
|
if ($minSeconds === 0 || ! Cache::has(self::COOLDOWN_CACHE_KEY)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastSent = (int) Cache::get(self::COOLDOWN_CACHE_KEY, 0);
|
||||||
|
if ($lastSent <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return max(0, $minSeconds - (now()->timestamp - $lastSent));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<int, string> */
|
/** @return array<int, string> */
|
||||||
|
|||||||
@@ -42,7 +42,22 @@ SET @invite_link_desc = 'متن پیام اشتراکگذاری دعوت در
|
|||||||
SET @deposit_guide_desc = 'متن راهنمای واریز در مودال شارژ حساب. متغیرها: ٪نام یا %نام = نام صاحب حساب؛ ٪کارت یا %کارت = شماره کارت؛ ٪شبا یا %شبا = شبا. فاصله بعد از ٪ اختیاری است. اگر خالی باشد از متن پیشفرض اپ استفاده میشود.';
|
SET @deposit_guide_desc = 'متن راهنمای واریز در مودال شارژ حساب. متغیرها: ٪نام یا %نام = نام صاحب حساب؛ ٪کارت یا %کارت = شماره کارت؛ ٪شبا یا %شبا = شبا. فاصله بعد از ٪ اختیاری است. اگر خالی باشد از متن پیشفرض اپ استفاده میشود.';
|
||||||
SET @deposit_support_msg_desc = 'متن پیام هنگام کلیک روی «پیام به پشتیبانی» و «پیام به پشتیبانی (sms)» در مودال واریز. فقط متغیر ٪نام یا %نام = نام صاحب حساب (deposit_account_holder). پیشفرض: «شماره حساب».';
|
SET @deposit_support_msg_desc = 'متن پیام هنگام کلیک روی «پیام به پشتیبانی» و «پیام به پشتیبانی (sms)» در مودال واریز. فقط متغیر ٪نام یا %نام = نام صاحب حساب (deposit_account_holder). پیشفرض: «شماره حساب».';
|
||||||
|
|
||||||
SET @price_channel_message_desc = 'قالب متن پیام ارسالی به کانال. متغیرهای قیمت تابلو: ٪گرم_خرید ٪گرم_فروش ٪مثقال_خرید ٪مثقال_فروش (یا با %). زمان: ٪تاریخ ٪ساعت. اپ: ٪اسم_اپ یا ٪نام (نام فارسی)؛ ٪عنوان = خط «📊 قیمت لحظهای + نام». تماس جدا: ٪آیدی ٪شماره ٪لینک. اختیاری: ٪محصولات (لیست همه محصولات)؛ ٪فوتر (ترکیب آیدی+شماره+لینک). فاصله بعد از ٪ اختیاری است. خالی = قالب پیشفرض.';
|
SET @price_channel_message_desc = CONCAT(
|
||||||
|
'متن پیامی که با تغییر قیمت به کانال فرستاده میشود. هر متغیر را دقیقاً همینطور بنویسید (با ٪ یا %).', CHAR(10),
|
||||||
|
CHAR(10),
|
||||||
|
'قیمت تابلو — مثل اپ:', CHAR(10),
|
||||||
|
'• %گرم_فروش = عدد بزرگ صفحهٔ اصلی اپ (فروش هر گرم)', CHAR(10),
|
||||||
|
'• %گرم_خرید = خرید هر گرم', CHAR(10),
|
||||||
|
'• %مثقال_فروش = فروش هر مثقال', CHAR(10),
|
||||||
|
'• %مثقال_خرید = خرید هر مثقال', CHAR(10),
|
||||||
|
CHAR(10),
|
||||||
|
'زمان: %تاریخ (شمسی) • %ساعت', CHAR(10),
|
||||||
|
'نام: %نام (فقط نام فروشگاه) • %عنوان (خط آماده 📊 قیمت لحظهای + نام)', CHAR(10),
|
||||||
|
'تماس: %شماره • %آیدی • %لینک (از فیلدهای پایین همین بخش)', CHAR(10),
|
||||||
|
'اختیاری: %محصولات • %فوتر', CHAR(10),
|
||||||
|
CHAR(10),
|
||||||
|
'خالی = قالب پیشفرض.'
|
||||||
|
);
|
||||||
SET @price_channel_default_text = CONCAT(
|
SET @price_channel_default_text = CONCAT(
|
||||||
'سلام 👋', CHAR(10),
|
'سلام 👋', CHAR(10),
|
||||||
'%عنوان', CHAR(10),
|
'%عنوان', CHAR(10),
|
||||||
|
|||||||
@@ -41,7 +41,22 @@ SET @invite_link_desc = 'متن پیام اشتراکگذاری دعوت در
|
|||||||
SET @deposit_guide_desc = 'متن راهنمای واریز در مودال شارژ حساب. متغیرها: ٪نام یا %نام = نام صاحب حساب؛ ٪کارت یا %کارت = شماره کارت؛ ٪شبا یا %شبا = شبا. فاصله بعد از ٪ اختیاری است. اگر خالی باشد از متن پیشفرض اپ استفاده میشود.';
|
SET @deposit_guide_desc = 'متن راهنمای واریز در مودال شارژ حساب. متغیرها: ٪نام یا %نام = نام صاحب حساب؛ ٪کارت یا %کارت = شماره کارت؛ ٪شبا یا %شبا = شبا. فاصله بعد از ٪ اختیاری است. اگر خالی باشد از متن پیشفرض اپ استفاده میشود.';
|
||||||
SET @deposit_support_msg_desc = 'متن پیام هنگام کلیک روی «پیام به پشتیبانی» و «پیام به پشتیبانی (sms)» در مودال واریز. فقط متغیر ٪نام یا %نام = نام صاحب حساب (deposit_account_holder). پیشفرض: «شماره حساب».';
|
SET @deposit_support_msg_desc = 'متن پیام هنگام کلیک روی «پیام به پشتیبانی» و «پیام به پشتیبانی (sms)» در مودال واریز. فقط متغیر ٪نام یا %نام = نام صاحب حساب (deposit_account_holder). پیشفرض: «شماره حساب».';
|
||||||
|
|
||||||
SET @price_channel_message_desc = 'قالب متن پیام ارسالی به کانال. متغیرهای قیمت تابلو: ٪گرم_خرید ٪گرم_فروش ٪مثقال_خرید ٪مثقال_فروش (یا با %). زمان: ٪تاریخ ٪ساعت. اپ: ٪اسم_اپ یا ٪نام (نام فارسی)؛ ٪عنوان = خط «📊 قیمت لحظهای + نام». تماس جدا: ٪آیدی ٪شماره ٪لینک. اختیاری: ٪محصولات (لیست همه محصولات)؛ ٪فوتر (ترکیب آیدی+شماره+لینک). فاصله بعد از ٪ اختیاری است. خالی = قالب پیشفرض.';
|
SET @price_channel_message_desc = CONCAT(
|
||||||
|
'متن پیامی که با تغییر قیمت به کانال فرستاده میشود. هر متغیر را دقیقاً همینطور بنویسید (با ٪ یا %).', CHAR(10),
|
||||||
|
CHAR(10),
|
||||||
|
'قیمت تابلو — مثل اپ:', CHAR(10),
|
||||||
|
'• %گرم_فروش = عدد بزرگ صفحهٔ اصلی اپ (فروش هر گرم)', CHAR(10),
|
||||||
|
'• %گرم_خرید = خرید هر گرم', CHAR(10),
|
||||||
|
'• %مثقال_فروش = فروش هر مثقال', CHAR(10),
|
||||||
|
'• %مثقال_خرید = خرید هر مثقال', CHAR(10),
|
||||||
|
CHAR(10),
|
||||||
|
'زمان: %تاریخ (شمسی) • %ساعت', CHAR(10),
|
||||||
|
'نام: %نام (فقط نام فروشگاه) • %عنوان (خط آماده 📊 قیمت لحظهای + نام)', CHAR(10),
|
||||||
|
'تماس: %شماره • %آیدی • %لینک (از فیلدهای پایین همین بخش)', CHAR(10),
|
||||||
|
'اختیاری: %محصولات • %فوتر', CHAR(10),
|
||||||
|
CHAR(10),
|
||||||
|
'خالی = قالب پیشفرض.'
|
||||||
|
);
|
||||||
SET @price_channel_default_text = CONCAT(
|
SET @price_channel_default_text = CONCAT(
|
||||||
'سلام 👋', CHAR(10),
|
'سلام 👋', CHAR(10),
|
||||||
'%عنوان', CHAR(10),
|
'%عنوان', CHAR(10),
|
||||||
|
|||||||
@@ -11,7 +11,22 @@
|
|||||||
START TRANSACTION;
|
START TRANSACTION;
|
||||||
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
|
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
SET @price_channel_message_desc = 'قالب متن پیام ارسالی به کانال. متغیرهای قیمت تابلو: ٪گرم_خرید ٪گرم_فروش ٪مثقال_خرید ٪مثقال_فروش (یا با %). زمان: ٪تاریخ ٪ساعت. اپ: ٪اسم_اپ یا ٪نام (نام فارسی)؛ ٪عنوان = خط «📊 قیمت لحظهای + نام». تماس جدا: ٪آیدی ٪شماره ٪لینک. اختیاری: ٪محصولات (لیست همه محصولات)؛ ٪فوتر (ترکیب آیدی+شماره+لینک). فاصله بعد از ٪ اختیاری است. خالی = قالب پیشفرض.';
|
SET @price_channel_message_desc = CONCAT(
|
||||||
|
'متن پیامی که با تغییر قیمت به کانال فرستاده میشود. هر متغیر را دقیقاً همینطور بنویسید (با ٪ یا %).', CHAR(10),
|
||||||
|
CHAR(10),
|
||||||
|
'قیمت تابلو — مثل اپ:', CHAR(10),
|
||||||
|
'• %گرم_فروش = عدد بزرگ صفحهٔ اصلی اپ (فروش هر گرم)', CHAR(10),
|
||||||
|
'• %گرم_خرید = خرید هر گرم', CHAR(10),
|
||||||
|
'• %مثقال_فروش = فروش هر مثقال', CHAR(10),
|
||||||
|
'• %مثقال_خرید = خرید هر مثقال', CHAR(10),
|
||||||
|
CHAR(10),
|
||||||
|
'زمان: %تاریخ (شمسی) • %ساعت', CHAR(10),
|
||||||
|
'نام: %نام (فقط نام فروشگاه) • %عنوان (خط آماده 📊 قیمت لحظهای + نام)', CHAR(10),
|
||||||
|
'تماس: %شماره • %آیدی • %لینک (از فیلدهای پایین همین بخش)', CHAR(10),
|
||||||
|
'اختیاری: %محصولات • %فوتر', CHAR(10),
|
||||||
|
CHAR(10),
|
||||||
|
'خالی = قالب پیشفرض.'
|
||||||
|
);
|
||||||
SET @price_channel_default_text = CONCAT(
|
SET @price_channel_default_text = CONCAT(
|
||||||
'سلام 👋', CHAR(10),
|
'سلام 👋', CHAR(10),
|
||||||
'%عنوان', CHAR(10),
|
'%عنوان', CHAR(10),
|
||||||
|
|||||||
Reference in New Issue
Block a user