You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
3.7 KiB
Python

from datetime import timedelta
from io import StringIO
from django.conf import settings
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
from django.core.mail import EmailMessage
from django.db.models import Count
from django.utils import timezone
def get_prev_month(d):
if d.month == 1:
year = d.year - 1
month = 12
else:
year = d.year
month = d.month - 1
return d.replace(month=month, year=year)
def should_bill(report, user, time_limit):
""" Determines if one user has actually paid for the current month """
# Here for consistency, should be filtered in the query
if not user.vpnuser.expiration or user.vpnuser.expiration < time_limit:
return False
# Replay payments
payments = list(user.payment_set.order_by('id').filter(status='confirmed'))
paid_expiration = None
for p in payments:
d = p.confirmed_on or p.created
paid_expiration = max(paid_expiration or d, d) + p.time
# Numbre of days paid after the start of the month
# If negative and not filtered with vpnuser.expiration, user was given time.
# If positive, user has paid for this time.
delta = paid_expiration - time_limit
if delta < timedelta():
report.write("- %s (#%d): %s\n" % (user.username, user.id, -delta))
return delta > timedelta()
class Command(BaseCommand):
help = "Generate and send a monthly usage report to ADMINS"
def handle(self, *args, **options):
addresses = settings.USAGE_REPORT_DESTINATION
def format_e(n):
return '%.2f%s' % (n / 100, settings.PAYMENTS_CURRENCY[1])
# Dates
end = timezone.now().replace(microsecond=0, second=0, minute=0, hour=0, day=5)
start = get_prev_month(end)
# Filter users
filtering_report = StringIO()
all_users = User.objects.order_by('id')
active_users = all_users.filter(vpnuser__expiration__gt=start)
paying_users = active_users.filter(payment__status='confirmed').annotate(Count('payment')).filter(payment__count__gt=0)
users = [u for u in paying_users if should_bill(filtering_report, u, start)]
# Generate report
report = "CCVPN Usage Report\n"
report += "==================\n\n"
report += "From: %s\nTo : %s\n\n" % (start, end)
keys = ('Users', 'Active', 'W/Payment', 'Selected')
values = (all_users.count(), active_users.count(), paying_users.count(), len(users))
report += " | ".join("%-10s" % s for s in keys) + "\n"
report += " | ".join("%-10s" % s for s in values) + "\n"
report += "\n"
user_cost = settings.VPN_USER_COST
total_cost = settings.VPN_USER_COST * len(users)
report += "Billed: %d * %s = %s\n" % (len(users), format_e(user_cost), format_e(total_cost))
report += "\n"
if filtering_report.getvalue():
report += "Ignored users:\n"
report += filtering_report.getvalue()
report += "\n"
users_text = "\n".join("%s (#%d)" % (u.username, u.id) for u in users)
subject = "[CCVPN] Usage Report: %s to %s" % (
start.strftime('%m/%Y'), end.strftime('%m/%Y'))
# Send
print(report)
print("-------")
print("Send to: " + ", ".join(a for a in addresses))
print("Confirm? [y/n] ", end='')
i = input()
if i.lower().strip() != 'y':
return
for dest in addresses:
mail = EmailMessage(subject=subject, body=report,
from_email=settings.DEFAULT_FROM_EMAIL, to=[dest])
mail.attach('users.txt', users_text, 'text/plain')
mail.send()
print("Sent.")