Plumb most of the basic interactions
This commit is contained in:
@@ -4,7 +4,7 @@ from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
|
||||
class Committee(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
chair = models.ForeignKey(User, null=True)
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@@ -41,9 +41,13 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django_cleanup',
|
||||
'social_django',
|
||||
'storages',
|
||||
'stdimage',
|
||||
|
||||
'items',
|
||||
'committee',
|
||||
'social_django',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@@ -93,6 +97,14 @@ DATABASES = {
|
||||
}
|
||||
}
|
||||
|
||||
# S3 File Storage
|
||||
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
|
||||
AWS_ACCESS_KEY_ID=os.environ['AWS_ACCESS_KEY_ID']
|
||||
AWS_SECRET_ACCESS_KEY=os.environ['AWS_SECRET_ACCESS_KEY']
|
||||
AWS_AUTO_CREATE_BUCKET=True
|
||||
AWS_STORAGE_BUCKET_NAME='fincom'
|
||||
AWS_S3_FILE_OVERWRITE=False
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
|
||||
@@ -118,6 +130,7 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ['SOCIAL_AUTH_GOOGLE_OAUTH2_KEY']
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ['SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET']
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS = ['andrew.cmu.edu']
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {'hd': 'andrew.cmu.edu' }
|
||||
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/items/'
|
||||
|
||||
# Internationalization
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
from __future__ import unicode_literals
|
||||
from django.contrib.auth.models import User
|
||||
from storages.backends.s3boto3 import S3Boto3Storage
|
||||
from stdimage.models import StdImageField
|
||||
from datetime import datetime, date
|
||||
|
||||
from committee.models import Committee
|
||||
|
||||
from django.db import models
|
||||
|
||||
class Item(models.Model):
|
||||
S3 = S3Boto3Storage()
|
||||
|
||||
NEW = 'N'
|
||||
PREAPPROVED = 'C'
|
||||
PROCESSED = 'P'
|
||||
@@ -24,24 +29,29 @@ class Item(models.Model):
|
||||
details = models.TextField()
|
||||
cost = models.DecimalField(max_digits=7, decimal_places=2)
|
||||
date_purchased = models.DateField('date purchased')
|
||||
image = StdImageField(upload_to='images/%Y/%m/%d',
|
||||
variations={'thumbnail': (600, 600)}
|
||||
)
|
||||
|
||||
created_by = models.ForeignKey(User, related_name='created_by')
|
||||
approved_by = models.ManyToManyField(User, blank=True, related_name='approved_by')
|
||||
date_filed = models.DateTimeField('date filed')
|
||||
status = models.CharField(max_length=2, choices=STATUS)
|
||||
task_id = models.CharField(max_length=30)
|
||||
|
||||
def approved(self):
|
||||
return self.status == 'P'
|
||||
return self.status == Item.PREAPPROVED
|
||||
|
||||
def processed(self):
|
||||
return self.status == 'C'
|
||||
return self.status == Item.PROCESSED
|
||||
|
||||
def rejected(self):
|
||||
return self.status == 'R'
|
||||
return self.status == Item.REJECTED
|
||||
|
||||
def new(self):
|
||||
return self.status == 'N'
|
||||
return self.status == Item.NEW
|
||||
|
||||
def statusText(self):
|
||||
return dict(Item.STATUS)[self.status]
|
||||
|
||||
def comName(self):
|
||||
return self.committee.name
|
||||
|
||||
@@ -3,5 +3,10 @@ from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.list, name='list'),
|
||||
url(r'^(?P<item_id>\d+)/$', views.details, name='details'),
|
||||
url(r'^(?P<item_id>\d+)/approve$', views.approve, name='approve'),
|
||||
url(r'^(?P<item_id>\d+)/reject$', views.reject, name='reject'),
|
||||
url(r'^(?P<item_id>\d+)/edit$', views.edit, name='edit'),
|
||||
url(r'^(?P<item_id>\d+)/delete$', views.delete, name='delete'),
|
||||
url(r'^new$', views.new_form, name='new_form'),
|
||||
]
|
||||
|
||||
@@ -1,22 +1,158 @@
|
||||
from django.shortcuts import HttpResponse
|
||||
from django.shortcuts import HttpResponse, HttpResponseRedirect
|
||||
from django.template import loader
|
||||
from django.utils import timezone
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import Q
|
||||
from models import Item
|
||||
from committee.models import Committee
|
||||
|
||||
def isAuthorised(request, item):
|
||||
return (request.user == item.committee.chair
|
||||
or request.user.groups.filter(name='Fincom').exists())
|
||||
|
||||
# Create your views here.
|
||||
def authError():
|
||||
return HttpResponseRedirect('/items')
|
||||
|
||||
def myItems(user):
|
||||
if (user.groups.filter(name='Fincom').exists()):
|
||||
return Items.objects.order_by('-date_filed', 'desc')
|
||||
|
||||
comms = []
|
||||
for c in Committee.objects.all():
|
||||
if (c.chair == user):
|
||||
comms.append(c)
|
||||
|
||||
return Item.objects.filter(Q(created_by=user) | Q(committee__in=comms)) \
|
||||
.order_by('-date_filed', 'desc')
|
||||
|
||||
@login_required
|
||||
def list(request):
|
||||
template = loader.get_template('items/list.html')
|
||||
items = myItems(request.user)
|
||||
|
||||
context = {
|
||||
'items': Item.objects.all(),
|
||||
'preapproved': items.filter(status=Item.PREAPPROVED),
|
||||
'processed': items.filter(status=Item.PROCESSED),
|
||||
'newitems': items.filter(status=Item.NEW),
|
||||
'rejected': items.filter(status=Item.REJECTED),
|
||||
}
|
||||
|
||||
return HttpResponse(template.render(context, request))
|
||||
|
||||
@login_required
|
||||
def details(request, item_id):
|
||||
I = Item.objects.get(pk=item_id)
|
||||
if (not isAuthorised(request, I)):
|
||||
return HttpResponseRedirect('/items/' + str(item_id) + '/edit')
|
||||
|
||||
template = loader.get_template('items/details.html')
|
||||
|
||||
context = {
|
||||
'I': I,
|
||||
}
|
||||
return HttpResponse(template.render(context, request))
|
||||
|
||||
def approve(request, item_id):
|
||||
I = Item.objects.get(pk=item_id)
|
||||
|
||||
if (not isAuthorised(request, I)):
|
||||
return authError()
|
||||
|
||||
I.approved_by.add(request.user)
|
||||
if (I.committee.chair == request.user and
|
||||
I.status == Item.NEW):
|
||||
I.status = Item.PREAPPROVED
|
||||
elif (request.user.groups.filter(name='Fincom').exists()):
|
||||
I.status = Item.PROCESSED
|
||||
|
||||
I.save()
|
||||
|
||||
return HttpResponseRedirect('/items')
|
||||
|
||||
def reject(request, item_id):
|
||||
I = Item.objects.get(pk=item_id)
|
||||
|
||||
if (not isAuthorised(request, I)):
|
||||
return authError()
|
||||
|
||||
I.status = Item.REJECTED
|
||||
I.save()
|
||||
|
||||
return HttpResponseRedirect('/items')
|
||||
|
||||
def delete(request, item_id):
|
||||
I = Item.objects.get(pk=item_id)
|
||||
|
||||
if (not isAuthorised(request, I)):
|
||||
return authError()
|
||||
|
||||
I.delete()
|
||||
|
||||
return HttpResponseRedirect('/items')
|
||||
|
||||
def edit(request, item_id):
|
||||
I = Item.objects.get(pk=item_id)
|
||||
|
||||
if (not isAuthorised(request, I)
|
||||
and request.user != I.created_by):
|
||||
return authError()
|
||||
|
||||
if request.method == 'POST':
|
||||
if (request.POST.get('desc', None)):
|
||||
I.desc = request.POST['desc']
|
||||
if (request.POST.get('event', None)):
|
||||
I.event = request.POST['event']
|
||||
if (request.POST.get('committee', None)):
|
||||
I.committee = Committee.objects.get(name=request.POST['committee'])
|
||||
if (request.POST.get('cost', None)):
|
||||
I.cost = request.POST['cost']
|
||||
if (request.POST.get('date', None)):
|
||||
I.date_purchased = Item.parseDate(request.POST['date']),
|
||||
if (request.POST.get('details', None)):
|
||||
I.details = request.POST['details']
|
||||
|
||||
I.save()
|
||||
|
||||
return HttpResponseRedirect('/items/' + str(item_id))
|
||||
else:
|
||||
template = loader.get_template('items/edit.html')
|
||||
|
||||
context = {
|
||||
'I': I,
|
||||
'committees': Committee.objects.order_by('name'),
|
||||
}
|
||||
return HttpResponse(template.render(context, request))
|
||||
|
||||
def new_form(request):
|
||||
template = loader.get_template('items/new.html')
|
||||
context = {
|
||||
'committees': Committee.objects.order_by('name'),
|
||||
}
|
||||
if request.method == 'POST':
|
||||
if request.FILES['image'].size > 10 * (1 << 20):
|
||||
template = loader.get_template('items/new.html')
|
||||
context = {
|
||||
'committees': Committee.objects.order_by('name'),
|
||||
'error': 'Your image file is too large. Maximum size is 20MB',
|
||||
}
|
||||
return HttpResponse(template.render(context, request))
|
||||
item = Item(
|
||||
desc = request.POST['desc'],
|
||||
event = request.POST['event'],
|
||||
committee = Committee.objects.get(name=request.POST['committee']),
|
||||
cost = request.POST['cost'],
|
||||
date_purchased = Item.parseDate(request.POST['date']),
|
||||
details = request.POST['details'],
|
||||
date_filed = timezone.now(),
|
||||
created_by = request.user,
|
||||
status = Item.NEW,
|
||||
image = request.FILES['image'],
|
||||
)
|
||||
|
||||
return HttpResponse(template.render(context, request))
|
||||
item.save()
|
||||
|
||||
return HttpResponseRedirect('/items')
|
||||
|
||||
else:
|
||||
template = loader.get_template('items/new.html')
|
||||
context = {
|
||||
'committees': Committee.objects.order_by('name'),
|
||||
}
|
||||
|
||||
return HttpResponse(template.render(context, request))
|
||||
|
||||
28
fincom/static/sass/details.scss
Normal file
28
fincom/static/sass/details.scss
Normal file
@@ -0,0 +1,28 @@
|
||||
.approve {
|
||||
padding: $pad-xl;
|
||||
|
||||
.status {
|
||||
font-size: 16px;
|
||||
color: $midgray;
|
||||
font-weight: lighter;
|
||||
|
||||
span {
|
||||
color: $text;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
border: 1px solid $midgray;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin: $pad-m 0;
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
$purple: #563d7c;
|
||||
$gold: #fdd017;
|
||||
$lightgray: #fcfcfc;
|
||||
$lightgray: #f8f8f8;
|
||||
$midgray: #969499;
|
||||
$darkgray: #4b4a4d;
|
||||
$text: #252526;
|
||||
@@ -41,18 +41,20 @@ body {
|
||||
}
|
||||
|
||||
.container {
|
||||
height: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 64px;
|
||||
max-width: 960;
|
||||
background-color: #fff;
|
||||
border: solid 1px $midgray;
|
||||
& > div {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 64px;
|
||||
max-width: 960;
|
||||
background-color: #fff;
|
||||
border: solid 1px $midgray;
|
||||
box-shadow: 0px 3px 9px lighten($shadowgray, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.btn {
|
||||
border-radius: $pad-s;
|
||||
border: 1px solid $midgray;
|
||||
color: $purple;
|
||||
|
||||
display: inline-block;
|
||||
@@ -63,6 +65,6 @@ body {
|
||||
|
||||
|
||||
&:hover {
|
||||
background-color: darken($purple, 15%);
|
||||
background-color: lighten($purple, 35%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@import 'globals';
|
||||
@import 'details';
|
||||
@import 'items';
|
||||
@import 'login';
|
||||
@import 'new';
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
section {
|
||||
color: $midgray;
|
||||
font-weight: lighter;
|
||||
font-size: 16px;
|
||||
margin-top: 2*$pad-xl;
|
||||
margin-bottom: -2*$pad-xl + $pad-l;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: $pad-m $pad-xl;
|
||||
margin: 0px;
|
||||
@@ -12,6 +20,10 @@
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.details-row {
|
||||
margin: $pad-m 0;
|
||||
font-size: 16px;
|
||||
@@ -36,7 +48,6 @@
|
||||
}
|
||||
|
||||
.cost {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
width: 120px;
|
||||
@@ -58,22 +69,52 @@
|
||||
background-color: #d9ffd9;
|
||||
}
|
||||
|
||||
.rejected {
|
||||
background-color: $midgray;
|
||||
color: $lightgray;
|
||||
}
|
||||
|
||||
.newItem {
|
||||
background-color: #fff7d9;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.item .cost {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
margin: $pad-l;
|
||||
color: $midgray;
|
||||
font-weight: lighter;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
$button-size: 24px;
|
||||
|
||||
.btn-floating {
|
||||
position: fixed;
|
||||
bottom: $button-size;
|
||||
right: $button-size;
|
||||
padding: $button-size;
|
||||
padding: $button-size/2;
|
||||
color: $gold;
|
||||
background-color: $purple;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
|
||||
z-index: 1000;
|
||||
border-radius: 50%;
|
||||
|
||||
text-align: center;
|
||||
box-shadow: 0 0 6px rgba(0,0,0,.16),0 6px 12px rgba(0,0,0,.32);
|
||||
|
||||
span {
|
||||
display: block;
|
||||
width: 36;
|
||||
height: 36;
|
||||
font-size: 28;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,12 @@ hr {
|
||||
form {
|
||||
div {
|
||||
margin: $pad-l;
|
||||
width: 376px;
|
||||
|
||||
* {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
label {
|
||||
text-align: right;
|
||||
width: 180px;
|
||||
color: $text;
|
||||
vertical-align: top;
|
||||
@@ -29,7 +27,6 @@ form {
|
||||
|
||||
input, select, textarea {
|
||||
width: 180px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
&.clear {
|
||||
@@ -46,9 +43,32 @@ form {
|
||||
}
|
||||
|
||||
.rcol {
|
||||
float: right;
|
||||
width: 40%;
|
||||
margin: $pad-l;
|
||||
color: $midgray;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
@media (min-width: 430px) {
|
||||
form {
|
||||
div {
|
||||
width: 376px;
|
||||
|
||||
|
||||
label {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
input, select, textarea {
|
||||
width: 180px;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.rcol {
|
||||
float: right;
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
{% block main %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% block bottom %}
|
||||
{% endblock %}
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link href="{% static "css/site.css" %}" rel="stylesheet">
|
||||
</head>
|
||||
<body class="login">
|
||||
<div class="container">
|
||||
<div>
|
||||
<h3>Delta Beta Chapter</h3>
|
||||
<h2>Fincom Webapp</h2>
|
||||
{% if error %}
|
||||
|
||||
22
fincom/templates/items/details.html
Normal file
22
fincom/templates/items/details.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{% extends "../boilerplate.html" %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div>
|
||||
{% include "./item.html" %}
|
||||
|
||||
<div class="approve">
|
||||
<div class="status">Status: <span>{{ I.statusText }}</span></div>
|
||||
|
||||
<div class="actions">
|
||||
<a href="/items/{{ I.pk }}/approve" class="btn">Approve</a>
|
||||
<a href="/items/{{ I.pk }}/reject" class="btn">Reject</a>
|
||||
<a href="/items/{{ I.pk }}/delete" class="btn">Delete</a>
|
||||
<a href="/items/{{ I.pk }}/edit" class="btn">Edit</a>
|
||||
</div>
|
||||
|
||||
<a href="{{ I.image.url }}"><img src="{{ I.image.thumbnail.url }}"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
65
fincom/templates/items/edit.html
Normal file
65
fincom/templates/items/edit.html
Normal file
@@ -0,0 +1,65 @@
|
||||
{% extends "../boilerplate.html" %}
|
||||
|
||||
{% block title %}Edit Reimbursement{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div>
|
||||
<h1>Edit Reimbursements</h1>
|
||||
<hr>
|
||||
|
||||
<form action="/items/{{ I.pk }}/edit" method="post">
|
||||
{% csrf_token %}
|
||||
<div>
|
||||
<label for="desc">Item</label>
|
||||
<input id="desc" type="text" name="desc" placeholder="What you bought"
|
||||
value="{{ I.desc }}">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="event">Event</label>
|
||||
<input id="event" type="text" name="event" placeholder="When we need it"
|
||||
value="{{ I.event }}">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="committee">Committee or Budget</label>
|
||||
<select name="committee" id="committee">
|
||||
{% for C in committees %}
|
||||
{% if I.committee == C %}
|
||||
<option selected>{{ C.name }}</option>
|
||||
{% else %}
|
||||
<option>{{ C.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="cost">Cost</label>
|
||||
<input id="cost" type="text" name="cost" placeholder="15.00"
|
||||
value="{{ I.cost }}">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="date">Date Purchased</label>
|
||||
<input id="date" type="date" name="date" placeholder="mm/dd/yyyy"
|
||||
value="{{ I.date_purchased }}">
|
||||
</div>
|
||||
|
||||
<div class="clear">
|
||||
<div>
|
||||
<label for="details">Details</label>
|
||||
<textarea id="details" name="details" rows="4" class="clear">{{ I.details }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clear">
|
||||
<div>
|
||||
<input type="submit">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -6,11 +6,14 @@
|
||||
<div class="cost approved">
|
||||
{% elif I.processed %}
|
||||
<div class="cost processed">
|
||||
{% elif I.rejected %}
|
||||
<div class="cost rejected">
|
||||
{% else %}
|
||||
<div class="cost newItem">
|
||||
{% endif %}
|
||||
${{ I.cost|floatformat:"2" }}
|
||||
</div>
|
||||
<a href="/items/{{ I.pk }}">
|
||||
<div class="details-row">
|
||||
<b>{{ I.event }}:</b>
|
||||
{{ I.desc }}
|
||||
@@ -19,12 +22,15 @@
|
||||
<em>on</em> {{ I.date_purchased }}
|
||||
<em>(filed {{ I.date_filed }})</em>
|
||||
</div>
|
||||
</a>
|
||||
<div class="status">
|
||||
{% if I.approved or I.processed %}
|
||||
Approved By:
|
||||
{% for u in I.approved_by.all %}
|
||||
{{ u.first_name }} {{ u.last_name }}
|
||||
{% endfor %}
|
||||
{% elif I.rejected %}
|
||||
Reimbursement Declined
|
||||
{% else %}
|
||||
Needs Approval
|
||||
{% endif %}
|
||||
|
||||
@@ -2,10 +2,60 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
{% for I in items %}
|
||||
{% if error %}
|
||||
<div>
|
||||
<span class="error">{{ error }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if preapproved %}
|
||||
<section>Pre-Approved</section>
|
||||
<div>
|
||||
{% for I in preapproved %}
|
||||
{% include "./item.html" %}
|
||||
{% empty %}
|
||||
<div>No Reimbursements</div>
|
||||
<div class="empty">No Reimbursements</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if newitems %}
|
||||
<section>New Items</section>
|
||||
<div>
|
||||
{% for I in newitems %}
|
||||
{% include "./item.html" %}
|
||||
{% empty %}
|
||||
<div class="empty">No Reimbursements</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if processed %}
|
||||
<section>Approved</section>
|
||||
<div>
|
||||
{% for I in processed %}
|
||||
{% include "./item.html" %}
|
||||
{% empty %}
|
||||
<div class="empty">No Reimbursements</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if rejected %}
|
||||
<section>Rejected</section>
|
||||
<div>
|
||||
{% for I in rejected %}
|
||||
{% include "./item.html" %}
|
||||
{% empty %}
|
||||
<div class="empty">No Reimbursements</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block bottom %}
|
||||
<a href="/items/new" title="Submit new item" class="btn-floating">
|
||||
<span>+</span>
|
||||
</a>
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div>
|
||||
<h1>Add New Reimbursements</h1>
|
||||
<hr>
|
||||
|
||||
@@ -12,7 +13,7 @@
|
||||
you select the correct committee.
|
||||
</div>
|
||||
|
||||
<form action="/new/" method="post">
|
||||
<form action="/items/new" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<div>
|
||||
<label for="desc">Item</label>
|
||||
@@ -53,16 +54,15 @@
|
||||
|
||||
<div>
|
||||
<label for="image">Receipt</label>
|
||||
<input type="file" name="image" id="image">
|
||||
<input type="file" name="image" id="image" accept="image/*">
|
||||
</div>
|
||||
|
||||
<div class="clear">
|
||||
<div>
|
||||
<input type="submit">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user