fix(notification): fixed formatting and linting

This commit is contained in:
sankalp committed 2025-12-11 21:09:14 +05:45
1 parent 466d4b868a
commit 63d63d5e5c
7 files changed
+57 -57

No files matched your search

+1 -1
View File
@@ -4,8 +4,8 @@
from src.admin import ( # noqa: F401
clients,
finance,
notifications,
productivity,
projects,
services,
notifications,
)
+2
View File
@@ -1,7 +1,9 @@
from django.contrib import admin
from src.admin.base import admin_site
from src.models.notifications import Notification
@admin.register(Notification, site=admin_site)
class NotificationAdmin(admin.ModelAdmin):
list_display = ("recipient", "subject", "status", "sent_at", "created_at")
@@ -1,8 +1,10 @@
from django.core.management.base import BaseCommand
from src.models.notifications import check_and_send_notifications
class Command(BaseCommand):
help = 'Checks for upcoming deadlines and sends notifications.'
help = "Checks for upcoming deadlines and sends notifications."
def handle(self, *args, **options):
self.stdout.write("Checking for notifications...")
-1
View File
@@ -5,7 +5,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("contenttypes", "0002_remove_content_type_name"),
("src", "0002_alter_client_phone"),
+1 -2
View File
@@ -1,5 +1,4 @@
"""generated with djinit"""
# Create your models here.
from .notifications import Notification
from .notifications import Notification as Notification
+32 -28
View File
@@ -1,19 +1,20 @@
from django.db import models
from django.core.mail import send_mail
from django.conf import settings
from django.utils import timezone
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth import get_user_model
from django.core.mail import send_mail
from django.db import models
from django.utils import timezone
from src.models.base import TimeStampedModel
from src.models.projects import Project, Milestone, Task
from src.models.services import Service
from src.models.finance import Invoice
from src.models.productivity import TimeEntry
from src.models.projects import Milestone, Project, Task
from src.models.services import Service
User = get_user_model()
class Notification(TimeStampedModel):
STATUS_CHOICES = [
("PENDING", "Pending"),
@@ -26,11 +27,13 @@ class Notification(TimeStampedModel):
message = models.TextField()
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="PENDING")
sent_at = models.DateTimeField(null=True, blank=True)
# Generic relation to link to the source object (Project, Invoice, etc.)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True)
content_type = models.ForeignKey(
ContentType, on_delete=models.CASCADE, null=True, blank=True
)
object_id = models.PositiveIntegerField(null=True, blank=True)
content_object = GenericForeignKey('content_type', 'object_id')
content_object = GenericForeignKey("content_type", "object_id")
class Meta:
ordering = ["-created_at"]
@@ -62,9 +65,9 @@ def get_admin_emails():
admins = getattr(settings, "ADMINS", [])
if admins:
return [email for name, email in admins]
# Fallback to superusers
return list(User.objects.filter(is_superuser=True).values_list('email', flat=True))
return list(User.objects.filter(is_superuser=True).values_list("email", flat=True))
def create_and_send(recipient, subject, message, obj=None):
@@ -77,7 +80,7 @@ def create_and_send(recipient, subject, message, obj=None):
subject=subject,
content_type=ct,
object_id=obj.id,
created_at__date=timezone.localdate()
created_at__date=timezone.localdate(),
).exists()
if already_sent:
return
@@ -100,7 +103,7 @@ def check_and_send_notifications():
"""
today = timezone.localdate()
tomorrow = today + timezone.timedelta(days=1)
admin_emails = get_admin_emails()
if not admin_emails:
print("Warning: No admin emails found.")
@@ -115,16 +118,16 @@ def check_and_send_notifications():
recipient=project.client.email,
subject=f"Project Deadline Reminder: {project.name}",
message=f"Dear {project.client.name},\n\nThe project '{project.name}' is due on {project.deadline}.\n\nRegards,\nDevSuite",
obj=project
obj=project,
)
# Notify Admin
for email in admin_emails:
create_and_send(
recipient=email,
subject=f"Admin Alert: Project Deadline - {project.name}",
message=f"Project '{project.name}' for client {project.client.name} is due on {project.deadline}.",
obj=project
obj=project,
)
# --- Milestones (Due Date) ---
@@ -138,16 +141,16 @@ def check_and_send_notifications():
recipient=project.client.email,
subject=f"Milestone Due: {milestone.title}",
message=f"Dear {project.client.name},\n\nThe milestone '{milestone.title}' for project '{project.name}' is due on {milestone.due_date}.\n\nRegards,\nDevSuite",
obj=milestone
obj=milestone,
)
# Notify Admin
for email in admin_emails:
create_and_send(
recipient=email,
subject=f"Admin Alert: Milestone Due - {milestone.title}",
message=f"Milestone '{milestone.title}' (Project: {project.name}) is due on {milestone.due_date}.",
obj=milestone
obj=milestone,
)
# --- Tasks (Due Date) ---
@@ -159,7 +162,7 @@ def check_and_send_notifications():
recipient=email,
subject=f"Task Due: {task.title}",
message=f"Task '{task.title}' (Project: {task.project.name}) is due on {task.due_date}.",
obj=task
obj=task,
)
# --- Services (Expiry Date) ---
@@ -171,33 +174,34 @@ def check_and_send_notifications():
recipient=service.client.email,
subject=f"Service Expiry Warning: {service.name}",
message=f"Dear {service.client.name},\n\nYour service '{service.name}' ({service.get_service_type_display()}) expires on {service.expiry_date}.\nPlease renew it soon.\n\nRegards,\nDevSuite",
obj=service
obj=service,
)
# --- Invoices (Due Date) ---
# Notify Client
invoices_due = Invoice.objects.filter(due_date=tomorrow, status__in=["SENT", "OVERDUE"])
invoices_due = Invoice.objects.filter(
due_date=tomorrow, status__in=["SENT", "OVERDUE"]
)
for invoice in invoices_due:
if invoice.client.email:
create_and_send(
recipient=invoice.client.email,
subject=f"Invoice Due: {invoice.invoice_number}",
message=f"Dear {invoice.client.name},\n\nInvoice {invoice.invoice_number} for {invoice.amount} is due on {invoice.due_date}.\nPlease make payment.\n\nRegards,\nDevSuite",
obj=invoice
obj=invoice,
)
# --- Productivity / TimeEntries ---
# Notify Admin for recently completed time entries (last 24h)
recent_entries = TimeEntry.objects.filter(
end_time__gte=timezone.now() - timezone.timedelta(hours=24),
end_time__lte=timezone.now()
end_time__lte=timezone.now(),
)
for entry in recent_entries:
# Check if we already sent a notification for this entry
if Notification.objects.filter(
content_type=ContentType.objects.get_for_model(entry),
object_id=entry.id
content_type=ContentType.objects.get_for_model(entry), object_id=entry.id
).exists():
continue
@@ -206,5 +210,5 @@ def check_and_send_notifications():
recipient=email,
subject=f"Time Entry Logged: {entry.description}",
message=f"User logged time for '{entry.description}'.\nDuration: {entry.duration}\nEnd Time: {entry.end_time}",
obj=entry
obj=entry,
)
+18 -24
View File
@@ -1,56 +1,50 @@
from django.contrib.auth import get_user_model
from django.core import mail
from django.test import TestCase
from django.utils import timezone
from django.core import mail
from django.contrib.auth import get_user_model
from src.models.projects import Project
from src.models.clients import Client
from src.models.notifications import check_and_send_notifications, Notification
from src.models.notifications import Notification, check_and_send_notifications
from src.models.projects import Project
User = get_user_model()
class NotificationTests(TestCase):
def test_send_deadline_notifications(self):
# Setup
admin = User.objects.create_superuser('admin', 'admin@example.com', 'password')
User.objects.create_superuser("admin", "admin@example.com", "password")
client = Client.objects.create(name="Test Client", email="client@example.com")
# Project due tomorrow
tomorrow = timezone.localdate() + timezone.timedelta(days=1)
project = Project.objects.create(
name="Test Project",
client=client,
deadline=tomorrow
)
Project.objects.create(name="Test Project", client=client, deadline=tomorrow)
# Run notification check
check_and_send_notifications()
# Verify emails sent
# Expecting 2 emails: 1 to client, 1 to admin
self.assertEqual(len(mail.outbox), 2)
# Verify Notification objects created
self.assertEqual(Notification.objects.count(), 2)
client_notif = Notification.objects.get(recipient="client@example.com")
self.assertIn("Project Deadline Reminder", client_notif.subject)
admin_notif = Notification.objects.get(recipient="admin@example.com")
self.assertIn("Admin Alert", admin_notif.subject)
def test_no_notifications_if_not_due(self):
# Setup
client = Client.objects.create(name="Test Client", email="client@example.com")
# Project due day after tomorrow
day_after = timezone.localdate() + timezone.timedelta(days=2)
Project.objects.create(
name="Future Project",
client=client,
deadline=day_after
)
Project.objects.create(name="Future Project", client=client, deadline=day_after)
check_and_send_notifications()
self.assertEqual(len(mail.outbox), 0)
self.assertEqual(Notification.objects.count(), 0)