diff --git a/src/accounts/forms.py b/src/accounts/forms.py index d457507..01f9d83 100644 --- a/src/accounts/forms.py +++ b/src/accounts/forms.py @@ -79,9 +79,13 @@ class Meta: "work_phone", "birth_date", "join_date", + "active", + "end_date", + "end_reason", "notes", ] widgets = { "birth_date": DateInput(format=("%Y-%m-%d")), "join_date": DateInput(format=("%Y-%m-%d")), + "end_date": DateInput(format=("%Y-%m-%d")), } diff --git a/src/models/management/commands/seed.py b/src/models/management/commands/seed.py new file mode 100644 index 0000000..d5f38d4 --- /dev/null +++ b/src/models/management/commands/seed.py @@ -0,0 +1,120 @@ +from django.core.management.base import BaseCommand +import random +from address.models import Address, Locality, State, Country + +from logging import getLogger + +from models.models import ( + Customer, + CustomerRecord, + Payment +) + + +log = getLogger(__name__) + +# python manage.py seed --mode=refresh + +""" Clear all data and creates cusotmers """ +MODE_REFRESH = 'refresh' + +""" Clear all data and do not create any object """ +MODE_CLEAR = 'clear' + +class Command(BaseCommand): + help = "seed database for testing and development." + + def add_arguments(self, parser): + parser.add_argument('--mode', type=str, help="Mode") + + def handle(self, *args, **options): + self.stdout.write('seeding data...') + run_seed(self, options['mode']) + self.stdout.write('done.') + + +def clear_data(): + """Deletes all the table data""" + log.info("Deleting customers") + Customer.objects.all().delete() + CustomerRecord.objects.all().delete() + + +def create_customer(local, payment_types): + """Creates an customer object combining different elements from the list""" + log.info("Creating customer") + + active_options = [True, False] + first_name_options = ["Bob", "Jane", "Joe", "Hank", "Jill", "Tom", "Alice"] + last_name_options = ["Smith", "Adams", "Thompson", "Berry", "Phillips"] + + + a = Address( + street_number="1", + route="Some Street", + locality=local, + raw="1 Some Street, Charlottesvile, VA" + ) + a.save() + + c = Customer( + active=random.choice(active_options), + first_name=random.choice(first_name_options), + last_name=random.choice(last_name_options), + address=a + ) + c.save() + + + cr = CustomerRecord( + customer=c, + num_meals=1, + payment_type=random.choice(payment_types) + ) + cr.save() + + log.info("{} customer created.".format(c)) + return c + +def run_seed(self, mode): + """ Seed database based on mode + + :param mode: refresh / clear + :return: + """ + # Clear data from tables + clear_data() + if mode == MODE_CLEAR: + return + + payment_types = [] + + try: + country = Country(name="US") + country.save() + state = State(name="VA", country=country) + state.save() + local = Locality(name="Charlottesville", postal_code="22911", state=state) + local.save() + except: + local = Locality.objects.first() + + try: + p1 = Payment(name="debit") + p1.save() + p2 = Payment(name="credit") + p2.save() + p3 = Payment(name="cash") + p3.save() + + payment_types = [p1,p2,p3] + except: + payment_types = Payment.objects.all() + + + # Creating 30 customers + for i in range(30): + try: + create_customer(local,payment_types) + except: + pass \ No newline at end of file diff --git a/src/models/migrations/0034_volunteer_end_date_volunteer_end_reason.py b/src/models/migrations/0034_volunteer_end_date_volunteer_end_reason.py new file mode 100644 index 0000000..7a6e485 --- /dev/null +++ b/src/models/migrations/0034_volunteer_end_date_volunteer_end_reason.py @@ -0,0 +1,35 @@ +# Generated by Django 4.0.4 on 2024-08-11 00:44 + +from django.db import migrations, models + + +def set_default_values(apps, schema_editor): + Volunteer = apps.get_model('models', 'volunteer') + db_alias = schema_editor.connection.alias + + Volunteer.objects.update(active=True) + +class Migration(migrations.Migration): + + dependencies = [ + ('models', '0033_alter_route_bonusroute'), + ] + + operations = [ + migrations.AddField( + model_name='volunteer', + name='end_date', + field=models.DateField(blank=True, null=True), + ), + migrations.AddField( + model_name='volunteer', + name='end_reason', + field=models.TextField(blank=True, default=''), + ), + migrations.AddField( + model_name='volunteer', + name='active', + field=models.BooleanField(default=True), + ), + migrations.RunPython(set_default_values), + ] diff --git a/src/models/models.py b/src/models/models.py index f4519e5..8d60d7c 100644 --- a/src/models/models.py +++ b/src/models/models.py @@ -93,6 +93,9 @@ class Volunteer(models.Model): birth_date = models.DateField(null=True, blank=True) notes = models.TextField(default="", blank=True) join_date = models.DateField(default=date.today) + end_date=models.DateField(null=True, blank=True) + end_reason = models.TextField(default="", blank=True) + active = models.BooleanField(default=True) number_of_people = models.IntegerField(default=1) dont_email = models.BooleanField(default=False) diff --git a/src/pdfs/templates/pdfs/job-overview.html b/src/pdfs/templates/pdfs/job-overview.html index d11906c..9829ac6 100644 --- a/src/pdfs/templates/pdfs/job-overview.html +++ b/src/pdfs/templates/pdfs/job-overview.html @@ -2,20 +2,22 @@
| Job Name | Volunteers | +Clients | +Meals | {% for j in jt.jobs %}|
|---|---|---|---|---|
| {{j.job.name}} | +{{j.job.job.name}} |
- {% for person in j.todays_volunteers %}
+ {% for person in j.job.todays_volunteers %}
{% if person.sub_pk %}
{% if person.name == open_substitution %}
{{open_substitution}}{% if not forloop.last %},{% endif %}
@@ -30,6 +32,8 @@ {{jt.job_type.name}} ({{d.date|date:'l, M. d, Y'} {{unassigned_job}} {% endfor%} |
+ {{j.number_of_customers}} | +{{j.total_meals}} | Nothing to display. | diff --git a/src/pdfs/templates/pdfs/monthly-billing.html b/src/pdfs/templates/pdfs/monthly-billing.html index fc73759..167098d 100644 --- a/src/pdfs/templates/pdfs/monthly-billing.html +++ b/src/pdfs/templates/pdfs/monthly-billing.html @@ -56,9 +56,9 @@ | Route | - {% for reportday in reportday_section %} + {% for reportday in reportday_section|sort_name:"customer__last_name,customer__first_name" %}
| {{ reportday.customer|getCustomer }} | +{{ reportday.customer__first_name }} {{ reportday.customer__last_name }} | {{ reportday.total_meals }} | {{ reportday.payment_type|getPayment }} | {{ reportday.route_assigned|getRoute }} | diff --git a/src/pdfs/templatetags/route_extras.py b/src/pdfs/templatetags/route_extras.py index 0da4a60..3c4dfc3 100644 --- a/src/pdfs/templatetags/route_extras.py +++ b/src/pdfs/templatetags/route_extras.py @@ -89,3 +89,8 @@ def numMealsOnDay(cust, date): register.filter("getItem", getItem) register.filter("numMealsOnDay", numMealsOnDay) register.filter("getRange", getRange) + +@register.filter +def sort_name(val, args): + x, y = args.split(',') + return sorted(val, key=lambda item: (item[x].lower(), item[y].lower())) diff --git a/src/pdfs/views.py b/src/pdfs/views.py index 285e8a0..b3165a6 100644 --- a/src/pdfs/views.py +++ b/src/pdfs/views.py @@ -39,19 +39,21 @@ "Delivery Status", "Client Status", "Notes", "Volunteer"] -def to_pdf(html, styleSheetPath=None): +def to_pdf(html, styleSheetPath=None, options=None): global _display if not _display: _display = Display(visible=0, size=(320, 240)).start() - options = { - "page-size": "Letter", - "margin-top": "0.74in", - "margin-right": "0.39in", - "margin-bottom": "0.39in", - "margin-left": "0.39in", - "print-media-type": True, - "user-style-sheet": styleSheetPath - } + if not options: + options = { + "page-size": "Letter", + "margin-top": "0.74in", + "margin-right": "0.39in", + "margin-bottom": "0.39in", + "margin-left": "0.39in", + "footer-right": "[page] of [topage]", + "print-media-type": True, + "user-style-sheet": styleSheetPath + } pdf = pdfkit.from_string(html, False, options) @@ -212,13 +214,33 @@ def job_overview_report(request, begin_date, end_date): begin_date_datetime = datetime.datetime.strptime(begin_date, "%m-%d-%Y") end_date_datetime = datetime.datetime.strptime(end_date, "%m-%d-%Y") dates = actuals_to_display( - begin_date_datetime, end_date_datetime + datetime.timedelta(days=1) + begin_date_datetime, end_date_datetime + datetime.timedelta(days=1), + skip_unfilled_end=True ) + + context = [] + for d in dates: + job_types = [] + for jt in d.job_types: + details = {"job_type_name": jt.job_type.name} + jobs = [] + for job in jt.jobs: + total_num_meals = 0 + customers = Customer.objects.filter(route=job.route_number) + for c in customers: + num_meals = c.num_meals_on_day(d.date) + total_num_meals += num_meals + jobs.append({"job": job, "number_of_customers": len(customers), "total_meals": total_num_meals}) + details["jobs"] = jobs + + job_types.append(details) + context.append({"date": d.date, "job_types": job_types}) + template = get_template("pdfs/job-overview.html") return to_pdf( template.render( { - "dates": dates, + "context": context, "open_substitution": OPEN_SUBSTITUTION, "unassigned_job": UNASSIGNED_JOB, } @@ -336,8 +358,10 @@ def monthly_billing_report(request, begin_date, end_date): CustomerRecord.objects.filter( num_meals__gte=1, date__gte=begin_date, - date__lte=end_date) .values( - "customer", + date__lte=end_date).select_related('customer').values( + "customer__id", + "customer__first_name", + "customer__last_name", "payment_type", "route_assigned") .annotate( total_meals=Sum("num_meals")) .order_by("payment_type")) @@ -576,6 +600,10 @@ def generate_routes_report(request, date): for c in custs: total_meals += c.num_meals_on_day(date) + + if total_meals < 1: + continue + # Append to data data.append({"route": route, "customer_list": custs, "total_meals": total_meals, "date": date, "vols": vols}) @@ -583,4 +611,12 @@ def generate_routes_report(request, date): template = get_template("pdfs/generate-routes-report.html") context = {"data": data} - return to_pdf(template.render(context), '/collected-static/pdfs/route_all_pdf.css') + return to_pdf(template.render(context), options = { + "page-size": "Letter", + "margin-top": "0.74in", + "margin-right": "0.39in", + "margin-bottom": "0.39in", + "margin-left": "0.39in", + "footer-right": "[page] of [topage]", + "user-style-sheet": '/collected-static/pdfs/route_all_pdf.css' + }) diff --git a/src/requirements.txt b/src/requirements.txt index 620e02f..0f2836e 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -32,7 +32,6 @@ graphviz==0.20 gunicorn==20.1.0 idna==3.3 inflection==0.5.1 -install==1.3.5 isort==5.10.1 itypes==1.2.0 Jinja2==3.1.1 diff --git a/src/staff/templates/edit-volunteer.html b/src/staff/templates/edit-volunteer.html index 860f5c4..e05f54c 100644 --- a/src/staff/templates/edit-volunteer.html +++ b/src/staff/templates/edit-volunteer.html @@ -92,6 +92,17 @@