Generated: Tue 2013-05-07 14:07 CEST
Source file: /home/tobi/Projects/django-payslip/src/payslip/views.py
Stats: 135 executed, 0 missed, 13 excluded, 228 ignored
"""Views for the ``online_docs`` app."""import cStringIO as StringIOimport osfrom django.contrib.auth.decorators import login_requiredfrom django.core.urlresolvers import reversefrom django.db.models import Q, Sumfrom django.http import Http404, HttpResponsefrom django.utils.decorators import method_decoratorfrom django.views.generic import ( CreateView, DeleteView, FormView, TemplateView, UpdateView,)from dateutil import parser, rrulefrom xhtml2pdf import pisafrom .app_settings import CURRENCYfrom .forms import ( EmployeeForm, ExtraFieldForm, PaymentForm, PayslipForm,)from .models import ( Company, Employee, ExtraField, ExtraFieldType, Payment, PaymentType,)#-------------## Mixins ##-------------#class PermissionMixin(object): """Mixin to handle security functions.""" @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): """ Makes sure that the user is logged in and has the right to display this view. """ if not request.user.is_staff: raise Http404 return super(PermissionMixin, self).dispatch(request, *args, **kwargs) def get_success_url(self): return reverse('payslip_dashboard')class CompanyMixin(object): """Mixin to handle company related functions.""" @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): """ Makes sure that the user is logged in and has the right to display this view. """ self.kwargs = kwargs self.object = self.get_object() try: Employee.objects.get(company=self.object, user=request.user, is_manager=True) except Employee.DoesNotExist: if not request.user.is_staff: raise Http404 return super(CompanyMixin, self).dispatch(request, *args, **kwargs) def get_success_url(self): return reverse('payslip_dashboard')class CompanyPermissionMixin(object): """Mixin to handle company-wide permissions functions.""" @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): """ Makes sure that the user is logged in and has the right to display this view. """ try: self.company = Employee.objects.get( user=request.user, is_manager=True).company except Employee.DoesNotExist: if not request.user.is_staff: raise Http404 self.company = None return super(CompanyPermissionMixin, self).dispatch(request, *args, **kwargs) def get_success_url(self): return reverse('payslip_dashboard')class EmployeeMixin(object): """Mixin to handle employee related functions.""" form_class = EmployeeForm def get_form_kwargs(self): kwargs = super(EmployeeMixin, self).get_form_kwargs() kwargs.update({'company': self.company}) return kwargsclass ExtraFieldMixin(object): """Mixin to handle extra field related functions.""" model = ExtraField form_class = ExtraFieldFormclass ExtraFieldTypeMixin(object): """Mixin to handle extra field type related functions.""" model = ExtraFieldTypeclass PaymentMixin(object): """Mixin to handle payment related functions.""" model = Payment form_class = PaymentFormclass PaymentTypeMixin(object): """Mixin to handle payment type related functions.""" model = PaymentType#-------------## Views ##-------------#class DashboardView(PermissionMixin, TemplateView): """Dashboard to navigate through the payslip app.""" template_name = 'payslip/dashboard.html' def get_context_data(self, **kwargs): return { 'companies': Company.objects.all(), 'employees': Employee.objects.all(), 'extra_field_types': ExtraFieldType.objects.all(), 'fixed_value_extra_fields': ExtraField.objects.filter( field_type__fixed_values=True), 'payments': Payment.objects.all(), 'payment_types': PaymentType.objects.all(), }class CompanyCreateView(PermissionMixin, CreateView): """Classic view to create a company.""" model = Company def get_success_url(self): return reverse('payslip_dashboard')class CompanyUpdateView(CompanyMixin, UpdateView): """Classic view to update a company.""" model = Companyclass CompanyDeleteView(CompanyMixin, DeleteView): """Classic view to delete a company.""" model = Companyclass EmployeeCreateView(CompanyPermissionMixin, EmployeeMixin, CreateView): """Classic view to create an employee.""" model = Employeeclass EmployeeUpdateView(CompanyPermissionMixin, EmployeeMixin, UpdateView): """Classic view to update an employee.""" model = Employeeclass EmployeeDeleteView(CompanyPermissionMixin, EmployeeMixin, DeleteView): """Classic view to delete an employee.""" model = Employeeclass ExtraFieldTypeCreateView(PermissionMixin, ExtraFieldTypeMixin, CreateView): """Classic view to create an extra field type.""" passclass ExtraFieldTypeUpdateView(PermissionMixin, ExtraFieldTypeMixin, UpdateView): """Classic view to update an extra field type.""" passclass ExtraFieldTypeDeleteView(PermissionMixin, ExtraFieldTypeMixin, DeleteView): """Classic view to delete an extra field type.""" passclass ExtraFieldCreateView(PermissionMixin, ExtraFieldMixin, CreateView): """Classic view to create an extra field.""" passclass ExtraFieldUpdateView(PermissionMixin, ExtraFieldMixin, UpdateView): """Classic view to update an extra field.""" passclass ExtraFieldDeleteView(PermissionMixin, ExtraFieldMixin, DeleteView): """Classic view to delete an extra field.""" passclass PaymentTypeCreateView(CompanyPermissionMixin, PaymentTypeMixin, CreateView): """Classic view to create a payment type.""" passclass PaymentTypeUpdateView(CompanyPermissionMixin, PaymentTypeMixin, UpdateView): """Classic view to update a payment type.""" passclass PaymentTypeDeleteView(CompanyPermissionMixin, PaymentTypeMixin, DeleteView): """Classic view to delete a payment type.""" passclass PaymentCreateView(CompanyPermissionMixin, PaymentMixin, CreateView): """Classic view to create a payment.""" passclass PaymentUpdateView(CompanyPermissionMixin, PaymentMixin, UpdateView): """Classic view to update a payment.""" passclass PaymentDeleteView(CompanyPermissionMixin, PaymentMixin, DeleteView): """Classic view to delete a payment.""" passclass PayslipGeneratorView(CompanyPermissionMixin, FormView): """View to present a small form to generate a custom payslip.""" template_name = 'payslip/payslip_form.html' form_class = PayslipForm def get_form_kwargs(self): kwargs = super(PayslipGeneratorView, self).get_form_kwargs() kwargs.update({'company': self.company}) return kwargs def get_template_names(self): if hasattr(self, 'post_data'): return ['payslip/payslip.html'] return super(PayslipGeneratorView, self).get_template_names() def get_context_data(self, **kwargs): kwargs = super(PayslipGeneratorView, self).get_context_data(**kwargs) if hasattr(self, 'post_data'): # Get form data employee = Employee.objects.get(pk=self.post_data.get('employee')) date_start = parser.parse(self.post_data.get('date_start')) date_end = parser.parse(self.post_data.get('date_end')) # Get payments for the selected year payments_year = employee.payments.filter( # Single payments in this year Q(date__year=date_start.year, payment_type__rrule__exact='') | # Recurring payments with past date and end_date in the # selected year or later Q(date__lte=date_end, end_date__gte=parser.parse( '{0}0101T000000'.format(date_start.year)), payment_type__rrule__isnull=False) | # Recurring payments with past date in period and open end Q(date__lte=date_end, end_date__isnull=True, payment_type__rrule__isnull=False) ) # Get payments for the selected period payments = payments_year.filter( # Single payments in the selected period Q(date__gte=date_start, date__lte=date_end, payment_type__rrule__exact='') | # Recurring payments with past date and end_date in the period Q(end_date__lte=date_end, end_date__gte=date_start, date__lte=date_end, payment_type__rrule__isnull=False) | # Recurring payments with past date in period and open end Q(date__lte=date_end, end_date__isnull=True, payment_type__rrule__isnull=False) ) # Yearly positive summary sum_year = payments_year.filter( amount__gt=0, payment_type__rrule__exact='').aggregate( Sum('amount')).get('amount__sum') or 0 # Yearly negative summary sum_year_neg = payments_year.filter( amount__lt=0, payment_type__rrule__exact='').aggregate( Sum('amount')).get('amount__sum') or 0 # Yearly summary of recurring payments for payment in payments_year.exclude( payment_type__rrule__exact=''): # If the recurring payment started in a year before, let's take # January 1st as a start, otherwise take the original date if payment.date.year < date_start.year: start = parser.parse('{0}0101T000000'.format( date_start.year)) else: start = payment.date # If the payments ends before the period's end date, let's take # this date, otherwise we can take the period's end if payment.end_date and payment.end_date < date_end: end = payment.end_date else: end = date_end recurrings = rrule.rrule( rrule._rrulestr._freq_map.get(payment.payment_type.rrule), dtstart=start, until=end, ) # Multiply amount with recurrings if payment.amount > 0: sum_year += payment.amount * recurrings.count() else: sum_year_neg += payment.amount * recurrings.count() # Period summaries sum = payments.filter(amount__gt=0).aggregate( Sum('amount')).get('amount__sum') or 0 sum_neg = payments.filter(amount__lt=0).aggregate( Sum('amount')).get('amount__sum') or 0 kwargs.update({ 'employee': employee, 'date_start': date_start, 'date_end': date_end, 'payments': payments, 'payment_extra_fields': ExtraFieldType.objects.filter( model='Payment'), 'sum_year': sum_year, 'sum_year_neg': sum_year + sum_year_neg, 'sum': sum, 'sum_neg': sum_neg, 'currency': CURRENCY, }) return kwargs def form_valid(self, form): self.post_data = self.request.POST if 'download' in self.post_data: result = StringIO.StringIO() html = self.render_to_response(self.get_context_data(form=form)) f = open(os.path.join( os.path.dirname(__file__), './static/payslip/css/payslip.css')) pdf = pisa.CreatePDF(html.render().content, result, default_css=f.read()) f.close() if not pdf.err: return HttpResponse(result.getvalue(), mimetype='application/pdf') return self.render_to_response(self.get_context_data(form=form))