207 lines
7.3 KiB
Python
207 lines
7.3 KiB
Python
"""
|
|
Chat Models für Live-Chat System
|
|
"""
|
|
|
|
from django.db import models
|
|
from django.contrib.auth.models import User
|
|
from django.utils import timezone
|
|
from django.conf import settings
|
|
import uuid
|
|
|
|
|
|
class ChatRoom(models.Model):
|
|
"""Chat-Raum für Kunde-Admin Kommunikation"""
|
|
|
|
ROOM_STATUS_CHOICES = [
|
|
('active', 'Aktiv'),
|
|
('waiting', 'Wartend'),
|
|
('closed', 'Geschlossen'),
|
|
('archived', 'Archiviert'),
|
|
]
|
|
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
customer = models.ForeignKey(User, on_delete=models.CASCADE, related_name='customer_chats')
|
|
admin = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='admin_chats')
|
|
status = models.CharField(max_length=20, choices=ROOM_STATUS_CHOICES, default='waiting')
|
|
subject = models.CharField(max_length=200, blank=True)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
last_message_at = models.DateTimeField(null=True, blank=True)
|
|
|
|
class Meta:
|
|
ordering = ['-last_message_at', '-created_at']
|
|
verbose_name = 'Chat-Raum'
|
|
verbose_name_plural = 'Chat-Räume'
|
|
|
|
def __str__(self):
|
|
return f"Chat {self.id} - {self.customer.username}"
|
|
|
|
def get_unread_count(self, user):
|
|
"""Anzahl ungelesener Nachrichten für User"""
|
|
return self.messages.filter(
|
|
sender__in=self.get_other_users(user),
|
|
read_at__isnull=True
|
|
).count()
|
|
|
|
def get_other_users(self, user):
|
|
"""Andere User im Chat"""
|
|
if user == self.customer:
|
|
return [self.admin] if self.admin else []
|
|
elif user == self.admin:
|
|
return [self.customer]
|
|
return []
|
|
|
|
def mark_messages_as_read(self, user):
|
|
"""Nachrichten als gelesen markieren"""
|
|
other_users = self.get_other_users(user)
|
|
self.messages.filter(
|
|
sender__in=other_users,
|
|
read_at__isnull=True
|
|
).update(read_at=timezone.now())
|
|
|
|
|
|
class ChatMessage(models.Model):
|
|
"""Chat-Nachricht"""
|
|
|
|
MESSAGE_TYPE_CHOICES = [
|
|
('text', 'Text'),
|
|
('image', 'Bild'),
|
|
('file', 'Datei'),
|
|
('system', 'System'),
|
|
]
|
|
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE, related_name='messages')
|
|
sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sent_messages')
|
|
message_type = models.CharField(max_length=20, choices=MESSAGE_TYPE_CHOICES, default='text')
|
|
content = models.TextField()
|
|
file = models.FileField(upload_to='chat_files/', null=True, blank=True)
|
|
image = models.ImageField(upload_to='chat_images/', null=True, blank=True)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
read_at = models.DateTimeField(null=True, blank=True)
|
|
is_system_message = models.BooleanField(default=False)
|
|
|
|
class Meta:
|
|
ordering = ['created_at']
|
|
verbose_name = 'Chat-Nachricht'
|
|
verbose_name_plural = 'Chat-Nachrichten'
|
|
|
|
def __str__(self):
|
|
return f"{self.sender.username}: {self.content[:50]}"
|
|
|
|
def save(self, *args, **kwargs):
|
|
"""Nachricht speichern und Room aktualisieren"""
|
|
is_new = self.pk is None
|
|
super().save(*args, **kwargs)
|
|
|
|
if is_new:
|
|
# Room last_message_at aktualisieren
|
|
self.room.last_message_at = self.created_at
|
|
self.room.save(update_fields=['last_message_at'])
|
|
|
|
|
|
class ChatNotification(models.Model):
|
|
"""Chat-Benachrichtigungen"""
|
|
|
|
NOTIFICATION_TYPE_CHOICES = [
|
|
('new_message', 'Neue Nachricht'),
|
|
('room_assigned', 'Raum zugewiesen'),
|
|
('room_closed', 'Raum geschlossen'),
|
|
('customer_online', 'Kunde online'),
|
|
('customer_offline', 'Kunde offline'),
|
|
]
|
|
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='chat_notifications')
|
|
room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE, related_name='notifications')
|
|
notification_type = models.CharField(max_length=20, choices=NOTIFICATION_TYPE_CHOICES)
|
|
title = models.CharField(max_length=200)
|
|
message = models.TextField()
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
read_at = models.DateTimeField(null=True, blank=True)
|
|
sent_via_email = models.BooleanField(default=False)
|
|
sent_via_push = models.BooleanField(default=False)
|
|
|
|
class Meta:
|
|
ordering = ['-created_at']
|
|
verbose_name = 'Chat-Benachrichtigung'
|
|
verbose_name_plural = 'Chat-Benachrichtigungen'
|
|
|
|
def __str__(self):
|
|
return f"{self.notification_type}: {self.title}"
|
|
|
|
|
|
class UserOnlineStatus(models.Model):
|
|
"""Online-Status von Benutzern"""
|
|
|
|
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='online_status')
|
|
is_online = models.BooleanField(default=False)
|
|
last_seen = models.DateTimeField(auto_now=True)
|
|
current_room = models.ForeignKey(ChatRoom, on_delete=models.SET_NULL, null=True, blank=True)
|
|
|
|
class Meta:
|
|
verbose_name = 'Online-Status'
|
|
verbose_name_plural = 'Online-Status'
|
|
|
|
def __str__(self):
|
|
status = "Online" if self.is_online else "Offline"
|
|
return f"{self.user.username} - {status}"
|
|
|
|
|
|
class QuickResponse(models.Model):
|
|
"""Schnelle Antworten für Admins"""
|
|
|
|
category = models.CharField(max_length=50, choices=[
|
|
('greeting', 'Begrüßung'),
|
|
('pricing', 'Preise'),
|
|
('shipping', 'Versand'),
|
|
('custom_order', 'Custom Order'),
|
|
('technical', 'Technische Fragen'),
|
|
('general', 'Allgemein'),
|
|
])
|
|
title = models.CharField(max_length=100)
|
|
content = models.TextField()
|
|
created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='quick_responses')
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
is_active = models.BooleanField(default=True)
|
|
use_count = models.IntegerField(default=0)
|
|
|
|
class Meta:
|
|
ordering = ['category', 'title']
|
|
verbose_name = 'Schnelle Antwort'
|
|
verbose_name_plural = 'Schnelle Antworten'
|
|
|
|
def __str__(self):
|
|
return f"{self.category}: {self.title}"
|
|
|
|
def increment_use_count(self):
|
|
"""Verwendungszähler erhöhen"""
|
|
self.use_count += 1
|
|
self.save(update_fields=['use_count'])
|
|
|
|
|
|
class ChatAnalytics(models.Model):
|
|
"""Chat-Analytics für Performance-Tracking"""
|
|
|
|
date = models.DateField()
|
|
total_messages = models.IntegerField(default=0)
|
|
total_rooms = models.IntegerField(default=0)
|
|
active_rooms = models.IntegerField(default=0)
|
|
avg_response_time = models.FloatField(default=0) # in Sekunden
|
|
customer_satisfaction = models.FloatField(default=0) # 0-5 Sterne
|
|
total_duration = models.FloatField(default=0) # in Minuten
|
|
|
|
class Meta:
|
|
unique_together = ['date']
|
|
verbose_name = 'Chat-Analytics'
|
|
verbose_name_plural = 'Chat-Analytics'
|
|
|
|
def __str__(self):
|
|
return f"Chat Analytics - {self.date}"
|
|
|
|
@classmethod
|
|
def get_or_create_today(cls):
|
|
"""Heutige Analytics erstellen oder abrufen"""
|
|
today = timezone.now().date()
|
|
analytics, created = cls.objects.get_or_create(date=today)
|
|
return analytics |