__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" import datetime from django import forms from django.contrib.auth import get_user_model from django.utils.dates import MONTHS from django.db.models import Sum from django.utils import timezone from ajax_select.fields import AutoCompleteSelectField from dateutil.rrule import rrule, MONTHLY from common.forms import MonthYearWidget from scipost.fields import UserModelChoiceField from .models import Subsidy, SubsidyAttachment, WorkLog class SubsidyForm(forms.ModelForm): organization = AutoCompleteSelectField('organization_lookup') class Meta: model = Subsidy fields = ['organization', 'subsidy_type', 'description', 'amount', 'amount_publicly_shown', 'status', 'date', 'date_until'] class SubsidyAttachmentForm(forms.ModelForm): class Meta: model = SubsidyAttachment fields = ( 'name', 'attachment', 'publicly_visible', ) def save(self, to_object, commit=True): """ This custom save method will automatically assign the file to the object given when it is a valid instance type. """ attachment = super().save(commit=False) # Formset might save an empty Instance if not attachment.name or not attachment.attachment: return None if isinstance(to_object, Subsidy): attachment.subsidy = to_object else: raise forms.ValidationError('You cannot save Attachments to this type of object.') if commit: attachment.save() return attachment class SubsidyAttachmentFormSet(forms.BaseModelFormSet): def save(self, to_object, commit=True): """ This custom save method will automatically assign the file to the object given when it is a valid instance type. """ returns = [] for form in self.forms: returns.append(form.save(to_object)) return returns class WorkLogForm(forms.ModelForm): def __init__(self, *args, **kwargs): self.types = kwargs.pop('log_types', False) super().__init__(*args, **kwargs) if self.types: self.fields['log_type'] = forms.ChoiceField(choices=self.types) class Meta: model = WorkLog fields = ( 'comments', 'log_type', 'duration', ) widgets = { 'comments': forms.Textarea(attrs={'rows': 4}), 'duration': forms.TextInput(attrs={'placeholder': 'HH:MM:SS'}) } class LogsFilter(forms.Form): """ Filter work logs given the requested date range and users. """ employee = UserModelChoiceField( queryset=get_user_model().objects.filter(work_logs__isnull=False).distinct(), required=False, empty_label='Show all') start = forms.DateField(widget=MonthYearWidget(required=True), required=True) # Month end = forms.DateField(widget=MonthYearWidget(required=True, end=True), required=True) # Month def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) today = timezone.now().date() self.initial['start'] = today.today() self.initial['end'] = today.today() def clean(self): if self.is_valid(): self.cleaned_data['months'] = [ dt for dt in rrule( MONTHLY, dtstart=self.cleaned_data['start'], until=self.cleaned_data['end'])] return self.cleaned_data def get_months(self): if self.is_valid(): return self.cleaned_data.get('months', []) return [] def filter(self): """Filter work logs and return in user-grouped format.""" output = [] if self.is_valid(): if self.cleaned_data['employee']: user_qs = get_user_model().objects.filter(id=self.cleaned_data['employee'].id) else: user_qs = get_user_model().objects.filter(work_logs__isnull=False) user_qs = user_qs.filter( work_logs__work_date__gte=self.cleaned_data['start'], work_logs__work_date__lte=self.cleaned_data['end']).distinct() output = [] for user in user_qs: logs = user.work_logs.filter( work_date__gte=self.cleaned_data['start'], work_date__lte=self.cleaned_data['end']).distinct() output.append({ 'logs': logs, 'duration': logs.aggregate(total=Sum('duration')), 'user': user, }) return output def filter_per_month(self): """Filter work logs and return in per-month format.""" output = [] if self.is_valid(): if self.cleaned_data['employee']: user_qs = get_user_model().objects.filter(id=self.cleaned_data['employee'].id) else: user_qs = get_user_model().objects.filter(work_logs__isnull=False) user_qs = user_qs.filter( work_logs__work_date__gte=self.cleaned_data['start'], work_logs__work_date__lte=self.cleaned_data['end']).distinct() output = [] for user in user_qs: # If logs exists for given filters output.append({ 'logs': [], 'user': user, }) for dt in self.get_months(): output[-1]['logs'].append( user.work_logs.filter( work_date__year=dt.year, work_date__month=dt.month).aggregate(total=Sum('duration'))['total']) return output