146 lines
5.3 KiB
Python
146 lines
5.3 KiB
Python
import logging
|
|
from datetime import timedelta
|
|
from django.urls import reverse
|
|
from django.conf import settings
|
|
from django.utils import timezone
|
|
from inventory.tasks import send_email
|
|
from django.core.management.base import BaseCommand
|
|
from django.template.loader import render_to_string
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django_ledger.models import InvoiceModel, EstimateModel
|
|
from inventory.models import ExtraInfo, Notification, CustomGroup
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = "Handles invoices due date reminders"
|
|
|
|
def handle(self, *args, **options):
|
|
self.stdout.write("Starting invoices due date reminders..")
|
|
|
|
# 1. Send expiration reminders
|
|
self.invocie_expiration_reminders()
|
|
# self.invoice_past_due()
|
|
|
|
# # 2. Deactivate expired plans
|
|
# self.deactivate_expired_plans()
|
|
|
|
# # 3. Clean up old incomplete orders
|
|
# self.cleanup_old_orders()
|
|
|
|
# self.stdout.write("Reminders completed!")
|
|
|
|
def invocie_expiration_reminders(self):
|
|
"""Queue email reminders for expiring plans"""
|
|
reminder_days = getattr(settings, "INVOICE_PAST_DUE_REMIND", [3, 7, 14])
|
|
today = timezone.now().date()
|
|
|
|
for days in reminder_days:
|
|
target_date = today + timedelta(days=days)
|
|
expiring_plans = InvoiceModel.objects.filter(
|
|
date_due=target_date
|
|
).select_related("customer", "ce_model")
|
|
|
|
for inv in expiring_plans:
|
|
# dealer = inv.customer.customer_set.first().dealer
|
|
subject = f"Your invoice is due in {days} days"
|
|
message = render_to_string(
|
|
"emails/invoice_past_due_reminder.txt",
|
|
{
|
|
"customer_name": inv.customer.customer_name,
|
|
"invoice_number": inv.invoice_number,
|
|
"amount_due": inv.amount_due,
|
|
"days_past_due": inv.due_in_days(),
|
|
"SITE_NAME": settings.SITE_NAME,
|
|
},
|
|
)
|
|
send_email(
|
|
"noreply@yourdomain.com",
|
|
inv.customer.email,
|
|
subject,
|
|
message,
|
|
)
|
|
|
|
self.stdout.write(f"Queuing {expiring_plans} reminders for {target_date}")
|
|
|
|
def invoice_past_due(self):
|
|
"""Queue email reminders for expiring plans"""
|
|
today = timezone.now().date()
|
|
expiring_plans = InvoiceModel.objects.filter(
|
|
date_due__lte=today
|
|
).select_related("customer", "ce_model")
|
|
|
|
# Send email
|
|
for inv in expiring_plans:
|
|
dealer = inv.customer.customer_set.first().dealer
|
|
|
|
subject = f"Your invoice is past due"
|
|
message = render_to_string(
|
|
"emails/invoice_past_due.txt",
|
|
{
|
|
"customer_name": inv.customer.customer_name,
|
|
"invoice_number": inv.invoice_number,
|
|
"amount_due": inv.amount_due,
|
|
"days_past_due": (today - inv.date_due).days,
|
|
"SITE_NAME": settings.SITE_NAME,
|
|
},
|
|
)
|
|
|
|
# send notification to accountatnt
|
|
recipients = (
|
|
CustomGroup.objects.filter(dealer=dealer, name="Accountant")
|
|
.first()
|
|
.group.user_set.exclude(email=dealer.user.email)
|
|
.distinct()
|
|
)
|
|
for rec in recipients:
|
|
Notification.objects.create(
|
|
user=rec,
|
|
message=_(
|
|
"""
|
|
Invoice {invoice_number} is past due,please your
|
|
<a href="{url}" target="_blank">View</a>.
|
|
"""
|
|
).format(
|
|
invoice_number=inv.invoice_number,
|
|
url=reverse(
|
|
"invoice_detail",
|
|
kwargs={
|
|
"dealer_slug": dealer.slug,
|
|
"entity_slug": dealer.entity.slug,
|
|
"pk": inv.pk,
|
|
},
|
|
),
|
|
),
|
|
)
|
|
|
|
# send email to customer
|
|
send_email(
|
|
"noreply@yourdomain.com",
|
|
inv.customer.email,
|
|
subject,
|
|
message,
|
|
)
|
|
|
|
self.stdout.write(f"Queuing {expiring_plans} reminders for {today}")
|
|
|
|
# def deactivate_expired_plans(self):
|
|
# """Deactivate plans that have expired (synchronous)"""
|
|
# expired_plans = UserPlan.objects.filter(
|
|
# active=True,
|
|
# expire__lt=timezone.now().date()
|
|
# )
|
|
# count = expired_plans.update(active=False)
|
|
# self.stdout.write(f"Deactivated {count} expired plans")
|
|
|
|
# def cleanup_old_orders(self):
|
|
# """Delete incomplete orders older than 30 days"""
|
|
# cutoff = timezone.now() - timedelta(days=30)
|
|
# count, _ = Order.objects.filter(
|
|
# created__lt=cutoff,
|
|
# status=Order.STATUS.NEW
|
|
# ).delete()
|
|
# self.stdout.write(f"Cleaned up {count} old incomplete orders")
|