Merge branch 'master' into feature/team_refactor
This commit is contained in:
commit
a4060c2815
|
@ -38,7 +38,7 @@ Install system dependencies (method depends on OS):
|
|||
### Python packages
|
||||
Install pip packages:
|
||||
```
|
||||
(venv) $ pip install -r src/requirements.txt
|
||||
(venv) $ pip install -r src/requirements/dev.txt
|
||||
```
|
||||
|
||||
### Configuration file
|
||||
|
|
|
@ -34,6 +34,14 @@
|
|||
<h4 class="list-group-item-heading">Manage Proposals</h4>
|
||||
<p class="list-group-item-text">Use this view to manage SpeakerProposals and EventProposals</p>
|
||||
</a>
|
||||
<a href="{% url 'backoffice:merchandise_orders' camp_slug=camp.slug %}" class="list-group-item">
|
||||
<h4 class="list-group-item-heading">Merchandise Orders</h4>
|
||||
<p class="list-group-item-text">Use this view to look at Merchandise Orders</p>
|
||||
</a>
|
||||
<a href="{% url 'backoffice:merchandise_to_order' camp_slug=camp.slug %}" class="list-group-item">
|
||||
<h4 class="list-group-item-heading">Merchandise To Order</h4>
|
||||
<p class="list-group-item-text">Use this view to generate a list of merchandise that needs to be ordered</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
44
src/backoffice/templates/merchandise_to_order.html
Normal file
44
src/backoffice/templates/merchandise_to_order.html
Normal file
|
@ -0,0 +1,44 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load commonmark %}
|
||||
{% load static from staticfiles %}
|
||||
{% load imageutils %}
|
||||
{% block extra_head %}
|
||||
<script src="{% static "js/jquery.dataTables.min.js" %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'css/jquery.dataTables.min.css' %}">
|
||||
{% endblock extra_head %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<h2>Merchandise To Order</h2>
|
||||
<div class="lead">
|
||||
This is a list of merchandise to order from our supplier
|
||||
</div>
|
||||
<div>
|
||||
This table shows all different merchandise that needs to be ordered
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Merchandise Type</th>
|
||||
<th>Quantity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for key, val in merchandise.items %}
|
||||
<tr>
|
||||
<td>{{ key }}</td>
|
||||
<td>{{ val }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('.table').DataTable();
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock content %}
|
51
src/backoffice/templates/orders_merchandise.html
Normal file
51
src/backoffice/templates/orders_merchandise.html
Normal file
|
@ -0,0 +1,51 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load commonmark %}
|
||||
{% load static from staticfiles %}
|
||||
{% load imageutils %}
|
||||
{% block extra_head %}
|
||||
<script src="{% static "js/jquery.dataTables.min.js" %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'css/jquery.dataTables.min.css' %}">
|
||||
{% endblock extra_head %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<h2>Merchandise Orders</h2>
|
||||
<div class="lead">
|
||||
Use this view to look at merchandise orders. </div>
|
||||
<div>
|
||||
This table shows all OrderProductRelations which are Merchandise (not including handed out, unpaid, cancelled and refunded orders). The table is initally sorted by order ID but the sorting can be changed by clicking the column headlines (if javascript is enabled).
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order</th>
|
||||
<th>User</th>
|
||||
<th>Email</th>
|
||||
<th>OPR Id</th>
|
||||
<th>Product</th>
|
||||
<th>Quantity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for productrel in orderproductrelation_list %}
|
||||
<tr>
|
||||
<td><a href="/admin/shop/order/{{ productrel.order.id }}/change/">Order #{{ productrel.order.id }}</a></td>
|
||||
<td>{{ productrel.order.user }}</td>
|
||||
<td>{{ productrel.order.user.email }}</td>
|
||||
<td>{{ productrel.id }}</td>
|
||||
<td>{{ productrel.product.name }}</td>
|
||||
<td>{{ productrel.quantity }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('.table').DataTable();
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock content %}
|
|
@ -10,6 +10,8 @@ urlpatterns = [
|
|||
path('badge_handout/', BadgeHandoutView.as_view(), name='badge_handout'),
|
||||
path('ticket_checkin/', TicketCheckinView.as_view(), name='ticket_checkin'),
|
||||
path('public_credit_names/', ApproveNamesView.as_view(), name='public_credit_names'),
|
||||
path('merchandise_orders/', MerchandiseOrdersView.as_view(), name='merchandise_orders'),
|
||||
path('merchandise_to_order/', MerchandiseToOrderView.as_view(), name='merchandise_to_order'),
|
||||
path('manage_proposals/', include([
|
||||
path('', ManageProposalsView.as_view(), name='manage_proposals'),
|
||||
path('speakers/<uuid:pk>/', SpeakerProposalManageView.as_view(), name='speakerproposal_manage'),
|
||||
|
|
|
@ -5,14 +5,12 @@ from django.views.generic import TemplateView, ListView
|
|||
from django.views.generic.edit import UpdateView
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib import messages
|
||||
from django.utils import timezone
|
||||
|
||||
from shop.models import OrderProductRelation
|
||||
from tickets.models import ShopTicket, SponsorTicket, DiscountTicket
|
||||
from profiles.models import Profile
|
||||
from camps.models import Camp
|
||||
from camps.mixins import CampViewMixin
|
||||
from program.models import SpeakerProposal, EventProposal
|
||||
|
||||
from .mixins import BackofficeViewMixin
|
||||
|
@ -26,7 +24,9 @@ class BackofficeIndexView(BackofficeViewMixin, TemplateView):
|
|||
|
||||
class ProductHandoutView(BackofficeViewMixin, ListView):
|
||||
template_name = "product_handout.html"
|
||||
queryset = OrderProductRelation.objects.filter(
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
return OrderProductRelation.objects.filter(
|
||||
handed_out=False,
|
||||
order__paid=True,
|
||||
order__refunded=False,
|
||||
|
@ -123,3 +123,48 @@ class EventProposalManageView(ProposalManageView):
|
|||
model = EventProposal
|
||||
template_name = "manage_eventproposal.html"
|
||||
|
||||
|
||||
class MerchandiseOrdersView(BackofficeViewMixin, ListView):
|
||||
template_name = "orders_merchandise.html"
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
camp_prefix = 'BornHack {}'.format(timezone.now().year)
|
||||
|
||||
return OrderProductRelation.objects.filter(
|
||||
handed_out=False,
|
||||
order__paid=True,
|
||||
order__refunded=False,
|
||||
order__cancelled=False,
|
||||
product__category__name='Merchandise',
|
||||
).filter(
|
||||
product__name__startswith=camp_prefix
|
||||
).order_by('order')
|
||||
|
||||
|
||||
class MerchandiseToOrderView(BackofficeViewMixin, TemplateView):
|
||||
template_name = "merchandise_to_order.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
camp_prefix = 'BornHack {}'.format(timezone.now().year)
|
||||
|
||||
order_relations = OrderProductRelation.objects.filter(
|
||||
handed_out=False,
|
||||
order__paid=True,
|
||||
order__refunded=False,
|
||||
order__cancelled=False,
|
||||
product__category__name='Merchandise',
|
||||
).filter(
|
||||
product__name__startswith=camp_prefix
|
||||
)
|
||||
|
||||
merchandise_orders = {}
|
||||
for relation in order_relations:
|
||||
try:
|
||||
quantity = merchandise_orders[relation.product.name] + relation.quantity
|
||||
merchandise_orders[relation.product.name] = quantity
|
||||
except KeyError:
|
||||
merchandise_orders[relation.product.name] = relation.quantity
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['merchandise'] = merchandise_orders
|
||||
return context
|
||||
|
|
|
@ -136,6 +136,22 @@ class SpeakerProposalForm(forms.ModelForm):
|
|||
# no free tickets for workshops
|
||||
del(self.fields['needs_oneday_ticket'])
|
||||
|
||||
elif eventtype.name == 'Meetup':
|
||||
# fix label and help_text for the name field
|
||||
self.fields['name'].label = 'Host Name'
|
||||
self.fields['name'].help_text = 'The name of the meetup host. Can be a real name or an alias.'
|
||||
|
||||
# fix label and help_text for the biograpy field
|
||||
self.fields['biography'].label = 'Host Biography'
|
||||
self.fields['biography'].help_text = 'The biography of the host.'
|
||||
|
||||
# fix label and help_text for the submission_notes field
|
||||
self.fields['submission_notes'].label = 'Host Notes'
|
||||
self.fields['submission_notes'].help_text = 'Private notes regarding this host. Only visible to yourself and the BornHack organisers.'
|
||||
|
||||
# no free tickets for workshops
|
||||
del(self.fields['needs_oneday_ticket'])
|
||||
|
||||
else:
|
||||
raise ImproperlyConfigured("Unsupported event type, don't know which form class to use")
|
||||
|
||||
|
@ -281,6 +297,26 @@ class EventProposalForm(forms.ModelForm):
|
|||
self.fields['duration'].label = 'Event Duration'
|
||||
self.fields['duration'].help_text = 'How much time (in minutes) should we set aside for this event? Please keep it between 60 and 180 minutes (1-3 hours).'
|
||||
|
||||
elif eventtype.name == 'Meetup':
|
||||
# fix label and help_text for the title field
|
||||
self.fields['title'].label = 'Meetup Title'
|
||||
self.fields['title'].help_text = 'The title of this meetup.'
|
||||
|
||||
# fix label and help_text for the submission_notes field
|
||||
self.fields['submission_notes'].label = 'Meetup Notes'
|
||||
self.fields['submission_notes'].help_text = 'Private notes regarding this meetup. Only visible to yourself and the BornHack organisers.'
|
||||
|
||||
# fix label and help_text for the abstract field
|
||||
self.fields['abstract'].label = 'Meetup Abstract'
|
||||
self.fields['abstract'].help_text = 'The description/abstract of this meetup. Explain what the meetup is about and who should attend.'
|
||||
|
||||
# no video recording for meetups
|
||||
del(self.fields['allow_video_recording'])
|
||||
|
||||
# duration field
|
||||
self.fields['duration'].label = 'Meetup Duration'
|
||||
self.fields['duration'].help_text = 'How much time (in minutes) should we set aside for this meetup? Please keep it between 60 and 180 minutes (1-3 hours).'
|
||||
|
||||
else:
|
||||
raise ImproperlyConfigured("Unsupported event type, don't know which form class to use")
|
||||
|
||||
|
|
|
@ -376,10 +376,10 @@ class EventProposal(UserSubmittedModel):
|
|||
eventmodel = apps.get_model('program', 'event')
|
||||
eventproposalmodel = apps.get_model('program', 'eventproposal')
|
||||
# use existing event if we have one
|
||||
if self.event:
|
||||
event = self.event
|
||||
else:
|
||||
if not hasattr(self, 'event'):
|
||||
event = eventmodel()
|
||||
else:
|
||||
event = self.event
|
||||
event.track = self.track
|
||||
event.title = self.title
|
||||
event.abstract = self.abstract
|
||||
|
@ -392,6 +392,8 @@ class EventProposal(UserSubmittedModel):
|
|||
try:
|
||||
event.speakers.add(sp.speaker)
|
||||
except ObjectDoesNotExist:
|
||||
# clean up
|
||||
event.urls.clear()
|
||||
event.delete()
|
||||
raise ValidationError('Not all speakers are approved or created yet.')
|
||||
|
||||
|
|
|
@ -84,45 +84,46 @@ def coinify_api_request(api_method, order, **kwargs):
|
|||
return req
|
||||
|
||||
|
||||
def handle_coinify_api_response(req, order):
|
||||
if req.method == 'invoice_create' or req.method == 'invoice_get':
|
||||
def handle_coinify_api_response(apireq, order, request):
|
||||
if apireq.method == 'invoice_create' or apireq.method == 'invoice_get':
|
||||
# Parse api response
|
||||
if req.response['success']:
|
||||
if apireq.response['success']:
|
||||
# save this new coinify invoice to the DB
|
||||
coinifyinvoice = process_coinify_invoice_json(
|
||||
invoicejson=req.response['data'],
|
||||
invoicejson=apireq.response['data'],
|
||||
order=order,
|
||||
request=request,
|
||||
)
|
||||
return coinifyinvoice
|
||||
else:
|
||||
api_error = req.response['error']
|
||||
api_error = apireq.response['error']
|
||||
logger.error("coinify API error: %s (%s)" % (
|
||||
api_error['message'],
|
||||
api_error['code']
|
||||
))
|
||||
return False
|
||||
else:
|
||||
logger.error("coinify api method not supported" % req.method)
|
||||
logger.error("coinify api method not supported" % apireq.method)
|
||||
return False
|
||||
|
||||
|
||||
################### API CALLS ################################################
|
||||
|
||||
|
||||
def get_coinify_invoice(coinify_invoiceid, order):
|
||||
def get_coinify_invoice(coinify_invoiceid, order, request):
|
||||
# put args for API request together
|
||||
invoicedict = {
|
||||
'invoice_id': coinify_invoiceid
|
||||
}
|
||||
|
||||
# perform the api request
|
||||
req = coinify_api_request(
|
||||
apireq = coinify_api_request(
|
||||
api_method='invoice_get',
|
||||
order=order,
|
||||
**invoicedict
|
||||
)
|
||||
|
||||
coinifyinvoice = handle_coinify_api_response(req, order)
|
||||
coinifyinvoice = handle_coinify_api_response(apireq, order, request)
|
||||
return coinifyinvoice
|
||||
|
||||
|
||||
|
@ -140,12 +141,12 @@ def create_coinify_invoice(order, request):
|
|||
}
|
||||
|
||||
# perform the API request
|
||||
req = coinify_api_request(
|
||||
apireq = coinify_api_request(
|
||||
api_method='invoice_create',
|
||||
order=order,
|
||||
**invoicedict
|
||||
)
|
||||
|
||||
coinifyinvoice = handle_coinify_api_response(req, order)
|
||||
coinifyinvoice = handle_coinify_api_response(apireq, order, request)
|
||||
return coinifyinvoice
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
body {
|
||||
margin-top: 85px;
|
||||
margin-bottom: 35px;
|
||||
margin-bottom: 65px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,20 @@ a, a:active, a:focus {
|
|||
outline: none;
|
||||
}
|
||||
|
||||
/* Z-index */
|
||||
/* Bootstrap values
|
||||
.dropdown-backdrop { z-index: 990; }
|
||||
.navbar-static-top, .dropdown-menu { z-index: 1000; }
|
||||
.navbar-fixed-top, .navbar-fixed-bottom { z-index: 1030; }
|
||||
.modal-backdrop { z-index: 1040; }
|
||||
.modal { z-index: 1050; }
|
||||
.popover { z-index: 1060; }
|
||||
.tooltip { z-index: 1070; }
|
||||
*/
|
||||
.sticky {
|
||||
z-index: 980;
|
||||
}
|
||||
|
||||
@media (max-width: 520px) {
|
||||
#main {
|
||||
width: 100%;
|
||||
|
@ -236,7 +250,6 @@ footer {
|
|||
.sticky {
|
||||
position: sticky;
|
||||
background-color: #fff;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
#daypicker {
|
||||
|
|
BIN
src/static_src/img/sponsors/DM_Logo_RGB.png
Normal file
BIN
src/static_src/img/sponsors/DM_Logo_RGB.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.4 KiB |
BIN
src/static_src/img/sponsors/epson.png
Executable file
BIN
src/static_src/img/sponsors/epson.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
BIN
src/static_src/img/sponsors/letsgo.png
Normal file
BIN
src/static_src/img/sponsors/letsgo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
src/static_src/img/sponsors/pcbway.png
Normal file
BIN
src/static_src/img/sponsors/pcbway.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
24
src/teams/migrations/0043_auto_20180804_1641.py
Normal file
24
src/teams/migrations/0043_auto_20180804_1641.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 2.0.4 on 2018-08-04 14:41
|
||||
|
||||
import django.contrib.postgres.fields.ranges
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('teams', '0042_auto_20180413_1933'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='teamtask',
|
||||
name='completed',
|
||||
field=models.BooleanField(default=False, help_text='Check to mark this task as completed.'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='teamtask',
|
||||
name='when',
|
||||
field=django.contrib.postgres.fields.ranges.DateTimeRangeField(blank=True, help_text='When does this task need to be started and/or finished?', null=True),
|
||||
),
|
||||
]
|
|
@ -4,6 +4,7 @@ from django.dispatch import receiver
|
|||
from django.utils.text import slugify
|
||||
from utils.models import CampRelatedModel
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.contrib.postgres.fields import DateTimeRangeField
|
||||
from django.contrib.auth.models import User
|
||||
from django.urls import reverse_lazy
|
||||
from django.conf import settings
|
||||
|
@ -281,6 +282,15 @@ class TeamTask(CampRelatedModel):
|
|||
description = models.TextField(
|
||||
help_text='Description of the task. Markdown is supported.'
|
||||
)
|
||||
when = DateTimeRangeField(
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text='When does this task need to be started and/or finished?'
|
||||
)
|
||||
completed = models.BooleanField(
|
||||
help_text='Check to mark this task as completed.',
|
||||
default=False
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
|
44
src/teams/templates/includes/team_tasks.html
Normal file
44
src/teams/templates/includes/team_tasks.html
Normal file
|
@ -0,0 +1,44 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4>Tasks</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>The {{ team.name }} Team is responsible for the following tasks</p>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>When</th>
|
||||
<th>Completed</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for task in team.tasks.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'teams:task_detail' slug=task.slug camp_slug=camp.slug team_slug=team.slug %}">{{ task.name }}</a></td>
|
||||
<td>{{ task.description }}</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Start: {{ task.when.lower|default:"N/A" }}<br>
|
||||
<li>Finish: {{ task.when.upper|default:"N/A" }}<br>
|
||||
</ul>
|
||||
</td>
|
||||
<td>{{ task.completed }}</td>
|
||||
<td>
|
||||
<a href="{% url 'teams:task_detail' camp_slug=camp.slug team_slug=team.slug slug=task.slug %}" class="btn btn-primary btn-sm"><i class="fas fa-search"></i> Details</a>
|
||||
{% if request.user in team.responsible_members.all %}
|
||||
<a href="{% url 'teams:task_update' camp_slug=camp.slug team_slug=team.slug slug=task.slug %}" class="btn btn-primary btn-sm"><i class="fas fa-edit"></i> Edit Task</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if request.user in team.responsible_members.all %}
|
||||
<a href="{% url 'teams:task_create' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-primary"><i class="fas fa-plus"></i> Create Task</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -7,8 +7,16 @@
|
|||
|
||||
{% block team_content %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><h4>Task: {{ task.name }}</h4></div>
|
||||
<div class="panel-body">{{ task.description|untrustedcommonmark }}</div>
|
||||
<div class="panel-heading"><h4>Task: {{ task.name }} ({% if not task.completed %}Not {% endif %}Completed)</h4></div>
|
||||
<div class="panel-body">
|
||||
{{ task.description|untrustedcommonmark }}
|
||||
<hr>
|
||||
<ul>
|
||||
<li>Start: {{ task.when.lower|default:"N/A" }}<br>
|
||||
<li>Finish: {{ task.when.upper|default:"N/A" }}<br>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-footer"><i>This task belongs to the <a href="{% url 'teams:detail' team_slug=task.team.slug camp_slug=task.team.camp.slug %}">{{ task.team.name }} Team</a></i></div>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -26,4 +26,3 @@ Manage Team: {{ team.name }} | {{ block.super }}
|
|||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ class TaskDetailView(CampViewMixin, TeamViewMixin, DetailView):
|
|||
class TaskCreateView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamResponsibleMixin, CreateView):
|
||||
model = TeamTask
|
||||
template_name = "task_form.html"
|
||||
fields = ['name', 'description']
|
||||
fields = ['name', 'description', 'when', 'completed']
|
||||
active_menu = 'tasks'
|
||||
|
||||
def get_team(self):
|
||||
|
@ -49,7 +49,7 @@ class TaskCreateView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTea
|
|||
class TaskUpdateView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamResponsibleMixin, UpdateView):
|
||||
model = TeamTask
|
||||
template_name = "task_form.html"
|
||||
fields = ['name', 'description']
|
||||
fields = ['name', 'description', 'when', 'completed']
|
||||
active_menu = 'tasks'
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
|
|
Loading…
Reference in a new issue