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
Esempio n. 2
0
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
Esempio n. 3
0
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)]
Esempio n. 4
0
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)
Esempio n. 5
0
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))
Esempio n. 6
0
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))
Esempio n. 7
0
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))