""" Appreciation models """ from django.db import models from django.utils.translation import gettext_lazy as _ from apps.core.models import BaseModel, PriorityChoices class AppreciationType(models.TextChoices): """Types of appreciations""" STAFF = 'staff', _('Staff Appreciation') PATIENT = 'patient', _('Patient Appreciation') DEPARTMENT = 'department', _('Department Appreciation') TEAM = 'team', _('Team Appreciation') INDIVIDUAL = 'individual', _('Individual Appreciation') GROUP = 'group', _('Group Appreciation') class AppreciationStatus(models.TextChoices): """Statuses for appreciations""" DRAFT = 'draft', _('Draft') SUBMITTED = 'submitted', _('Submitted') ACKNOWLEDGED = 'acknowledged', _('Acknowledged') PUBLISHED = 'published', _('Published') ARCHIVED = 'archived', _('Archived') class AppreciationCategory(models.Model): """Categories for appreciations""" name = models.CharField( max_length=100, verbose_name=_('Name'), help_text=_('Category name') ) description = models.TextField( blank=True, verbose_name=_('Description'), help_text=_('Category description') ) is_active = models.BooleanField( default=True, verbose_name=_('Is Active'), help_text=_('Whether this category is active') ) display_order = models.PositiveIntegerField( default=0, verbose_name=_('Display Order'), help_text=_('Order for displaying categories') ) created_at = models.DateTimeField( auto_now_add=True, verbose_name=_('Created At') ) updated_at = models.DateTimeField( auto_now=True, verbose_name=_('Updated At') ) class Meta: verbose_name = _('Appreciation Category') verbose_name_plural = _('Appreciation Categories') ordering = ['display_order', 'name'] def __str__(self): return self.name class Appreciation(BaseModel): """Appreciation model for recognizing and rewarding excellence""" uuid = models.UUIDField( unique=True, editable=False, db_index=True, verbose_name=_('UUID') ) # Basic Information title = models.CharField( max_length=255, verbose_name=_('Title'), help_text=_('Title of the appreciation') ) description = models.TextField( verbose_name=_('Description'), help_text=_('Detailed description of the appreciation') ) story = models.TextField( blank=True, verbose_name=_('Story'), help_text=_('The story behind this appreciation') ) # Classification appreciation_type = models.CharField( max_length=20, choices=AppreciationType.choices, verbose_name=_('Appreciation Type'), help_text=_('Type of appreciation') ) category = models.ForeignKey( AppreciationCategory, on_delete=models.SET_NULL, null=True, blank=True, related_name='appreciations', verbose_name=_('Category'), help_text=_('Category of appreciation') ) status = models.CharField( max_length=20, choices=AppreciationStatus.choices, default=AppreciationStatus.DRAFT, verbose_name=_('Status'), help_text=_('Status of appreciation') ) # Organization hospital = models.ForeignKey( 'organizations.Hospital', on_delete=models.CASCADE, related_name='appreciations', verbose_name=_('Hospital'), help_text=_('Hospital where this appreciation occurred') ) department = models.ForeignKey( 'organizations.Department', on_delete=models.SET_NULL, null=True, blank=True, related_name='appreciations', verbose_name=_('Department'), help_text=_('Department where this appreciation occurred') ) # Recipient Information recipient_name = models.CharField( max_length=255, verbose_name=_('Recipient Name'), help_text=_('Name of the person or team being appreciated') ) recipient_type = models.CharField( max_length=50, verbose_name=_('Recipient Type'), help_text=_('Type of recipient (e.g., Staff, Patient, Department)') ) recipient_id = models.CharField( max_length=100, blank=True, verbose_name=_('Recipient ID'), help_text=_('ID of the recipient in the system') ) # Submitter Information submitted_by = models.ForeignKey( 'accounts.User', on_delete=models.CASCADE, related_name='submitted_appreciations', verbose_name=_('Submitted By'), help_text=_('User who submitted this appreciation') ) submitter_role = models.CharField( max_length=100, blank=True, verbose_name=_('Submitter Role'), help_text=_('Role of the submitter') ) # Acknowledgment acknowledged_by = models.ForeignKey( 'accounts.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='acknowledged_appreciations', verbose_name=_('Acknowledged By'), help_text=_('User who acknowledged this appreciation') ) acknowledged_at = models.DateTimeField( null=True, blank=True, verbose_name=_('Acknowledged At'), help_text=_('When this appreciation was acknowledged') ) acknowledgment_notes = models.TextField( blank=True, verbose_name=_('Acknowledgment Notes'), help_text=_('Notes added during acknowledgment') ) # Timeline submitted_at = models.DateTimeField( null=True, blank=True, verbose_name=_('Submitted At'), help_text=_('When this appreciation was submitted') ) published_at = models.DateTimeField( null=True, blank=True, verbose_name=_('Published At'), help_text=_('When this appreciation was published') ) # Visibility and Sharing is_public = models.BooleanField( default=False, verbose_name=_('Is Public'), help_text=_('Whether this appreciation is publicly visible') ) share_on_dashboard = models.BooleanField( default=True, verbose_name=_('Share on Dashboard'), help_text=_('Whether to display on the dashboard') ) share_in_newsletter = models.BooleanField( default=False, verbose_name=_('Share in Newsletter'), help_text=_('Whether to include in newsletter') ) # Additional Details tags = models.JSONField( default=list, blank=True, verbose_name=_('Tags'), help_text=_('Tags for categorization and search') ) impact_score = models.PositiveIntegerField( default=0, verbose_name=_('Impact Score'), help_text=_('Score indicating the impact of this appreciation') ) metadata = models.JSONField( default=dict, blank=True, verbose_name=_('Metadata'), help_text=_('Additional metadata as key-value pairs' ) class Meta: verbose_name = _('Appreciation') verbose_name_plural = _('Appreciations') ordering = ['-created_at'] indexes = [ models.Index(fields=['status']), models.Index(fields=['appreciation_type']), models.Index(fields=['hospital']), models.Index(fields=['created_at']), ] def __str__(self): return f"{self.title} - {self.recipient_name}" def save(self, *args, **kwargs): # Auto-set submitted_at when status changes to submitted if self.status == AppreciationStatus.SUBMITTED and not self.submitted_at: from django.utils import timezone self.submitted_at = timezone.now() # Auto-set published_at when status changes to published if self.status == AppreciationStatus.PUBLISHED and not self.published_at: from django.utils import timezone self.published_at = timezone.now() super().save(*args, **kwargs) class AppreciationAttachment(models.Model): """Attachments for appreciations""" appreciation = models.ForeignKey( Appreciation, on_delete=models.CASCADE, related_name='attachments', verbose_name=_('Appreciation'), help_text=_('Associated appreciation') ) file = models.FileField( upload_to='appreciations/attachments/%Y/%m/', verbose_name=_('File'), help_text=_('Attachment file') ) filename = models.CharField( max_length=255, verbose_name=_('Filename'), help_text=_('Original filename') ) file_type = models.CharField( max_length=100, blank=True, verbose_name=_('File Type'), help_text=_('MIME type of file') ) file_size = models.PositiveIntegerField( verbose_name=_('File Size'), help_text=_('Size of file in bytes') ) description = models.TextField( blank=True, verbose_name=_('Description'), help_text=_('Description of the attachment') ) uploaded_by = models.ForeignKey( 'accounts.User', on_delete=models.CASCADE, related_name='appreciation_uploads', verbose_name=_('Uploaded By'), help_text=_('User who uploaded this attachment') ) created_at = models.DateTimeField( auto_now_add=True, verbose_name=_('Created At') ) class Meta: verbose_name = _('Appreciation Attachment') verbose_name_plural = _('Appreciation Attachments') ordering = ['-created_at'] def __str__(self): return f"{self.filename} - {self.appreciation.title}" class AppreciationReaction(models.Model): """Reactions to appreciations (likes, emojis, etc.)""" appreciation = models.ForeignKey( Appreciation, on_delete=models.CASCADE, related_name='reactions', verbose_name=_('Appreciation'), help_text=_('Associated appreciation') ) user = models.ForeignKey( 'accounts.User', on_delete=models.CASCADE, related_name='appreciation_reactions', verbose_name=_('User'), help_text=_('User who reacted') ) reaction_type = models.CharField( max_length=50, verbose_name=_('Reaction Type'), help_text=_('Type of reaction (e.g., like, heart, star)' ) created_at = models.DateTimeField( auto_now_add=True, verbose_name=_('Created At') ) class Meta: verbose_name = _('Appreciation Reaction') verbose_name_plural = _('Appreciation Reactions') unique_together = ['appreciation', 'user'] ordering = ['-created_at'] def __str__(self): return f"{self.user.email} - {self.reaction_type}" class AppreciationComment(models.Model): """Comments on appreciations""" appreciation = models.ForeignKey( Appreciation, on_delete=models.CASCADE, related_name='comments', verbose_name=_('Appreciation'), help_text=_('Associated appreciation') ) user = models.ForeignKey( 'accounts.User', on_delete=models.CASCADE, related_name='appreciation_comments', verbose_name=_('User'), help_text=_('User who commented') ) comment = models.TextField( verbose_name=_('Comment'), help_text=_('Comment text') ) parent = models.ForeignKey( 'self', on_delete=models.CASCADE, null=True, blank=True, related_name='replies', verbose_name=_('Parent Comment'), help_text=_('Parent comment for nested replies') ) is_internal = models.BooleanField( default=False, verbose_name=_('Is Internal'), help_text=_('Whether this is an internal comment') ) created_at = models.DateTimeField( auto_now_add=True, verbose_name=_('Created At') ) updated_at = models.DateTimeField( auto_now=True, verbose_name=_('Updated At') ) class Meta: verbose_name = _('Appreciation Comment') verbose_name_plural = _('Appreciation Comments') ordering = ['-created_at'] def __str__(self): return f"{self.user.email}: {self.comment[:50]}"