def fields_dict(self): form_types, projects = get_forms() f = dict([ (f.name, f.value) for f in self.fields.filter(updated__isnull=True) ]) if not f.has_key('form_comments'): f['form_comments'] = '' ft = form_types[self.form_code] f = ft.from_database(f) return f
def download_csv(request, code, csvkey=None): if not request.user.is_staff: return redirect(list_projects) form_types, projects = get_forms() form = None for f in form_types.values(): if code == f.code: form = f break if not form: return HttpResponseNotFound('<h1>No form called %s</h1>'% code) # Create the HttpResponse object with the appropriate CSV header. response = HttpResponse(mimetype='text/csv') today = datetime.strftime(datetime.today(), '%Y-%m-%d') # GET THE DATA HERE if csvkey != None: res = form.get_download_data(csvkey) filename = '%s-%s-%s' % (code, csvkey, today) else: res = form.get_download_data() filename = '%s-%s' % (code, today) response['Content-Disposition'] = 'attachment; filename=%s.csv' % filename writer = csv.writer(response) writer.writerows(res) return response
def user_projects(user): """ Return the projects that user has access to. """ from dataentry.forms import get_forms form_types, projects = get_forms() def perm(p): return user.has_perm("%s.data_entry" % p.project) \ or user.has_perm("%s.reconciler" % p.project) \ or user.is_staff return [pr for pr in projects.values() if perm(pr)]
def _try_to_reconcile(form_number, code, user): form_types, projects = get_forms() keyed_forms = Form.objects.filter(form_number=form_number, form_code=code) for f in keyed_forms: mixin(DataEntryForm, form_types[f.form_code]) usrs = [User.objects.get(id = uid) for uid in list(set([ f.user_id for f in keyed_forms ]))] keyed_numbers = [ len([f for f in keyed_forms if f.user_id == u.id ]) for u in usrs ] tf = DataEntryForm() reconcilable = len(filter(lambda n: n > 0, keyed_numbers)) >= tf.min_authors # Check if already has been reconciled rids = [f.reconciled_id for f in keyed_forms] # check if reconciled when it shouldn't be if not reconcilable and len(filter(None, rids)) > 0: unreconcile_forms(form_number, code) for form in keyed_forms: form.fields_dict = form.fields_dict() if reconcilable: done = len(filter(None, rids)) == len(keyed_forms) and len(set(rids)) == 1 good = True goodfields = dict(form_number = form_number) for fn in tf.field_names(): vals = [] for form in keyed_forms: if not form.fields_dict.has_key(fn): continue vals.append(form.fields_dict[fn]) vals = list(set([str(v) for v in vals])) if len(vals) == 1: goodfields[fn] = vals[0] if len(vals) > 1: good = False if good and not done: form = DataEntryForm(goodfields) if form.is_valid() and form.is_really_valid(goodfields): reconcile_forms(user, form_number, form) return True if not good and done: unreconcile_forms(form_number, code)
def reconcile(request, code, form_number): """Reconciliation screen""" form_types, projects = get_forms() referrer = request.META.get('HTTP_REFERER') all_forms = Form.objects.filter(form_number=form_number, form_code=code) usernames = dict([ (u.id, u.first_name or u.username) for u in User.objects.all()]) fts = list(set([f.form_code for f in all_forms])) if len(fts) != 1: assert False, "More than one form type for form %s !" % form_number # Do we have permission... code = fts[0] mixin(DataEntryForm, form_types[code]) if not request.user.has_perm("%s.reconciler" % DataEntryForm.project): return redirect(referrer) postform = None if request.method == 'POST': postform = DataEntryForm(request.POST) # postform.clean = postform.reconcile_clean if postform.is_valid() and postform.is_really_valid(): reconcile_forms(request.user, form_number, postform) referrer = request.POST['referrer'] if request.POST.has_key('import'): returnto = postform.importurl(form_number) elif referrer and referrer != 'None': returnto = referrer else: returnto = reverse('dataentry.views.show_forms', kwargs=dict(project = postform.project)) returnto = returnto + '#' + postform.cleaned_data['form_number'] return redirect(returnto) else: logging.debug(postform.errors) tf = DataEntryForm() for form in all_forms: form.fields_dict = form.fields_dict() form.groomed = {} tf.groom_all(form.groomed, form.fields_dict) fields = Field.objects.filter(form=form) form.fields_name_dict = {} for field in fields: if not field.name in form.fields_name_dict: form.fields_name_dict[field.name] = [] form.fields_name_dict[field.name].append(field) f = dict(form_number = form_number) info = dict() for fn in tf.field_names(): vals = [] groomed = False for form in all_forms: if not form.fields_dict.has_key(fn): continue vals.append(form.fields_dict[fn]) if form.groomed.has_key(fn): groomed = True def cmp_dates(a,b): return cmp(b.date_entered, a.date_entered) history = list( reduce( set.union, [set(frm.fields_name_dict[fn] if fn in frm.fields_name_dict else []) for frm in all_forms] ) ) history.sort(cmp_dates) history = [ dict( value = fi.value, user = usernames[fi.user_id], date_entered = fi.date_entered.strftime('%d %b %Y %H:%M'), ) for fi in history ] history = dedupe(history, lambda h: "**".join(h.values())) history_groomed = (len(list(set([ h['value'] for h in history ]))) > 1 and all_forms[0].reconciled != None) info[fn] = dict( groomed = groomed and len(list(set(vals))) == 1, vals = list(set([str(v) for v in vals])), frms = dict([ (form.id, form.fields_dict.get(fn,"")) for form in all_forms]), history = history, history_groomed = history_groomed, ) if len(set([str(v) for v in vals])) == 1: f[fn] = vals[0] else: f[fn] = '' # load up the comments comments = [] for fm in all_forms: comments.append(dict( comment = fm.comment, user = fm.user, )) if postform: form = postform errors = postform.errors else: form = DataEntryForm(f) form.is_really_valid(f) errors = form.errors importable = hasattr(form_types[code], 'imported_forms') and (code, form_number) not in form_types[code].imported_forms() extra = None if hasattr(form_types[code], 'ft_annotate'): extra = form.ft_annotate(form_number) return render_to_response("dataentry/reconcile.html", dict( form_number = form_number, forms = all_forms, form = form, reconciled = all_forms[0].reconciled, reconciling = True, comments = comments, info = simplejson.dumps(info), errors = simplejson.dumps(errors), referrer = referrer, importable = importable, menuname = 'dataentry', extra = extra, ), context_instance=RequestContext(request))
def form(request, code, form_id): form_types, projects = get_forms() if not code in form_types.keys(): return HttpResponseNotFound('<h1>No form type called %s</h1>' % code) all_forms = [] mixin(DataEntryForm, form_types[code]) if not request.user.has_perm("%s.data_entry" % DataEntryForm.project) and not request.user.is_staff: return redirect(list_projects) form_number = None secondtime = False groomed = dict() thisuser = None if request.method == 'POST': form = DataEntryForm(request.POST) if request.POST.has_key('delete'): delete_form(request.user, form_id) return redirect(reverse('dataentry.views.show_forms', kwargs=dict(project = form.project))) if form.is_valid(): # If the user is trying to enter, reconcile and import in # one step, validation and redirects are different. reconciler = request.user.has_perm("%s.reconciler" % DataEntryForm.project) or request.user.is_staff importing = reconciler and request.POST.has_key('import') and hasattr(form, 'importurl') if importing: validation_stage = 'reconcile' else: validation_stage = 'entry' # Do the groom check thing here... valid = False secondtime = True form_number = form.cleaned_data['form_number'] if not request.POST.has_key('secondtime') : form.groom_all(groomed) fd = form.cleaned_data if groomed: form = DataEntryForm(fd) valid = form.is_really_valid(fd, stage=validation_stage) else: valid = form.is_really_valid(stage=validation_stage) if not valid: secondtime = False logging.debug(form.errors) elif not groomed: if form_id: f = update_form(request.user, form_id, form) else: f = create_form(request.user, form, form.generate_form_number) success = _try_to_reconcile(f.form_number, f.form_code, request.user) if importing: if success: return redirect(form.importurl(f.form_number)) if reconciler: return redirect(reverse('dataentry.views.reconcile', kwargs=dict( code=f.form_code, form_number=f.form_number))) return redirect(reverse('dataentry.views.show_forms', kwargs=dict(project = form.project))) else: logging.debug(form.errors) else: if form_id: f = load_form(form_id) form_number = f['form_number'] all_forms = Form.objects.filter(form_number=form_number, form_code=code) for form in all_forms: if form.id == int(form_id): thisuser = form.user form.matched = True form = DataEntryForm(f) else: form = DataEntryForm() if form.generate_form_number: # Fill form_number with garbage for now; fix it in create_form f = {'form_number': 100000000 + int('0x' + request.session.session_key[11:17], 16)} form = DataEntryForm(f) allow_rename = True if not form_id: importable = hasattr(form_types[code], 'importurl') elif hasattr(form_types[code], 'imported_forms') and form_number != None: importable = (code, form_number) not in form_types[code].imported_forms() # Changing the form_number of a previously imported form # causes bad things to happen, don't allow it until this is # fixed. allow_rename = importable else: importable = False extra = None if form_id and hasattr(form_types[code], 'ft_annotate'): extra = form.ft_annotate(form_number) fts_q = reduce(lambda x,y: x|y, [Q(form_code=ft.code) for ft in form_types.values() if ft.project == form.project]) keyed_forms = Form.objects.filter(Q(user = request.user) & fts_q) nforms = keyed_forms.count() enable_save_button = request.user.is_staff or not form_id or thisuser == request.user info = dict() for fn in form.field_names() + ['form_comments']: info[fn] = dict() info[fn]['desc'] = ", ".join([ gr['description'] for gr in form.grooming_rules if fn in gr['fields']]) if groomed.has_key(fn): info[fn]['groomed'] = 1 return render_to_response('dataentry/form.html', dict( enable_save_button = enable_save_button, allow_rename = allow_rename, secondtime = secondtime, info = info, errors = simplejson.dumps(form.errors), form = form, form_id = form_id, all_forms = all_forms, number_of_forms = nforms, project_name = projects[form.project].name, importable = importable, menuname = 'dataentry', extra = extra, ), context_instance=RequestContext(request))
def show_forms(request, project, year=None): """View all forms already keyed by user.""" form_types, projects = get_forms() if not projects.has_key(project): return HttpResponseNotFound('<h1>No project called %s</h1>'% project) if not request.user.has_perm("%s.data_entry" % project) and not request.user.is_staff: return redirect(list_projects) fts_q = reduce(lambda x,y: x|y, [Q(form_code=ft.code) for ft in form_types.values() if ft.project == project]) if year: fts_q = fts_q & Q(date_entered__year = year) if request.user.has_perm('%s.reconciler' % project): all_forms = Form.objects.filter(fts_q) else: all_forms = Form.objects.filter(Q(user = request.user) & fts_q) nforms = all_forms.count() usrs = [User.objects.get(id = uid) for uid in list(set([ f.user_id for f in all_forms ]))] def get_forms1(fn): keyed_forms = [f for f in all_forms if f.form_number == fn ] for f in keyed_forms: mixin(f.__class__, form_types[f.form_code]) return [ [ f for f in keyed_forms if f.user_id == u.id ] for u in usrs ] def get_status(fn): keyed = [f for f in all_forms if f.form_number == fn ] if keyed[0].reconciled_id: return 'reconciled' elif len(keyed) > 1: return 'not-reconciled' else: return 'single' frms = [ dict( form_number = fn, form_code = form_code, status = get_status(fn), keyed_forms = get_forms1(fn), form_type = form_types[form_code], modified = max([ f.date_modified for f in all_forms if f.form_number == fn ]) ) for (form_code, fn) in sorted( list(set([(f.form_code, f.form_number) for f in all_forms])), key = lambda a: [a[0]] + [int(k) for k in filter(None, re.split('\D+', a[1]))] ) ] imported = {} for ft in form_types: if hasattr(form_types[ft], 'imported_forms'): imported[ft] = form_types[ft].imported_forms() if imported != {}: # Add 'imported' status for f in frms: if f['form_code'] in imported: if hasattr(form_types[f['form_code']], 'importurl'): f['importurl'] = form_types[f['form_code']].importurl(f['form_number']) if hasattr(form_types[f['form_code']], 'import_html'): f['import_html'] = form_types[f['form_code']].import_html(f['form_number']) if (f['form_code'], f['form_number']) in imported[f['form_code']]: f['status'] = 'imported' # Sort form numbers by status & date status_order = ['single', 'not-reconciled', 'reconciled', 'imported'] frms = sorted(frms, key=lambda f: f['modified'], reverse=True) frms = sorted(frms, key=lambda f: status_order.index(f['status'])) counts = dict() for ft in form_types.values(): if ft.project != project: continue fmt = counts.setdefault(ft.code, dict()) totals = counts.setdefault('totals', dict()) for f in all_forms: if f.form_code != ft.code: continue fdf = fmt.setdefault(f.form_number, dict(keyed = 0, reconciled = 0)) tdf = totals.setdefault(f.form_number, dict(keyed = 0, reconciled = 0)) fdf['keyed'] = fdf['keyed'] + 1 tdf['keyed'] = tdf['keyed'] + 1 if f.reconciled_id: fdf['reconciled'] = fdf['reconciled'] + 1 if f.reconciled_id: tdf['reconciled'] = tdf['reconciled'] + 1 summary = [dict( code = ft.code, blurb = ft.blurb, keyed = len(counts[ft.code].keys()) or '', double = len([v for v in counts[ft.code].values() if v['keyed'] > 1]) or '', reconciled = len([v for v in counts[ft.code].values() if v['reconciled'] > 0]) or '', ) for ft in form_types.values() if ft.project == project] \ + [ dict( code = "Total", blurb = "", keyed = len(counts['totals'].keys()) or '', double = len([v for v in counts['totals'].values() if v['keyed'] > 1]) or '', reconciled = len([v for v in counts['totals'].values() if v['reconciled'] > 0]) or '', )] return render_to_response("dataentry/forms.html", dict( project_name = projects[project].name, usrs = usrs, frms = frms, number_of_forms = nforms, summary = summary, form_types = form_types, menuname = 'dataentry', ), context_instance=RequestContext(request))