Игорь Надеин 6fb2cdcea0 feat: enhance Employee model and integrate Telegram/WhatsApp bot
- Add birth_date, created_at/updated_at to Employee; remove username field
- Introduce EmployeeAction for tracking HR events and is_actually_active/status properties
- Create BotSubscriber model (OneToOne relation) for TG/WA binding
- Implement Aiogram-based Telegram bot:
  • request contact to bind by phone or @username
  • department selection keyboard from DEPARTMENTS dict
  • async ORM via sync_to_async, custom filters for bound & active employees
- Update profile view & template:
  • show “Bind Telegram/WhatsApp” button only when not already bound
  • preview avatar on upload
- Remove registration tokens in favor of contact-based auth
- Clean up templates, forms and add avatar validation mixin
2025-07-30 08:15:53 +03:00

117 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# documents/admin.py
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from django.utils.html import format_html, mark_safe
from django.urls import reverse
from .models import Document, DocumentAcknowledgement
from django.contrib.auth import get_user_model
User = get_user_model()
class AcknowledgementInline(admin.TabularInline):
model = DocumentAcknowledgement
extra = 0
can_delete = False
verbose_name = _("Ознакомление")
verbose_name_plural = _("Ознакомления")
fields = ('user_link', 'acknowledged_at')
readonly_fields = ('user_link', 'acknowledged_at')
def user_link(self, obj):
url = reverse(
'admin:{}_{}_change'.format(
User._meta.app_label, User._meta.model_name
), args=[obj.user.pk]
)
return format_html('<a href="{}">{}</a>', url, obj.user.get_full_name() or obj.user)
user_link.short_description = _("Сотрудник")
@admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
inlines = [AcknowledgementInline]
list_display = (
'title', 'uploaded_at', 'sent_to_all',
# убрали 'pending_summary'
)
list_filter = ('sent_to_all', 'uploaded_at')
search_fields = ('title', 'description')
filter_horizontal = ('recipients',)
actions = ['send_document']
fieldsets = (
(None, {
'fields': ('title', 'file', 'description', 'recipients', 'sent_to_all'),
}),
(_('Meta'), {
'fields': ('uploaded_by', 'uploaded_at'),
'classes': ('collapse',),
}),
(_('Ознакомление'), {
'fields': ('recipients_summary', 'pending_list'),
}),
)
readonly_fields = (
'uploaded_by', 'uploaded_at',
'recipients_summary', 'pending_list',
)
def save_model(self, request, obj, form, change):
if not obj.pk:
obj.uploaded_by = request.user
super().save_model(request, obj, form, change)
def send_document(self, request, queryset):
from .tasks import send_document_to_recipients
for doc in queryset:
send_document_to_recipients.delay(doc.id)
self.message_user(request, _("Рассылка запущена."))
send_document.short_description = _('Отправить документ')
def get_recipients_qs(self, obj):
return User.objects.filter(is_active=True) if obj.sent_to_all else obj.recipients.all()
def recipients_summary(self, obj):
qs = self.get_recipients_qs(obj)
names = [u.get_full_name() or str(u) for u in qs[:5]]
count = qs.count()
if count > 5:
return format_html("{}… (ещё {})", ", ".join(names), count - 5)
return ", ".join(names) if names else _("— никто —")
recipients_summary.short_description = _('Получатели')
def pending_list(self, obj):
recipients = set(self.get_recipients_qs(obj))
acked_ids = set(
DocumentAcknowledgement.objects
.filter(document=obj)
.values_list('user_id', flat=True)
)
pending = [u for u in recipients if u.id not in acked_ids]
if not pending:
return format_html('<span style="color:green;">{}</span>', _("Все ознакомились"))
links = []
for u in pending:
url = reverse(
'admin:{}_{}_change'.format(
User._meta.app_label, User._meta.model_name
), args=[u.pk]
)
links.append(format_html('<a href="{}">{}</a>',
url, u.get_full_name() or u))
return mark_safe('<br>'.join(links))
pending_list.short_description = _('Кто ещё не ознакомился')
@admin.register(DocumentAcknowledgement)
class DocumentAcknowledgementAdmin(admin.ModelAdmin):
list_display = ('document', 'user', 'acknowledged_at')
list_filter = ('document', 'acknowledged_at')
search_fields = ('user__phone_number',
'user__last_name', 'document__title')
readonly_fields = ('user', 'document', 'acknowledged_at')
ordering = ('-acknowledged_at',)