Refactor time sheet, schedule filter forms to use colander/deform
also add "print employee schedule" feature, didn't realize that was missing
This commit is contained in:
parent
d30e5e2b02
commit
4191e50456
10 changed files with 225 additions and 100 deletions
|
@ -2,7 +2,7 @@
|
|||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
# Copyright © 2010-2018 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -36,28 +36,29 @@ from rattail.db import model, api
|
|||
from rattail.time import localtime, make_utc, get_sunday
|
||||
from rattail.util import pretty_hours, hours_as_decimal
|
||||
|
||||
import formencode as fe
|
||||
from pyramid_simpleform import Form
|
||||
import colander
|
||||
from deform import widget as dfwidget
|
||||
from webhelpers2.html import tags, HTML
|
||||
|
||||
from tailbone import forms
|
||||
from tailbone import forms2 as forms
|
||||
from tailbone.db import Session
|
||||
from tailbone.views import View
|
||||
|
||||
|
||||
class ShiftFilter(fe.Schema):
|
||||
allow_extra_fields = True
|
||||
filter_extra_fields = True
|
||||
store = forms.validators.ValidStore()
|
||||
department = forms.validators.ValidDepartment()
|
||||
date = fe.validators.DateConverter()
|
||||
class ShiftFilter(colander.Schema):
|
||||
|
||||
store = colander.SchemaNode(forms.types.StoreType())
|
||||
|
||||
department = colander.SchemaNode(forms.types.DepartmentType())
|
||||
|
||||
date = colander.SchemaNode(colander.Date())
|
||||
|
||||
|
||||
class EmployeeShiftFilter(fe.Schema):
|
||||
allow_extra_fields = True
|
||||
filter_extra_fields = True
|
||||
employee = forms.validators.ValidEmployee()
|
||||
date = fe.validators.DateConverter()
|
||||
class EmployeeShiftFilter(colander.Schema):
|
||||
|
||||
employee = colander.SchemaNode(forms.types.EmployeeType())
|
||||
|
||||
date = colander.SchemaNode(colander.Date())
|
||||
|
||||
|
||||
class TimeSheetView(View):
|
||||
|
@ -166,47 +167,88 @@ class TimeSheetView(View):
|
|||
Process a "shift filter" form if one was in fact POST'ed. If it was
|
||||
then we store new context in session and redirect to display as normal.
|
||||
"""
|
||||
if self.request.method == 'POST':
|
||||
if form.validate():
|
||||
store = form.data['store']
|
||||
self.request.session['timesheet.{}.store'.format(self.key)] = store.uuid if store else None
|
||||
department = form.data['department']
|
||||
self.request.session['timesheet.{}.department'.format(self.key)] = department.uuid if department else None
|
||||
date = form.data['date']
|
||||
self.request.session['timesheet.{}.date'.format(self.key)] = date.strftime('%m/%d/%Y') if date else None
|
||||
raise self.redirect(self.request.current_route_url())
|
||||
if form.validate(newstyle=True):
|
||||
store = form.validated['store']
|
||||
self.request.session['timesheet.{}.store'.format(self.key)] = store.uuid if store else None
|
||||
department = form.validated['department']
|
||||
self.request.session['timesheet.{}.department'.format(self.key)] = department.uuid if department else None
|
||||
date = form.validated['date']
|
||||
self.request.session['timesheet.{}.date'.format(self.key)] = date.strftime('%m/%d/%Y') if date else None
|
||||
raise self.redirect(self.request.current_route_url())
|
||||
|
||||
def process_employee_filter_form(self, form):
|
||||
"""
|
||||
Process an "employee shift filter" form if one was in fact POST'ed. If it
|
||||
was then we store new context in session and redirect to display as normal.
|
||||
"""
|
||||
if self.request.method == 'POST':
|
||||
if form.validate():
|
||||
employee = form.data['employee']
|
||||
self.request.session['timesheet.{}.employee'.format(self.key)] = employee.uuid if employee else None
|
||||
date = form.data['date']
|
||||
self.request.session['timesheet.{}.employee.date'.format(self.key)] = date.strftime('%m/%d/%Y') if date else None
|
||||
raise self.redirect(self.request.current_route_url())
|
||||
if form.validate(newstyle=True):
|
||||
employee = form.validated['employee']
|
||||
self.request.session['timesheet.{}.employee'.format(self.key)] = employee.uuid if employee else None
|
||||
date = form.validated['date']
|
||||
self.request.session['timesheet.{}.employee.date'.format(self.key)] = date.strftime('%m/%d/%Y') if date else None
|
||||
raise self.redirect(self.request.current_route_url())
|
||||
|
||||
def make_full_filter_form(self, context):
|
||||
form = forms.Form(schema=ShiftFilter(), request=self.request)
|
||||
|
||||
stores = self.get_stores()
|
||||
store_values = [(s.uuid, "{} - {}".format(s.id, s.name)) for s in stores]
|
||||
store_values.insert(0, ('', "(all)"))
|
||||
form.set_widget('store', forms.widgets.PlainSelectWidget(values=store_values))
|
||||
if context['store']:
|
||||
form.set_default('store', context['store'].uuid)
|
||||
|
||||
departments = self.get_departments()
|
||||
department_values = [(d.uuid, d.name) for d in departments]
|
||||
department_values.insert(0, ('', "(all)"))
|
||||
form.set_widget('department', forms.widgets.PlainSelectWidget(values=department_values))
|
||||
if context['department']:
|
||||
form.set_default('department', context['department'].uuid)
|
||||
|
||||
form.set_type('date', 'date_jquery')
|
||||
form.set_default('date', get_sunday(context['date']))
|
||||
return form
|
||||
|
||||
def full(self):
|
||||
"""
|
||||
View a "full" timesheet/schedule, i.e. all employees but filterable by
|
||||
store and/or department.
|
||||
"""
|
||||
form = Form(self.request, schema=ShiftFilter)
|
||||
self.process_filter_form(form)
|
||||
context = self.get_timesheet_context()
|
||||
form = self.make_full_filter_form(context)
|
||||
self.process_filter_form(form)
|
||||
context['form'] = form
|
||||
return self.render_full(**context)
|
||||
|
||||
def make_employee_filter_form(self, context):
|
||||
"""
|
||||
View time sheet for single employee.
|
||||
"""
|
||||
permission_prefix = self.key
|
||||
form = forms.Form(schema=EmployeeShiftFilter(), request=self.request)
|
||||
|
||||
if self.request.has_perm('{}.viewall'.format(permission_prefix)):
|
||||
employee_display = six.text_type(context['employee'] or '')
|
||||
employees_url = self.request.route_url('employees.autocomplete')
|
||||
form.set_widget('employee', forms.widgets.JQueryAutocompleteWidget(
|
||||
field_display=employee_display, service_url=employees_url))
|
||||
if context['employee']:
|
||||
form.set_default('employee', context['employee'].uuid)
|
||||
else:
|
||||
form.set_widget('employee', forms.widgets.ReadonlyWidget())
|
||||
form.set_default('employee', context['employee'].uuid)
|
||||
|
||||
form.set_type('date', 'date_jquery')
|
||||
form.set_default('date', get_sunday(context['date']))
|
||||
return form
|
||||
|
||||
def employee(self):
|
||||
"""
|
||||
View time sheet for single employee.
|
||||
"""
|
||||
form = Form(self.request, schema=EmployeeShiftFilter)
|
||||
self.process_employee_filter_form(form)
|
||||
context = self.get_employee_context()
|
||||
form = self.make_employee_filter_form(context)
|
||||
self.process_employee_filter_form(form)
|
||||
context['form'] = form
|
||||
return self.render_single(**context)
|
||||
|
||||
|
@ -280,7 +322,8 @@ class TimeSheetView(View):
|
|||
|
||||
context = {
|
||||
'page_title': self.get_title_full(),
|
||||
'form': forms.FormRenderer(form) if form else None,
|
||||
'form': form,
|
||||
'dform': form.make_deform_form() if form else None,
|
||||
'employees': employees,
|
||||
'stores': stores,
|
||||
'store_options': store_options,
|
||||
|
@ -326,7 +369,8 @@ class TimeSheetView(View):
|
|||
context = {
|
||||
'single': True,
|
||||
'page_title': "Employee {}".format(self.get_title()),
|
||||
'form': forms.FormRenderer(form) if form else None,
|
||||
'form': form,
|
||||
'dform': form.make_deform_form() if form else None,
|
||||
'employee': employee,
|
||||
'employees': [employee],
|
||||
'week_of': week_of,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
# Copyright © 2010-2018 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -31,10 +31,8 @@ import datetime
|
|||
from rattail.db import model
|
||||
from rattail.time import localtime, make_utc, get_sunday
|
||||
|
||||
from pyramid_simpleform import Form
|
||||
|
||||
from tailbone.db import Session
|
||||
from tailbone.views.shifts.lib import TimeSheetView, ShiftFilter
|
||||
from tailbone.views.shifts.lib import TimeSheetView
|
||||
|
||||
|
||||
class ScheduleView(TimeSheetView):
|
||||
|
@ -61,10 +59,9 @@ class ScheduleView(TimeSheetView):
|
|||
return self.redirect(self.request.route_url('schedule.edit'))
|
||||
|
||||
# okay then, process filters; redirect if any were received
|
||||
form = Form(self.request, schema=ShiftFilter)
|
||||
self.process_filter_form(form)
|
||||
|
||||
context = self.get_timesheet_context()
|
||||
form = self.make_full_filter_form(context)
|
||||
self.process_filter_form(form)
|
||||
|
||||
# okay then, maybe process saved shift data
|
||||
if self.request.method == 'POST':
|
||||
|
@ -199,12 +196,20 @@ class ScheduleView(TimeSheetView):
|
|||
permission='schedule.edit')
|
||||
config.add_tailbone_permission('schedule', 'schedule.edit', "Edit full schedule")
|
||||
|
||||
# print schedule
|
||||
# printing "any" schedule requires this permission
|
||||
config.add_tailbone_permission('schedule', 'schedule.print', "Print schedule")
|
||||
|
||||
# print full schedule
|
||||
config.add_route('schedule.print', '/schedule/print')
|
||||
config.add_view(cls, attr='full', route_name='schedule.print',
|
||||
renderer='/shifts/schedule_print.mako',
|
||||
permission='schedule.print')
|
||||
config.add_tailbone_permission('schedule', 'schedule.print', "Print schedule")
|
||||
|
||||
# print employee schedule
|
||||
config.add_route('schedule.employee.print', '/schedule/employee/print')
|
||||
config.add_view(cls, attr='employee', route_name='schedule.employee.print',
|
||||
renderer='/shifts/schedule_print_employee.mako',
|
||||
permission='schedule.print')
|
||||
|
||||
|
||||
def includeme(config):
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
# Copyright © 2010-2018 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -31,10 +31,8 @@ import datetime
|
|||
from rattail.db import model
|
||||
from rattail.time import make_utc, localtime
|
||||
|
||||
from pyramid_simpleform import Form
|
||||
|
||||
from tailbone.db import Session
|
||||
from tailbone.views.shifts.lib import TimeSheetView as BaseTimeSheetView, EmployeeShiftFilter
|
||||
from tailbone.views.shifts.lib import TimeSheetView as BaseTimeSheetView
|
||||
|
||||
|
||||
class TimeSheetView(BaseTimeSheetView):
|
||||
|
@ -50,10 +48,9 @@ class TimeSheetView(BaseTimeSheetView):
|
|||
View for editing single employee's timesheet
|
||||
"""
|
||||
# process filters; redirect if any were received
|
||||
form = Form(self.request, schema=EmployeeShiftFilter)
|
||||
self.process_employee_filter_form(form)
|
||||
|
||||
context = self.get_employee_context()
|
||||
form = self.make_employee_filter_form(context)
|
||||
self.process_employee_filter_form(form)
|
||||
|
||||
# okay then, maybe process saved shift data
|
||||
if self.request.method == 'POST':
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue