bale bot
This commit is contained in:
1 parent
99a86c7073
commit
f19d8ee6a7
2 files changed
+168
-1
No files matched your search
@@ -0,0 +1,166 @@
|
||||
import requests
|
||||
import logging
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
from django.db.models import Sum, Count, Avg, Q
|
||||
from persiantools.jdatetime import JalaliDateTime
|
||||
from admin_panel.models import Customer, Factor, Action, Article, Sarresid
|
||||
|
||||
# تنظیم لاگر برای ثبت خطاهای احتمالی سیستم بدون نمایش به کاربر
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'ارسال گزارش جامع عملیات روزانه به پیامرسان بله'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# ⚠️ اطلاعات اتصال به API بله
|
||||
BALE_BOT_TOKEN = '422476936:gDClZVRB8NxDKXoo9XE7EcZPLr0yqkOu-F0'
|
||||
CHAT_ID = '5063785185'
|
||||
|
||||
# --- ۱. تنظیمات زمان و تاریخ کاملا دقیق (با در نظر گرفتن تایمزون ایران) ---
|
||||
now = timezone.localtime(timezone.now())
|
||||
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
today_end = now.replace(hour=23, minute=59, second=59, microsecond=999999)
|
||||
|
||||
# تبدیل تاریخ میلادی به تاریخ دقیق شمسی برای هدر پیام
|
||||
jalali_date = JalaliDateTime(now).strftime('%Y/%m/%d')
|
||||
|
||||
try:
|
||||
# --- ۲. بهینهسازی کوئریها (تجمیع در سطح دیتابیس برای حداکثر سرعت) ---
|
||||
|
||||
# آمار مشتریان
|
||||
new_customers_count = Customer.objects.filter(create_date__range=(today_start, today_end)).count()
|
||||
|
||||
# آمار فاکتورها (استفاده از Aggregate یکپارچه به جای چندین کوئری مجزا)
|
||||
factor_stats = Factor.objects.filter(create_date__range=(today_start, today_end)).aggregate(
|
||||
total_sales=Sum('amount', filter=Q(is_active=True)),
|
||||
active_count=Count('id', filter=Q(is_active=True)),
|
||||
canceled_count=Count('id', filter=Q(is_active=False)),
|
||||
nasb_count=Count('id', filter=Q(is_active=True, FactorType__iexact='Nasb'))
|
||||
)
|
||||
|
||||
total_sales = factor_stats['total_sales'] or 0
|
||||
factors_count = factor_stats['active_count'] or 0
|
||||
canceled_factors_count = factor_stats['canceled_count'] or 0
|
||||
nasb_count = factor_stats['nasb_count'] or 0
|
||||
|
||||
# آمار وصولیها (فقط مقادیر واریزی خالص بدون اسناد ابطالی)
|
||||
vosol_stats = Article.objects.filter(
|
||||
createdDT__range=(today_start, today_end),
|
||||
credit__gt=0,
|
||||
nahvePardakht__isnull=False
|
||||
).exclude(payStatus='cancell').aggregate(
|
||||
total_vosol=Sum('credit'),
|
||||
vosol_count=Count('id')
|
||||
)
|
||||
|
||||
total_vosol = vosol_stats['total_vosol'] or 0
|
||||
vosol_count = vosol_stats['vosol_count'] or 0
|
||||
|
||||
# آمار چکهای خطرناک (بحران نقدینگی: سررسید شده و پاس نشده)
|
||||
overdue_checks = Sarresid.objects.filter(
|
||||
type='check',
|
||||
payStatus='false',
|
||||
sarresidDT__lte=today_end
|
||||
).aggregate(
|
||||
total_amount=Sum('price'),
|
||||
check_count=Count('id')
|
||||
)
|
||||
|
||||
overdue_checks_amount = overdue_checks['total_amount'] or 0
|
||||
overdue_checks_count = overdue_checks['check_count'] or 0
|
||||
|
||||
# آمار عملیات و پرسنل (بر اساس actionDateTime که در سیستم شما معیار "امروز" است)
|
||||
completed_actions = Action.objects.filter(
|
||||
actionDateTime__range=(today_start, today_end),
|
||||
status='finish'
|
||||
)
|
||||
|
||||
bazdid_count = completed_actions.filter(actionType='bazdid').count()
|
||||
|
||||
staff_performance = completed_actions.exclude(forUser__username='admin').values(
|
||||
'forUser__first_name', 'forUser__last_name', 'forUser__username'
|
||||
).annotate(task_count=Count('id')).order_by('-task_count')
|
||||
|
||||
staff_text = ""
|
||||
for staff in staff_performance:
|
||||
first = staff.get('forUser__first_name') or ''
|
||||
last = staff.get('forUser__last_name') or ''
|
||||
name = f"{first} {last}".strip()
|
||||
if not name:
|
||||
name = staff.get('forUser__username') or "کاربر ناشناس"
|
||||
staff_text += f"\n🔹 {name}: {staff['task_count']} کار"
|
||||
|
||||
if not staff_text:
|
||||
staff_text = "\n🔹 هیچ کار/بازدیدی امروز تکمیل نشده است."
|
||||
|
||||
# آمار نظرسنجیها
|
||||
nazar_stats = Action.objects.filter(
|
||||
nazarDT__range=(today_start, today_end),
|
||||
grade__gt=0
|
||||
).aggregate(
|
||||
avg_grade=Avg('grade'),
|
||||
total_count=Count('id')
|
||||
)
|
||||
|
||||
nazar_count = nazar_stats['total_count'] or 0
|
||||
nazar_avg = round(nazar_stats['avg_grade'] or 0, 1)
|
||||
|
||||
except Exception as db_error:
|
||||
# اگر خطایی در دیتابیس رخ داد، کل پروسه با لاگ متوقف میشود و سایت اصلی آسیب نمیبیند
|
||||
logger.error(f"Database Error in daily report: {db_error}")
|
||||
self.stdout.write(self.style.ERROR('خطا در خواندن اطلاعات از دیتابیس'))
|
||||
return
|
||||
|
||||
# --- ۳. قالببندی پیام خروجی (با تاریخ شمسی) ---
|
||||
report_text = f"""📊 **گزارش جامع عملیات روزانه**
|
||||
📅 تاریخ: {jalali_date}
|
||||
|
||||
👥 **آمار مشتریان:**
|
||||
🔸 تشکیل پرونده جدید: {new_customers_count} نفر
|
||||
|
||||
🛒 **آمار فروش:**
|
||||
🔸 جمع فروش: {total_sales:,.0f} تومان ({factors_count} فاکتور)
|
||||
⚠️ فاکتورهای ابطال شده: {canceled_factors_count} مورد
|
||||
|
||||
💵 **خزانه و وصولی امروز:**
|
||||
🔸 دریافتی و وصولی: {vosol_count} مورد (مبلغ {total_vosol:,.0f} تومان)
|
||||
🚨 کل چکهای پاسنشده تا الان: {overdue_checks_count} فقره (مبلغ {overdue_checks_amount:,.0f} تومان)
|
||||
|
||||
⚙️ **خدمات و عملیات امروز:**
|
||||
🔸 نصب دستگاه جدید: {nasb_count} مورد
|
||||
🔸 بازدید و تعویض فیلتر: {bazdid_count} مورد
|
||||
|
||||
👨🔧 **عملکرد پرسنل (تسکهای تکمیلشده):** {staff_text}
|
||||
|
||||
📞 **مرکز تماس و رضایتسنجی امروز:**
|
||||
🔸 نظرسنجیهای ثبت شده: {nazar_count} مورد
|
||||
🔸 میانگین رضایت: {nazar_avg} از 20
|
||||
|
||||
⚡ *سلطان تصفیه آب ایران، اگه میخواهی مو رو از ماست بکشی به پنل مراجعه کن 😘.*"""
|
||||
|
||||
# --- ۴. ارسال ایمن به API بله (بدون تداخل با سیستم اصلی) ---
|
||||
url = f"https://tapi.bale.ai/bot{BALE_BOT_TOKEN}/sendMessage"
|
||||
payload = {
|
||||
"chat_id": CHAT_ID,
|
||||
"text": report_text
|
||||
}
|
||||
|
||||
try:
|
||||
# timeout=7 شدیدا توصیه میشود تا اسکریپت هنگ نکند و منابع سرور هدر نرود
|
||||
response = requests.post(url, json=payload, timeout=7)
|
||||
if response.status_code == 200:
|
||||
self.stdout.write(self.style.SUCCESS('گزارش با موفقیت به پیامرسان بله ارسال شد.'))
|
||||
else:
|
||||
self.stdout.write(self.style.ERROR(f'خطای API بله: {response.text}'))
|
||||
logger.error(f"Bale API Error: {response.text}")
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
self.stdout.write(self.style.ERROR('خطا: پایان زمان اتصال به سرور بله (Timeout). پیام ارسال نشد.'))
|
||||
logger.warning("Bale API Timeout. Report not sent.")
|
||||
except requests.exceptions.RequestException as e:
|
||||
self.stdout.write(self.style.ERROR(f'خطای شبکه در ارتباط با سرور بله: {str(e)}'))
|
||||
logger.error(f"Bale API Network Error: {str(e)}")
|
||||
except Exception as e:
|
||||
self.stdout.write(self.style.ERROR('خطای سیستمی ناشناخته رخ داد.'))
|
||||
logger.critical(f"Unknown error in daily report API call: {str(e)}")
|
||||
Reference in new issue
Block a user