diff --git a/events/forms.py b/events/forms.py index cdb12376..0b22d4af 100644 --- a/events/forms.py +++ b/events/forms.py @@ -20,6 +20,7 @@ from django.utils import timezone # python multithreading bug workaround from pagedown.widgets import PagedownWidget +from accounts.models import User from data.forms import DynamicFieldContainer, FieldAccessForm, FieldAccessLevel from events.fields import GroupedModelChoiceField @@ -1268,6 +1269,60 @@ class Meta: category = ModelChoiceField(queryset=Category.objects.all(), required=False) service = ModelChoiceField(queryset=Service.objects.all(), required=False) # queryset gets changed in constructor +class MKSingleHoursForm(forms.ModelForm): + """ Hours Form for a single user at an event""" + def __init__(self, event, user, *args, **kwargs): + self.event = event + self.user = user + self.helper = FormHelper() + self.helper.form_class = "form-horizontal" + self.helper.form_method = "post" + self.helper.form_action = "" + self.helper.layout = Layout( + Field('user'), + Field('hours'), + Field('service'), + FormActions( + Submit('save', 'Save Changes'), + # Reset('reset','Reset Form'), + ) + ) + super(MKSingleHoursForm, self).__init__(*args, **kwargs) + self.fields['service'].queryset = get_qs_from_event(self.event) + if isinstance(self.event, Event2019): + self.fields['category'].queryset = Category.objects.filter( + pk__in=self.event.serviceinstance_set.values_list('service__category', flat=True)) + if user is not None: + self.fields['user'] = forms.ModelChoiceField(queryset=User.objects.filter(pk=user.id), disabled=True, empty_label=None, initial=user) + + def clean(self): + user = self.user if self.user is not None else self.cleaned_data.get('user') + super(MKSingleHoursForm, self).clean() + category = self.cleaned_data.get('category') + service = self.cleaned_data.get('service') + if user is None: + # this problem will raise an error elsewhere + return + if self.event.hours.filter(user=user, category=category, service=service).exists() and not self.instance.pk: + raise ValidationError("User already has hours for this category/service. Edit those instead") + + def save(self, commit=True): + obj = super(MKSingleHoursForm, self).save(commit=False) + if obj.category is None and obj.service is not None: + obj.category = obj.service.category + obj.event = self.event + if commit: + obj.save() + return obj + + class Meta: + model = Hours + fields = ('user','hours', 'category', 'service') + + user = AutoCompleteSelectField('Users', required=True) + hours = forms.DecimalField(min_value=decimal.Decimal("0.00")) + category = ModelChoiceField(queryset=Category.objects.all(), required=False) + service = ModelChoiceField(queryset=Service.objects.all(), required=False) # queryset gets changed in constructor class EditHoursForm(forms.ModelForm): def __init__(self, *args, **kwargs): diff --git a/events/urls/events.py b/events/urls/events.py index d0d00829..16bb60d3 100644 --- a/events/urls/events.py +++ b/events/urls/events.py @@ -68,6 +68,10 @@ def generate_date_patterns(func, name): flow_views.rmcrew, name="remove-crew"), url(r'^(?P[0-9]+)/hours/bulk/$', flow_views.hours_bulk_admin, name="add-bulk-crew"), + url(r'^(?P[0-9]+)/hours/single/(?P[0-9a-f]+)/$', flow_views.hours_single_admin, + name="edit_single_crew_hours"), + url(r'^(?P[0-9]+)/hours/single/$', flow_views.hours_single_admin, + name="edit_single_crew_hours"), url(r'^selfcrew/(?P[0-9]+)/$', flow_views.hours_prefill_self, name="selfcrew"), url(r'^crewchief/(?P[0-9a-f]+)/$', flow_views.assigncc, name="chiefs"), url(r'^rmcc/(?P[0-9a-f]+)/(?P[0-9a-f]+)/$', flow_views.rmcc, name="remove-chief"), diff --git a/events/views/flow.py b/events/views/flow.py index 7d22928c..fc7fb426 100644 --- a/events/views/flow.py +++ b/events/views/flow.py @@ -18,12 +18,12 @@ from django.views.decorators.http import require_GET, require_POST from reversion.models import Version -from accounts.models import UserPreferences +from accounts.models import User, UserPreferences from emails.generators import (ReportReminderEmailGenerator, EventEmailGenerator, BillingEmailGenerator, DefaultLNLEmailGenerator as DLEG, send_survey_if_necessary) from slack.views import cc_report_reminder from slack.api import lookup_user, slack_post -from events.forms import (AttachmentForm, BillingForm, BillingUpdateForm, MultiBillingForm, +from events.forms import (AttachmentForm, BillingForm, BillingUpdateForm, EditHoursForm, MKSingleHoursForm, MultiBillingForm, MultiBillingUpdateForm, CCIForm, CrewAssign, EventApprovalForm, EventDenialForm, EventReviewForm, ExtraForm, InternalReportForm, MKHoursForm, BillingEmailForm, MultiBillingEmailForm, ServiceInstanceForm, WorkdayForm, CrewCheckinForm, @@ -449,6 +449,41 @@ def hours_bulk_admin(request, id): context['formset'] = formset return render(request, 'formset_hours_bulk.html', context) +@login_required +def hours_single_admin(request, id, user=None): + """ Update single crew member hours """ + try: + user = User.objects.get(pk=user) + context = {'msg': "Update Crew Hours"} + except User.DoesNotExist: + context = {'msg': "Add Crew Hours"} + event = get_object_or_404(BaseEvent, pk=id) + if not event.reports_editable and not request.user.has_perm('events.edit_event_hours') and \ + request.user.has_perm('events.edit_event_hours', event): + return render(request, 'too_late.html', {'days': CCR_DELTA, 'event': event}) + if not (request.user.has_perm('events.edit_event_hours') or + request.user.has_perm('events.edit_event_hours', event) and event.reports_editable): + raise PermissionDenied + if event.closed: + messages.add_message(request, messages.ERROR, 'Event is closed.') + return HttpResponseRedirect(reverse('events:detail', args=(event.id,))) + context['event'] = event + context['oldevent'] = isinstance(event, Event) + + mk_hours_formset = inlineformset_factory(BaseEvent, Hours, exclude=[], extra=(0 if event.hours.filter(user=user).exists() else 1)) + mk_hours_formset.form = curry_class(MKSingleHoursForm, event=event, user=user) + + if request.method == 'POST': + formset = mk_hours_formset(request.POST, instance=event) + if formset.is_valid(): + formset.save() + return HttpResponseRedirect(reverse('events:detail', args=(event.id,)) + "#reports") + else: + formset = mk_hours_formset(instance=event, queryset=Hours.objects.filter(user=user)) + + context['formset'] = formset + return render(request, 'formset_hours_bulk.html', context) + @login_required @require_GET diff --git a/site_tmpl/formset_hours_bulk.html b/site_tmpl/formset_hours_bulk.html index 8ca916c1..028a7912 100644 --- a/site_tmpl/formset_hours_bulk.html +++ b/site_tmpl/formset_hours_bulk.html @@ -4,7 +4,7 @@ {% block content %}
-

{{msg }} Crew Chiefs for "{{ event }}"

+

{{ msg }} for "{{ event }}"

{% csrf_token %} {{ formset.management_form }} diff --git a/site_tmpl/uglydetail.html b/site_tmpl/uglydetail.html index 629e9f5f..5b2fb4c1 100644 --- a/site_tmpl/uglydetail.html +++ b/site_tmpl/uglydetail.html @@ -581,7 +581,8 @@

Crew Chiefs Needing Reports

{% endif %} {% if not event.closed %} {% permission request.user has 'events.edit_event_hours' of event %} -
+ {% endpermission %} @@ -593,6 +594,7 @@

Hours

Member Hours Category + {% for hour in event.hours.all %} @@ -607,6 +609,11 @@

Hours

{% endif %} {{ hour.category }} + + {% if not event.closed %}{% permission request.user has 'events.edit_event_hours' of event %} + Edit + {% endpermission %}{% endif %} + {% endfor %}