aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/dispatch/admin.py3
-rw-r--r--app/dispatch/migrations/0001_initial.py2
-rw-r--r--app/dispatch/migrations/0002_auto_20171107_1912.py (renamed from app/dispatch/migrations/0002_auto_20171102_1949.py)4
-rw-r--r--app/dispatch/migrations/0003_invoice_payment_identifer.py20
-rw-r--r--app/dispatch/models.py8
-rw-r--r--app/dispatch/monkey_patch.py10
-rw-r--r--app/dispatch/templates/dispatch/drivers/detail.html14
-rw-r--r--app/dispatch/templates/dispatch/drivers/summary.html47
-rw-r--r--app/dispatch/templates/dispatch/generic_load_listing.html18
-rw-r--r--app/dispatch/templates/dispatch/invoice/detail-table.html22
-rw-r--r--app/dispatch/templates/dispatch/invoice/detail.html8
-rw-r--r--app/dispatch/templates/dispatch/invoice/edit.html21
-rw-r--r--app/dispatch/templates/dispatch/loads/list.html2
-rw-r--r--app/dispatch/urls.py2
-rw-r--r--app/dispatch/views.py64
-rw-r--r--app/dispatchAuth/migrations/0001_initial.py4
-rw-r--r--app/dispatchAuth/migrations/0002_auto_20171106_2233.py20
17 files changed, 205 insertions, 64 deletions
diff --git a/app/dispatch/admin.py b/app/dispatch/admin.py
index 9d1e0b3..702f0e4 100644
--- a/app/dispatch/admin.py
+++ b/app/dispatch/admin.py
@@ -1,7 +1,7 @@
from django.contrib import admin
# Register your models here.
-from .models import Load, Customer, Identity, Settings, Invoice, InvoiceItem
+from .models import Load, Paperwork, Customer, Identity, Settings, Invoice, InvoiceItem
admin.site.register(Load)
admin.site.register(Customer)
@@ -9,3 +9,4 @@ admin.site.register(Identity)
admin.site.register(Invoice)
admin.site.register(InvoiceItem)
admin.site.register(Settings)
+admin.site.register(Paperwork)
diff --git a/app/dispatch/migrations/0001_initial.py b/app/dispatch/migrations/0001_initial.py
index a358b07..d2aa2f8 100644
--- a/app/dispatch/migrations/0001_initial.py
+++ b/app/dispatch/migrations/0001_initial.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Generated by Django 1.11.5 on 2017-11-02 19:49
+# Generated by Django 1.11.5 on 2017-11-07 19:12
from __future__ import unicode_literals
import dispatch.misc
diff --git a/app/dispatch/migrations/0002_auto_20171102_1949.py b/app/dispatch/migrations/0002_auto_20171107_1912.py
index 4be45e9..059d7be 100644
--- a/app/dispatch/migrations/0002_auto_20171102_1949.py
+++ b/app/dispatch/migrations/0002_auto_20171107_1912.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Generated by Django 1.11.5 on 2017-11-02 19:49
+# Generated by Django 1.11.5 on 2017-11-07 19:12
from __future__ import unicode_literals
from django.conf import settings
@@ -12,8 +12,8 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('dispatch', '0001_initial'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
diff --git a/app/dispatch/migrations/0003_invoice_payment_identifer.py b/app/dispatch/migrations/0003_invoice_payment_identifer.py
new file mode 100644
index 0000000..21130a7
--- /dev/null
+++ b/app/dispatch/migrations/0003_invoice_payment_identifer.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.5 on 2017-11-09 20:53
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('dispatch', '0002_auto_20171107_1912'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='invoice',
+ name='payment_identifer',
+ field=models.CharField(default='', max_length=256),
+ ),
+ ]
diff --git a/app/dispatch/models.py b/app/dispatch/models.py
index fe0cdb3..ef59fe4 100644
--- a/app/dispatch/models.py
+++ b/app/dispatch/models.py
@@ -40,6 +40,13 @@ class Load(models.Model):
def get_absolute_url(self):
return "/loads/view/%i" % self.id
+ def can_invoice(self):
+ # Prevent 0 and $1 invoices as well as loads w/o attachments
+ if self.amount >= 2 and len(self.paperwork_set.all()) >= 1:
+ return True
+ else:
+ return False
+
class Paperwork(models.Model):
load = models.ForeignKey(Load, on_delete=models.CASCADE)
@@ -96,6 +103,7 @@ class Invoice(models.Model):
invoice_date = models.DateField()
due_date = models.DateField()
paid = models.BooleanField(default=False)
+ payment_identifer = models.CharField(default="", max_length=256)
def __str__(self):
return "Invoice for {} by {} for ${}".format(
diff --git a/app/dispatch/monkey_patch.py b/app/dispatch/monkey_patch.py
deleted file mode 100644
index cc61b6e..0000000
--- a/app/dispatch/monkey_patch.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from django.contrib.auth import get_user_model
-from django.core.urlresolvers import reverse
-
-# This should be going away soon with the addition
-# of my custom user model
-
-def get_absolute_url(self):
- return reverse('driver_details', kwargs={'pk': self.pk})
-
-User.add_to_class("get_absolute_url", get_absolute_url)
diff --git a/app/dispatch/templates/dispatch/drivers/detail.html b/app/dispatch/templates/dispatch/drivers/detail.html
index 99d9611..e8ffb99 100644
--- a/app/dispatch/templates/dispatch/drivers/detail.html
+++ b/app/dispatch/templates/dispatch/drivers/detail.html
@@ -51,7 +51,8 @@
<div class="col s6">
<div class="right-align">
{% if request.user.is_superuser %}
- <a class="btn orange" href="{% url 'identity_default' object.pk ident.pk %}">Make Default Bill To</a>
+ <a class="btn orange" href="{% url 'identity_default' object.pk ident.pk %}">Make Default Bill To</a>
+ {% else %}
{% endif %}
<a class="btn green" href="{% url 'identity_edit' object.pk ident.pk %}">
Edit
@@ -60,6 +61,17 @@
</div>
</div>
+{% if request.user.is_superuser %}
+<div class="row">
+ <div class="col s12">
+ <p class="">
+ "Default Bill To" is the Identity object to which all of the Invoices generated
+ by the system will have their Bill-To set. Be careful when changing this.
+ </p>
+ </div>
+</div>
+{% endif %}
+
<div class="row">
<div class="col s12">
<table>
diff --git a/app/dispatch/templates/dispatch/drivers/summary.html b/app/dispatch/templates/dispatch/drivers/summary.html
index 5da7d3c..362c1fa 100644
--- a/app/dispatch/templates/dispatch/drivers/summary.html
+++ b/app/dispatch/templates/dispatch/drivers/summary.html
@@ -15,10 +15,15 @@
<div class="row">
<div class="col s12">
<div class="right-align">
+ {% if can_invoice %}
<a class="btn orange" href="{% url 'invoice_generate' object.pk%}?date={{week_dates.start_date|date:"m/d/Y"}}">Generate Invoice For Listing</a>
+ {% else %}
+ <a class="btn orange disabled">Generate Invoice For Listing</a>
+ {% endif %}
</div>
</div>
</div>
+{% else %}
{% endif %}
{% if not request.user.is_superuser %}
@@ -30,6 +35,7 @@
<td>Date</td>
<td>Description</td>
<td>Total</td>
+ <td>Attachments</td>
<td></td>
</tr>
</thead>
@@ -38,7 +44,17 @@
<tr>
<td>{{load.date}}</td>
<td>{{load.description}}</td>
- <td>{{load.amount}}</td>
+ {% if load.amount == 0 %}
+ <td><b><span class="red-text">{{load.amount}}</span></b></td>
+ {% else %}
+ <td>{{load.amount}}</td>
+ {% endif %}
+ {% if load.paperwork_set.all %}
+ <td>{{load.paperwork_set.all|length}}</td>
+ {% else %}
+ <td><b><span class="red-text">0</span></b></td>
+ {% endif %}
+ <td></td>
<td class="right-align">
<a href="{% url 'load_detail' load.id %}" class="btn green">
View
@@ -52,6 +68,7 @@
</div>
{% endif %}
+
<div class="row">
<div class="col s12">
<table>
@@ -71,6 +88,18 @@
</div>
</div>
+{% if not can_invoice %}
+<div class="row">
+ <div class="col s12">
+ <h5>Note:</h5>
+ <p class="flow-text">
+ Cannot generate an invoice at this time, one or more Loads has an improper
+ Amount or is missing attachments.
+ </p>
+ </div>
+</div>
+{% endif %}
+
@@ -84,23 +113,9 @@
</div>
</div>
-{% if stats.incomplete_loads > 0 %}
-<div class="row">
- <div class="col s12 m8 offset-m2">
- <div class="card red z-depth-3">
- <div class="card-content black-text">
- <span class="card-title">
- Note: One or more loads has a 0 amount that needs attention
- </span>
- </div>
- </div>
- </div>
-</div>
-{% endif %}
-
{% if request.user.is_superuser %}
{% load custom_tags %}
- {% listForCommaString "Customer,Amount,Description" as load_headers %}
+ {% listForCommaString "Customer,Amount,Description,Attachments" as load_headers %}
{% include "dispatch/generic_load_listing.html" %}
{% endif %}
diff --git a/app/dispatch/templates/dispatch/generic_load_listing.html b/app/dispatch/templates/dispatch/generic_load_listing.html
index 5512184..3a78335 100644
--- a/app/dispatch/templates/dispatch/generic_load_listing.html
+++ b/app/dispatch/templates/dispatch/generic_load_listing.html
@@ -28,7 +28,13 @@
</thead>
<tbody>
{% for load in loads|keyvalue:date %}
- <tr class="green lighten-4">
+ {% if load.amount <= 2 %}
+ <tr class="red lighten-4">
+ {% elif load.paperwork_set.all|length <= 0 %}
+ <tr class="orange lighten-4">
+ {% else %}
+ <tr class="green lighten-4">
+ {% endif %}
{% if "Customer" in load_headers %}
{% if request.user.is_superuser %}
<td><a href="{% url 'customer_detail' load.customer.id %}">{{ load.customer.name }}</a></td>
@@ -42,7 +48,7 @@
{% if "Amount" in load_headers %}
{% if load.amount == 0 %}
- <td><span class="red-text">{{ load.amount }}</span></td>
+ <td><b><span class="red-text">{{ load.amount }}</span></b></td>
{% else %}
<td>{{ load.amount }}</td>
{% endif %}
@@ -52,6 +58,14 @@
<td>{{ load.description }}</td>
{% endif %}
+ {% if "Attachments" in load_headers %}
+ {% if load.paperwork_set.all %}
+ <td>{{load.paperwork_set.all|length}}</td>
+ {% else %}
+ <td><b><span class="red-text">0</span></b></td>
+ {% endif %}
+ {% endif %}
+
<td class="right-align">
<!-- <a href="{% url 'load_edit' load.id %}" class="btn orange">Edit</a> -->
<a href="{% url 'load_detail' load.id %}" class="btn blue">View</a>
diff --git a/app/dispatch/templates/dispatch/invoice/detail-table.html b/app/dispatch/templates/dispatch/invoice/detail-table.html
index 37fa2a5..508ab31 100644
--- a/app/dispatch/templates/dispatch/invoice/detail-table.html
+++ b/app/dispatch/templates/dispatch/invoice/detail-table.html
@@ -4,6 +4,9 @@
Invoice #{{object.invoice_id}}
</h4>
</div>
+ <div class="col s6 right-align">
+ <h4>PAID</h4>
+ </div>
</div>
<div class="row">
<div class="col s6">
@@ -67,9 +70,28 @@
<td>{{object.total}}</td>
</tr>
<tr>
+ <td><b>Amount Paid:</b></td>
+
+ {% if object.paid %}
+ <td>{{object.payment_identifier}}</td>
+ {% else %}
+ <td></td>
+ {% endif %}
+
+ {% if object.paid %}
+ <td>({{object.total}})</td>
+ {% else %}
+ <td>0</td>
+ {% endif %}
+ </tr>
+ <tr>
<td><b>Amount Due:</b></td>
<td></td>
+ {% if object.paid %}
+ <td><b>0</b></td>
+ {% else %}
<td><b>{{object.total}}</b></td>
+ {% endif %}
</tr>
</tbody>
</table>
diff --git a/app/dispatch/templates/dispatch/invoice/detail.html b/app/dispatch/templates/dispatch/invoice/detail.html
index 033747c..850c427 100644
--- a/app/dispatch/templates/dispatch/invoice/detail.html
+++ b/app/dispatch/templates/dispatch/invoice/detail.html
@@ -13,7 +13,8 @@
<!-- <input type="submit" class="btn red" value="Delete" /> -->
{% csrf_token %}
<a class="btn red" href="#" onClick="warn_submit('Are you sure?', '#invoice_delete')">Delete</a>
- <a class="btn green" href="#" onClick="window.print()">Print</a>
+ <a class="btn orange darken-3" href="{% url 'invoice_edit' object.pk %}">Edit</a>
+ <a class="btn green" href="#" onClick="window.print()">Print</a>
</form>
</div>
</div>
@@ -21,6 +22,8 @@
<div style="padding-top:30px;" class="hide-print"></div>
+<div style="padding-top:30px;" class="hide-print"></div>
+
<div class="z-depth-3 padding-30">
{% include "dispatch/invoice/detail-table.html" %}
</div>
@@ -33,7 +36,8 @@
<!-- <input type="submit" class="btn red" value="Delete" /> -->
{% csrf_token %}
<a class="btn red" href="#" onClick="warn_submit('Are you sure?', '#invoice_delete')">Delete</a>
- <a class="btn green" href="#" onClick="window.print()">Print</a>
+ <a class="btn orange darken-3" href="{% url 'invoice_edit' object.pk %}">Edit</a>
+ <a class="btn green" href="#" onClick="window.print()">Print</a>
</form>
</div>
</div>
diff --git a/app/dispatch/templates/dispatch/invoice/edit.html b/app/dispatch/templates/dispatch/invoice/edit.html
new file mode 100644
index 0000000..c056ed9
--- /dev/null
+++ b/app/dispatch/templates/dispatch/invoice/edit.html
@@ -0,0 +1,21 @@
+{% extends 'dispatch/base.html' %}
+
+{% block title %}Edit - {{ object.description }}{% endblock %}
+
+{% block content %}
+<div class="row">
+ <div class="col s12 m6">
+ <h1>{{object.name}}</h1>
+ </div>
+</div>
+
+<form action="" method="post">{% csrf_token %}
+ {% for field in form %}
+ <p>
+ {{field.label_tag}} {{field}}
+ </p>
+ {% endfor %}
+ <input type="submit" class="btn blue" value="Update" />
+</form>
+
+{% endblock %}
diff --git a/app/dispatch/templates/dispatch/loads/list.html b/app/dispatch/templates/dispatch/loads/list.html
index 01dd47d..615c4e1 100644
--- a/app/dispatch/templates/dispatch/loads/list.html
+++ b/app/dispatch/templates/dispatch/loads/list.html
@@ -24,7 +24,7 @@
</div>
{% load custom_tags %}
-{% listForCommaString "Customer,Driver,Amount,Description" as load_headers %}
+{% listForCommaString "Customer,Driver,Amount,Description,Attachments" as load_headers %}
{% include "dispatch/generic_load_listing.html" %}
<div class="row">
diff --git a/app/dispatch/urls.py b/app/dispatch/urls.py
index 270c674..14f78f8 100644
--- a/app/dispatch/urls.py
+++ b/app/dispatch/urls.py
@@ -42,7 +42,7 @@ urlpatterns = [
url(r'^invoices/$', views.InvoiceList.as_view(), name='invoice_list'),
url(r'^invoices/view/(?P<pk>\d+)$', views.InvoiceDetail.as_view(), name='invoice_detail'),
- # url(r'^invoices/edit/(?P<pk>\d+)$', views.InvoiceEdit.as_view(), name='invoice_edit'),
+ url(r'^invoices/edit/(?P<pk>\d+)$', views.InvoiceEdit.as_view(), name='invoice_edit'),
url(r'^invoices/delete/(?P<pk>\d+)$', views.InvoiceDelete.as_view(), name='invoice_delete'),
url(r'^drivers/view/(?P<pk>\d+)/generate/$', views.InvoiceGenerateForDates, name='invoice_generate'),
diff --git a/app/dispatch/views.py b/app/dispatch/views.py
index c80607e..b729922 100644
--- a/app/dispatch/views.py
+++ b/app/dispatch/views.py
@@ -13,7 +13,7 @@ from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from dispatch.models import Customer, Load, Paperwork, \
- Invoice, UserInvoiceNumber, Identity
+ Invoice, UserInvoiceNumber, Identity, Settings
from dispatch.forms import AddPaperworkForm
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import UserPassesTestMixin
@@ -112,6 +112,23 @@ class DriverDetail(UserPassesTestMixin, DetailView):
uinv.save()
context['invoice_number'] = uinv
+ # A stupid hack to set a default Bill to Identity on first super user
+ # login
+ try:
+ context['default_bill_to'] = Identity.objects.get(pk=\
+ Settings.objects.get(key='default_bill_to').value)
+ except:
+ if self.request.user.is_superuser:
+ try:
+ print("No default Identity Set")
+ bill_to = self.request.user.identity
+ default = Settings(key='default_bill_to', value=bill_to.pk)
+ default.save()
+ except Exception as e:
+ print(e)
+ print("No identity, you should be redirected")
+ context['default_bill_to'] = None
+
return context
@@ -130,7 +147,7 @@ class DriverSummary(UserPassesTestMixin, LoadDateSort):
stats = {}
stats['count'], stats['average'], stats['sum'] = (0, 0, 0)
- stats['incomplete_loads'] = 0
+ context['can_invoice'] = True
loads_by_date = context['loads']
for d in loads_by_date:
@@ -138,8 +155,12 @@ class DriverSummary(UserPassesTestMixin, LoadDateSort):
for l in loads_by_date[d]:
stats['count'] += 1
stats['sum'] += l.amount
- if l.amount == 0:
- stats['incomplete_loads'] += 1
+
+ # Any load not up to par will break the chain
+ print(l)
+ print(l.can_invoice())
+ if not l.can_invoice():
+ context['can_invoice'] = False
if stats['sum'] is not 0 and stats['count'] is not 0:
stats['average'] = stats['sum']/stats['count']
@@ -295,7 +316,7 @@ class LoadDetail(DetailView):
return context
-class LoadUpdate(FilteredUpdateView):
+class LoadUpdate(UserPassesTestMixin, FilteredUpdateView):
template_name = "dispatch/loads/edit.html"
model = Load
fields = []
@@ -325,6 +346,10 @@ class LoadUpdate(FilteredUpdateView):
load.user = self.request.user
return super(LoadUpdate, self).form_valid(form)
+ def test_func(self):
+ return self.request.user.is_superuser or \
+ self.get_object().user.pk == self.request.user.pk
+
class LoadDelete(UserPassesTestMixin, FilteredDeleteView):
template_name = "dispatch/loads/delete.html"
@@ -502,6 +527,35 @@ class IdentityUpdate(UserPassesTestMixin, UpdateView):
# Invoice
+class InvoiceEdit(UserPassesTestMixin, FilteredUpdateView):
+ template_name = "dispatch/invoice/edit.html"
+ model = Invoice
+ fields = []
+
+ default_fields = []
+ superuser_fields = ['user', 'owner', 'bill_to', 'invoice_id',
+ 'invoice_date', 'due_date', 'paid',
+ 'payment_identifer']
+
+ def set_fields(self, user):
+ if user.is_superuser:
+ self.fields = self.superuser_fields
+ else:
+ self.fields = self.default_fields
+
+ def post(self, request, pk):
+ self.set_fields(request.user)
+ return super(InvoiceEdit, self).post(request)
+
+ def get(self, request, pk):
+ self.set_fields(request.user)
+ return super(InvoiceEdit, self).get(request)
+
+ def test_func(self):
+ return self.request.user.is_superuser # or \
+ # self.get_object().user.pk == self.request.user.pk
+
+
class InvoiceList(FilteredListView):
template_name = "dispatch/invoice/list.html"
model = Invoice
diff --git a/app/dispatchAuth/migrations/0001_initial.py b/app/dispatchAuth/migrations/0001_initial.py
index 4a0f37c..f91594a 100644
--- a/app/dispatchAuth/migrations/0001_initial.py
+++ b/app/dispatchAuth/migrations/0001_initial.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Generated by Django 1.11.5 on 2017-11-02 19:51
+# Generated by Django 1.11.5 on 2017-11-07 19:12
from __future__ import unicode_literals
from django.db import migrations, models
@@ -17,9 +17,9 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='User',
fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
+ ('id', models.AutoField(primary_key=True, serialize=False)),
('email', models.EmailField(max_length=256, unique=True)),
('first_name', models.CharField(max_length=256)),
('last_name', models.CharField(max_length=256)),
diff --git a/app/dispatchAuth/migrations/0002_auto_20171106_2233.py b/app/dispatchAuth/migrations/0002_auto_20171106_2233.py
deleted file mode 100644
index fa2f934..0000000
--- a/app/dispatchAuth/migrations/0002_auto_20171106_2233.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.11.5 on 2017-11-06 22:33
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('dispatchAuth', '0001_initial'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='user',
- name='id',
- field=models.AutoField(primary_key=True, serialize=False),
- ),
- ]