コード例 #1
0
    def delete(self, request, *args, **kwargs):
        result_count = self.get_object().result_set.count()
        rationale = request.POST.get('rationale')
        indicator = self.get_object().indicator
        old_indicator_values = indicator.logged_fields
        if result_count and result_count > 0:
            if not rationale:
                return JsonResponse(
                    {
                        "status": "failed",
                        "msg": _("Reason for change is required")
                    },
                    status=400)
            else:
                self.get_object().result_set.all().update(periodic_target=None)
        if not rationale and result_count == 0:
            rationale = _('No reason for change required.')
        self.get_object().delete()
        if indicator.periodictargets.count() == 0:
            indicator.target_frequency = None
            indicator.target_frequency_num_periods = 1
            indicator.target_frequency_start = None
            indicator.target_frequency_custom = None

        indicator.lop_target = indicator.calculated_lop_target
        indicator.save()

        ProgramAuditLog.log_indicator_updated(request.user, indicator,
                                              old_indicator_values,
                                              indicator.logged_fields,
                                              rationale)

        return JsonResponse({"status": "success"})
コード例 #2
0
    def form_valid(self, form, **kwargs):
        indicator = form.save()

        periodic_targets = self.request.POST.get('periodic_targets')

        # Save completed PeriodicTargets to the DB (will be empty u'[]' for LoP)
        if indicator.target_frequency == Indicator.LOP:
            PeriodicTarget.objects.create(
                indicator=indicator,
                period=PeriodicTarget.LOP_PERIOD,
                target=indicator.lop_target,
                create_date=timezone.now(),
            )
        else:
            # now create/update periodic targets
            pt_json = json.loads(periodic_targets)

            normalized_pt_json = self.normalize_periodic_target_client_json_dates(
                pt_json)

            self.validate_periodic_target_json_from_client(
                normalized_pt_json, indicator.program,
                indicator.target_frequency)

            for i, pt in enumerate(normalized_pt_json):
                values = dict(
                    period=pt.get('period', ''),
                    target=pt.get('target', 0),
                    start_date=pt['start_date'],
                    end_date=pt['end_date'],
                )

                PeriodicTarget.objects.create(indicator=indicator,
                                              customsort=i,
                                              create_date=timezone.now(),
                                              **values)

        ProgramAuditLog.log_indicator_created(self.request.user, indicator,
                                              'N/A')

        return JsonResponse({
            'success':
            True,
            'id':
            indicator.id,
            'save_success_msg':
            self._save_success_msg(indicator, created=True)
        })
コード例 #3
0
    def update(self, request, pk=None):
        instance = self.get_object()
        program = instance.program
        role = request.user.tola_user.program_role(program.id)
        if request.user.is_anonymous or role != 'high':
            return HttpResponseRedirect('/')

        # Pull rationale string outside of model serializer, since not part of model
        rationale_str = request.data.get('rationale', '')
        instance = self.get_object()
        old_level_fields = self.get_object().logged_fields

        with transaction.atomic():
            # update Level

            serializer = self.get_serializer(instance,
                                             data=request.data,
                                             partial=False)
            serializer.is_valid(raise_exception=True)

            serializer.save()

            # log changes
            new_level_fields = instance.logged_fields

            # only log changes if indicators attached and not just adding assumption text
            has_indicators = instance.indicator_set.exists()
            diff_fields = set(old_level_fields.items()) - set(
                new_level_fields.items())
            only_added_assumptions = len(
                diff_fields) == 1 and diff_fields.pop() == ('assumptions', '')

            if has_indicators and not only_added_assumptions:
                ProgramAuditLog.log_result_level_updated(
                    self.request.user,
                    instance,
                    old_level_fields,
                    new_level_fields,
                    rationale_str,
                )

        # DRF stuff
        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)
コード例 #4
0
    def form_valid(self, form):
        old_result = Result.objects.get(id=self.kwargs['pk'])

        getDisaggregationLabel = DisaggregationLabel.objects.filter(
            Q(disaggregation_type__indicator__id=old_result.indicator_id)
            | Q(disaggregation_type__standard=True)).distinct()

        # save the form then update manytomany relationships
        old_values = old_result.logged_fields
        new_result = form.save(
        )  # internally this clears disaggregation_value m2m relationships!

        # like the create view, create disaggregation values as all or nothing

        disaggregation_label_ids = set(
            [str(dl.id) for dl in getDisaggregationLabel])
        process_disaggregation = False
        for k, v in self.request.POST.items():
            if k in disaggregation_label_ids and v:
                process_disaggregation = True
                break

        if process_disaggregation:
            for label in getDisaggregationLabel:
                form_id_for_label = str(label.id)
                form_disagg_value = self.request.POST.get(
                    form_id_for_label, '')
                new_result.disaggregation_value.create(
                    disaggregation_label=label, value=form_disagg_value)

        # Result.achieved comes back different from the DB than from the ResultForm
        new_result.refresh_from_db()
        ProgramAuditLog.log_result_updated(self.request.user,
                                           new_result.indicator, old_values,
                                           new_result.logged_fields,
                                           form.cleaned_data.get('rationale'))

        if self.request.is_ajax():
            data = serializers.serialize('json', [self.object])
            return HttpResponse(data)

        messages.success(self.request, _('Success, Data Updated!'))
        redirect_url = new_result.program.program_page_url

        return HttpResponseRedirect(redirect_url)
コード例 #5
0
    def form_valid(self, form):
        indicator = self.request.POST['indicator']
        disaggregation_labels = DisaggregationLabel.objects.filter(
            Q(disaggregation_type__indicator__id=indicator)
            | Q(disaggregation_type__standard=True))

        new = form.save()

        # The following code appears to be accomplishing the following
        # The for submitted contains key/vals for all disaggregation_labels on creation
        # if 1 or more values are present, create values in the DB for all key/vals
        # otherwise leave the disaggregation_value associates completely empty
        # In other words, save key/vals as all or nothing

        disaggregation_label_ids = set(
            [str(dl.id) for dl in disaggregation_labels])
        process_disaggregation = False
        for k, v in self.request.POST.items():
            if k in disaggregation_label_ids and v:
                process_disaggregation = True
                break

        if process_disaggregation is True:
            for label in disaggregation_labels:
                form_id_for_label = str(label.id)
                form_disagg_value = self.request.POST.get(
                    form_id_for_label, '')
                new.disaggregation_value.create(disaggregation_label=label,
                                                value=form_disagg_value)

        ProgramAuditLog.log_result_created(self.request.user, new.indicator,
                                           new)

        if self.request.is_ajax():
            data = {
                'pk': new.pk,
                'url': reverse('result_update', kwargs={'pk': new.pk})
            }
            return JsonResponse(data)

        messages.success(self.request, _('Success, Data Created!'))
        redirect_url = new.indicator.program.program_page_url
        return HttpResponseRedirect(redirect_url)
コード例 #6
0
    def delete(self, request, *args, **kwargs):
        if request.is_ajax():
            if not request.POST.get('rationale'):
                return JsonResponse(
                    {
                        "status": "failed",
                        "msg": _("Reason for change is required")
                    },
                    status=401)

            result = self.get_object()
            result_values = result.logged_fields
            result.delete()
            ProgramAuditLog.log_result_deleted(self.request.user,
                                               result.indicator, result_values,
                                               self.request.POST['rationale'])

            return JsonResponse({"status": "success", "msg": "Result Deleted"})
        else:
            return super(ResultDelete, self).delete(request, *args, **kwargs)
コード例 #7
0
 def delete(self, request, *args, **kwargs):
     if request.is_ajax():
         indicator = self.get_object()
         if not request.POST.get('rationale'):
             # if an indicator has results and no rationale is provided, fail:
             if indicator.result_set.all().count() > 0:
                 return JsonResponse(
                     {
                         "status": "failed",
                         "msg": _("Reason for change is required.")
                     },
                     status=400)
             # otherwise the rationale is this default:
             else:
                 rationale = _(
                     "Reason for change is not required when deleting an indicator with no linked results."
                 )
         else:
             rationale = request.POST.get('rationale')
         indicator_values = indicator.logged_fields
         program_page_url = indicator.program.program_page_url
         indicator.delete()
         ProgramAuditLog.log_indicator_deleted(self.request.user, indicator,
                                               indicator_values, rationale)
         success_message = _("The indicator was successfully deleted.")
         response_context = {'status': 'success'}
         if request.POST.get('redirect'):
             response_context['redirect_url'] = program_page_url
             # message tagged "pnotify" to display a success popup after redirect
             messages.success(request,
                              success_message,
                              extra_tags="pnotify pnotify-success")
         else:
             response_context['msg'] = success_message
         return JsonResponse(response_context)
     else:
         return super(IndicatorDelete, self).delete(request, *args,
                                                    **kwargs)
コード例 #8
0
    def post(self, request, *args, **kwargs):
        indicator = Indicator.objects.get(
            pk=self.kwargs.get('indicator', None))

        rationale = request.POST.get('rationale')
        if not rationale:
            if indicator.result_set.all().exists():
                return JsonResponse(
                    {
                        "status": "failed",
                        "msg": _("Reason for change is required")
                    },
                    status=400)
            else:
                rationale = _('No reason for change required.')

        periodic_targets = PeriodicTarget.objects.filter(indicator=indicator)

        old = indicator.logged_fields

        for pt in periodic_targets:
            pt.result_set.all().update(periodic_target=None)
            pt.delete()

        indicator.target_frequency = None
        indicator.target_frequency_num_periods = 1
        indicator.target_frequency_start = None
        indicator.target_frequency_custom = None
        indicator.lop_target = None  # since lop target is auto-calculated, unset it when PTs are destroyed
        indicator.save()

        ProgramAuditLog.log_indicator_updated(self.request.user, indicator,
                                              old, indicator.logged_fields,
                                              rationale)

        return JsonResponse({"status": "success"})
コード例 #9
0
    def form_valid(self, form, **kwargs):
        periodic_targets = self.request.POST.get('periodic_targets')
        old_indicator = Indicator.objects.get(pk=self.kwargs.get('pk'))
        existing_target_frequency = old_indicator.target_frequency
        new_target_frequency = form.cleaned_data.get('target_frequency')
        lop = form.cleaned_data.get('lop_target')
        rationale = form.cleaned_data.get('rationale')
        old_indicator_values = old_indicator.logged_fields
        prev_level = old_indicator.level  # previous value of "new" level (not to be confused with Indicator.old_level)

        # if existing_target_frequency != new_target_frequency
        # then either existing_target_frequency is None or LoP
        # It shouldn't be anything else as the user should have to delete all targets first

        # Disassociate existing records and delete old PeriodicTargets
        if existing_target_frequency != new_target_frequency:
            PeriodicTarget.objects.filter(indicator=old_indicator).delete()

        # Save completed PeriodicTargets to the DB)
        if new_target_frequency == Indicator.LOP:
            # assume only 1 PT at this point
            lop_pt, created = PeriodicTarget.objects.update_or_create(
                indicator=old_indicator,
                defaults={
                    'target': lop,
                    'period': PeriodicTarget.LOP_PERIOD,
                })

            if created:
                lop_pt.create_date = timezone.now()
                lop_pt.save()

                # Redirect results to new LoP target
                Result.objects.filter(indicator=old_indicator).update(
                    periodic_target=lop_pt)
        else:
            # now create/update periodic targets (will be empty u'[]' for LoP)
            pt_json = json.loads(periodic_targets)

            normalized_pt_json = self.normalize_periodic_target_client_json_dates(
                pt_json)

            self.validate_periodic_target_json_from_client(
                normalized_pt_json, old_indicator.program,
                new_target_frequency)

            generated_pt_ids = []
            for i, pt in enumerate(normalized_pt_json):
                defaults = {
                    'period': pt.get('period', ''),
                    'target': pt.get('target', 0),
                    'customsort': i,
                    'start_date': pt['start_date'],
                    'end_date': pt['end_date'],
                    'edit_date': timezone.now()
                }

                periodic_target, created = PeriodicTarget.objects \
                    .update_or_create(indicator=old_indicator, id=pt['id'], defaults=defaults)

                if created:
                    periodic_target.create_date = timezone.now()
                    periodic_target.save()
                    generated_pt_ids.append(periodic_target.id)

            # Reassign results to newly created PTs
            if generated_pt_ids:
                pts = PeriodicTarget.objects.filter(indicator=old_indicator,
                                                    pk__in=generated_pt_ids)
                for pt in pts:
                    Result.objects.filter(indicator=old_indicator,
                                          date_collected__range=[
                                              pt.start_date, pt.end_date
                                          ]).update(periodic_target=pt)

        # save the indicator form
        form.save()
        self.object.refresh_from_db()

        # Write to audit log if results attached or special case of RF level reassignment
        results_count = Result.objects.filter(indicator=self.object).count()
        if (results_count and results_count > 0
            ) or old_indicator.level_id != self.object.level_id:
            ProgramAuditLog.log_indicator_updated(self.request.user,
                                                  self.object,
                                                  old_indicator_values,
                                                  self.object.logged_fields,
                                                  rationale)

        # refresh the periodic targets form such that pkids of new PeriodicTargets are submitted in the future
        content = render_to_string(
            'indicators/indicatortargets.html', {
                'indicator':
                self.object,
                'periodic_targets':
                PeriodicTarget.objects.filter(indicator=self.object).annotate(
                    num_data=Count('result'))
            })

        return JsonResponse({
            'content':
            content,
            'title_str':
            self._form_title_display_str,
            'subtitle_str':
            self._form_subtitle_display_str,
            'save_success_msg':
            self._save_success_msg(
                self.object,
                created=False,
                level_changed=(self.object.level != prev_level)),
        })
コード例 #10
0
def reportingperiod_update(request, pk):
    program = Program.objects.get(pk=pk)
    old_dates = program.dates_for_logging

    # In some cases the start date input will be disabled and won't come through POST
    reporting_period_start = False
    reporting_period_end = False
    try:
        reporting_period_start = parser.parse(
            request.POST['reporting_period_start'])
    except MultiValueDictKeyError as e:
        pass
    reporting_period_end = parser.parse(request.POST['reporting_period_end'])
    success = True
    failmsg = []
    failfields = []

    if not request.POST.get('rationale') and program.indicator_set.all(
    ).exists():
        success = False
        # Translators: Text of an error message that appears when a user hasn't provided a justification for the change they are making to some data
        failmsg.append(_('Reason for change is required'))

    if reporting_period_start:
        if reporting_period_start.day != 1:
            success = False
            failmsg.append(
                _('Reporting period must start on the first of the month'))
            failfields.append('reporting_period_start')
        elif reporting_period_start.date() == program.reporting_period_start:
            pass
        elif program.has_time_aware_targets:
            success = False
            failmsg.append(
                _('Reporting period start date cannot be changed while time-aware periodic targets are in place'
                  ))
        else:
            program.reporting_period_start = reporting_period_start
    if reporting_period_end:
        next_day = reporting_period_end + timedelta(days=1)
        if next_day.day != 1:
            success = False
            failmsg.append(
                _('Reporting period must end on the last day of the month'))
            failfields.append('reporting_period_end')
        elif reporting_period_end.date() == program.reporting_period_end:
            pass
        elif (program.last_time_aware_indicator_start_date
              and reporting_period_end.date() <
              program.last_time_aware_indicator_start_date):
            success = False
            failmsg.append(
                _('Reporting period must end after the start of the last target period'
                  ))
            failfields.append('reporting_period_end')
        else:
            program.reporting_period_end = reporting_period_end
        if reporting_period_start and reporting_period_start >= reporting_period_end:
            success = False
            failmsg.append(
                _('Reporting period must start before reporting period ends'))
            failfields.append('reporting_period_start')
            failfields.append('reporting_period_end')
    else:
        success = False
        failmsg.append(_('You must select a reporting period end date'))
        failfields.append('reporting_period_end')
    if success:
        program.save()
        ProgramAuditLog.log_program_dates_updated(
            request.user, program, old_dates, program.dates_for_logging,
            request.POST.get('rationale'))

    return JsonResponse(
        {
            'msg': 'success' if success else 'fail',
            'failmsg': failmsg,
            'failfields': failfields,
            'program_id': pk,
            'rptstart': program.reporting_period_start,
            'rptend': program.reporting_period_end,
        },
        status=200 if success else 422)