def calculated_rating(issuer_type_id, rating_decision_obj): """Calculate the rating based on scores using pycreditrating.""" internal_score_obj = InternalScoreData.objects.filter( rating_decision=rating_decision_obj ).all() return PCRRating(generate_rating_dict( int(issuer_type_id), internal_score_obj, 'decided'),)
def update_long_term_rating(sender, instance, **kwargs): """Update the long term rating when a subscore is updated.""" rating_decision_obj = instance.rating_decision issuer_type_id = rating_decision_obj.issuer.issuer_type.id internal_score_obj = InternalScoreData.objects.filter( rating_decision=rating_decision_obj).all() try: # Return indicative ratings based on score input proposed_rating = PCRRating( generate_rating_dict(issuer_type_id, internal_score_obj, 'proposed')) rating_decision_obj.proposed_lt = RATING_LONG_TERM[ proposed_rating.issuer_assessment.upper()] # Return decided ratings based on score input decided_rating = PCRRating( generate_rating_dict(issuer_type_id, internal_score_obj, 'decided')) rating_decision_obj.decided_lt = RATING_LONG_TERM[ decided_rating.issuer_assessment.upper()] rating_decision_obj.primary_analyst = \ instance.rating_decision.issuer.analyst.primary_analyst rating_decision_obj.secondary_analyst = \ instance.rating_decision.issuer.analyst.secondary_analyst rating_decision_obj.save() except: # noqa E722 pass
except Exception as err: traceback.print_tb(err.__traceback__) # Set assessment per assessment job for a in AssessmentJob.objects.all(): internal_score_obj = AssessmentSubscoreData.objects.filter( assessment_id=a.id).all() # Issuer type id is used to create the rating below issuer_type_id = a.issuer.issuer_type.id try: # Return indicative ratings based on score input rating_dict = generate_rating_dict(issuer_type_id, internal_score_obj, 'decided', version=2) proposed_rating = PCRRating(rating_dict) c_assessment = RATING_LONG_TERM[proposed_rating.issuer_rating.upper()] except Exception as e: print('{} due to {}'.format(a, e)) from pprint import pprint pprint(rating_dict) c_assessment = None try:
def view_subscore_list(request, issuer_type_pk): """View a list of issuers, their latest rating decision and respective subscores.""" output_list = [] issuers = Issuer.objects.filter( rating_decision_issuer__is_current=True, issuer_type_id=issuer_type_pk ).order_by( 'gics_sub_industry__industry__industry_group__sector', 'address__country').select_related( 'gics_sub_industry__industry__industry_group__sector').\ select_related('issuer_type').\ select_related('address__country') for i in issuers: issuer_data = {} issuer_data['current_rating'] = {} issuer_data['issuer'] = i # Current rating decision rating_decision_obj = RatingDecision.objects.select_related( 'rating_type').\ get( is_current=True, issuer=i, ) issuer_data['current_rating']['data'] = rating_decision_obj # Get all subscores score_data = InternalScoreData.objects.filter( rating_decision__is_current=1, rating_decision__issuer=i).select_related( 'subfactor') # All scores issuer_data['current_rating']['score_data'] = {} for x in score_data: issuer_data['current_rating']['score_data'][ x.subfactor.name] = { 'score_display': x.get_decided_score_display(), 'score_value': x.decided_score, 'weight': x.weight, 'adjustment_value': x.decided_notch_adjustment, } # Calculated rating decided_calculated_rating = PCRRating( generate_rating_dict( i.issuer_type.description, score_data, 'decided')) issuer_data['current_rating'][ 'calculated_rating'] = decided_calculated_rating output_list.append(issuer_data) context = { 'issuer_list': output_list, 'issuer_type': issuer_type_pk, } return render( request, 'sector/index.html', context )
def generate_rating_job_data(issuer_obj, gui_controls, current_rating_obj, auth, request, rating_decision_id=None): """ Returns data for a specific rating job if rating_decision_id is specified, else takes last one :return: Dict content for rating_job """ try: # Show an existing rating decision if rating_decision_id: rating_decision_obj = RatingDecision.objects. \ select_related('rating_type').select_related('chair'). \ get(pk=rating_decision_id) else: rating_decision_obj = RatingDecision.objects.filter( issuer=issuer_obj, date_time_deleted__isnull=True, date_time_published__isnull=True).select_related( 'rating_type').select_related('chair')[0] # We need to be able to amend the error list with some custom errors error_messages = list(rating_decision_obj.error_messages) no_committee_members = JobMember.objects.confirmed_members().filter( rating_decision=rating_decision_obj).count() if no_committee_members < 2: error_messages.append('Add more voting members, or make ' 'sure they confirm their attendance.') # Gui controls gui_controls['progress_bar'] = {} gui_controls['progress_bar'].update({'enable': True}) gui_controls['progress_bar'].update({'ongoing_surveillance': False}) # Store the current step in a shorter variable s = rating_decision_obj.get_process_step_display() if s == 'pre_committee': gui_controls['progress_bar'].update({'setup_done': True}) elif s == 'analytical_phase': gui_controls['progress_bar'].update({'setup_done': True}) gui_controls['progress_bar'].update({'pre_committee_done': True}) elif s == 'post_committee': gui_controls['progress_bar'].update({'setup_done': True}) gui_controls['progress_bar'].update({'pre_committee_done': True}) gui_controls['progress_bar'].update( {'analytical_phase_done': True}) elif s == 'editor_phase': gui_controls['progress_bar'].update({'setup_done': True}) gui_controls['progress_bar'].update({'pre_committee_done': True}) gui_controls['progress_bar'].update( {'analytical_phase_done': True}) gui_controls['progress_bar'].update({'post_committee_done': True}) elif s == 'issuer_confirmation_phase': gui_controls['progress_bar'].update({'setup_done': True}) gui_controls['progress_bar'].update({'pre_committee_done': True}) gui_controls['progress_bar'].update( {'analytical_phase_done': True}) gui_controls['progress_bar'].update({'post_committee_done': True}) gui_controls['progress_bar'].update({'editing_done': True}) elif s == 'analyst_final_approval_phase': gui_controls['progress_bar'].update({'setup_done': True}) gui_controls['progress_bar'].update({'pre_committee_done': True}) gui_controls['progress_bar'].update( {'analytical_phase_done': True}) gui_controls['progress_bar'].update({'post_committee_done': True}) gui_controls['progress_bar'].update({'editing_done': True}) gui_controls['progress_bar'].update( {'issuer_confirmation_done': True}) elif s == 'chair_final_approval_phase': gui_controls['progress_bar'].update({'setup_done': True}) gui_controls['progress_bar'].update({'pre_committee_done': True}) gui_controls['progress_bar'].update( {'analytical_phase_done': True}) gui_controls['progress_bar'].update({'post_committee_done': True}) gui_controls['progress_bar'].update({'editing_done': True}) gui_controls['progress_bar'].update( {'issuer_confirmation_done': True}) gui_controls['progress_bar'].update( {'analyst_final_approval_done': True}) elif s == 'publishing_phase' or s == 'publishing_phase_done': gui_controls['progress_bar'].update({'setup_done': True}) gui_controls['progress_bar'].update({'pre_committee_done': True}) gui_controls['progress_bar'].update( {'analytical_phase_done': True}) gui_controls['progress_bar'].update({'post_committee_done': True}) gui_controls['progress_bar'].update({'editing_done': True}) gui_controls['progress_bar'].update( {'issuer_confirmation_done': True}) gui_controls['progress_bar'].update( {'analyst_final_approval_done': True}) gui_controls['progress_bar'].update( {'chair_final_approval_done': True}) # Override settings on some of the steps if s == 'pre_committee' or s == 'chair_final_approval_phase': # Only chair may edit here if request.user == rating_decision_obj.chair: auth['issuer']['rating_job']['edit'] = True else: auth['issuer']['rating_job']['edit'] = False ##################################################### # Subscores ##################################################### subscores = {} internal_score_obj = InternalScoreData.objects.filter( rating_decision=rating_decision_obj).all().order_by( 'subfactor__sort_order').select_related('subfactor__factor') internal_score_obj_list = list(internal_score_obj) if issuer_obj.issuer_type.description == 1 or \ issuer_obj.issuer_type.description == 3: subscores['business_risk'] = list( filter(lambda i: i.subfactor.factor.name == 'Business risk', internal_score_obj_list)) subscores['financial_risk_assessment'] = list( filter(lambda i: i.subfactor.factor.name == 'Financial risk', internal_score_obj_list)) elif issuer_obj.issuer_type.description == 2: subscores['operating_environment'] = list( filter( lambda i: i.subfactor.factor.name == 'Operating environment', internal_score_obj_list)) subscores['risk_appetite'] = list( filter(lambda i: i.subfactor.factor.name == 'Risk appetite', internal_score_obj_list)) subscores['competitive_position'] = list( filter( lambda i: i.subfactor.factor.name == 'Competitive position', internal_score_obj_list)) subscores['performance_indicators'] = list( filter( lambda i: i.subfactor.factor.name == 'Performance indicators', internal_score_obj_list)) subscores['adjustment_factor'] = list( filter(lambda i: i.subfactor.factor.name == 'Adjustment factors', internal_score_obj_list)) subscores['support_factor'] = list( filter(lambda i: i.subfactor.factor.name == 'Support factors', internal_score_obj_list)) ##################################################### # Existing issue subscore data ##################################################### # Issue subscores['issue'] = RatingDecisionIssue.objects.filter( rating_decision=rating_decision_obj).all() ##################################################### # Committee members ##################################################### try: rating_committee_member_obj = JobMember.objects.filter( rating_decision=rating_decision_obj, group_id=1).select_related('member'). \ select_related('role'). \ select_related('group') except: # noqa E722 rating_committee_member_obj = False ##################################################### # Editor ##################################################### try: if rating_decision_obj: editor_obj = JobMember.objects.get( rating_decision=rating_decision_obj, group_id=2) else: editor_obj = False except: # noqa E722 editor_obj = False ##################################################### # Insiders linked to rating job ##################################################### try: rating_job_insiders_obj = \ RatingDecisionInsiderLink.objects.filter( rating_decision=rating_decision_obj).select_related( 'insider') except: # noqa E722 rating_job_insiders_obj = False ##################################################### # Information about press release ##################################################### try: if rating_decision_obj: press_release_obj = PressRelease.objects.get( rating_decision=rating_decision_obj) if not press_release_obj.is_valid and \ rating_decision_obj.get_process_step_display() == \ 'analyst_final_approval_phase': error_messages.append('Fill in all fields of the ' 'press release.') else: press_release_obj = False except: # noqa E722 press_release_obj = False ##################################################### # Questions ##################################################### question_obj = ControlQuestion.objects.filter( rating_decision=rating_decision_obj).select_related( 'question').select_related('question__stage') control_questions = { 'analyst_final_approval': question_obj.filter(question__stage=3), 'chair_final_approval': question_obj.filter(question__stage=4), 'publishing': question_obj.filter(question__stage=5) } ##################################################### # Information about the process steps ##################################################### try: if rating_decision_obj: process_obj = Process.objects.get( rating_decision=rating_decision_obj) else: process_obj = False except: # noqa E722 process_obj = False ##################################################### # Methodology ##################################################### # Insert links between decision and methodology if rating_decision_obj: methodology_link_obj = RatingDecisionMethodologyLink.objects.\ filter(rating_decision=rating_decision_obj).select_related( 'methodology__category') if not methodology_link_obj: if issuer_obj.issuer_type.description == 1 or \ issuer_obj.issuer_type.description == 3: # Corporate # Always pick latest methodology_id = 1 else: # Financial methodology_id = 2 try: methodology_obj = Methodology.objects.order_by( 'category__name', '-date_decision').filter( date_deleted__isnull=True, category__id=methodology_id).distinct( 'category__name')[0] RatingDecisionMethodologyLink.objects.create( rating_decision=rating_decision_obj, methodology=methodology_obj) # Rating principles methodology_rating_criteria_obj = Methodology.objects.\ order_by('category__name', '-date_decision').filter( date_deleted__isnull=True, category__id=3).distinct('category__name')[0] RatingDecisionMethodologyLink.objects.create( rating_decision=rating_decision_obj, methodology=methodology_rating_criteria_obj) methodology_link_obj = RatingDecisionMethodologyLink. \ objects.filter(rating_decision=rating_decision_obj) except: # noqa E722 methodology_link_obj = [] else: methodology_link_obj = [] ##################################################### # Calculated ratings ##################################################### # Decided rating try: decided_calculated_rating = PCRRating( generate_rating_dict(issuer_obj.issuer_type.description, internal_score_obj_list, 'decided')) except: # noqa E722 decided_calculated_rating = False # Proposed rating try: proposed_calculated_rating = PCRRating( generate_rating_dict(issuer_obj.issuer_type.description, internal_score_obj_list, 'proposed')) except: # noqa E722 proposed_calculated_rating = False if rating_decision_obj.process_step >= 3: if not proposed_calculated_rating.weight_check \ or not decided_calculated_rating.weight_check: error_messages.append( 'The impact weights do not sum to 100%, but {:.1%}.'. format(proposed_calculated_rating.weight)) else: if proposed_calculated_rating.issuer_rating is None \ or decided_calculated_rating.issuer_rating is None: error_messages.append('Not all sub scores are set.') onboarding_obj = OnboardingProcess.objects.get(issuer=issuer_obj) if onboarding_obj.instrument_rating: if len(subscores['issue']) == 0: error_messages.append('The issues has requested issue ' 'ratings, add ratings for seniority ' 'levels.') if len(subscores['issue']) > 0 and \ rating_decision_obj.process_step >= 4: _e_list = [] for issue in subscores['issue']: if issue.decided_lt is None: _e_list.append(1) if sum(_e_list) > 0: error_messages.append('Assign ratings for seniority ' 'levels.') ##################################################### # Existing rating decision score data ##################################################### try: show_existing_scores = rating_decision_obj.previous_rating existing_scores = {} if show_existing_scores: internal_score_existing_obj = InternalScoreData.objects.filter( rating_decision=show_existing_scores) if internal_score_existing_obj: internal_score_existing_obj_values = \ internal_score_existing_obj.\ values('subfactor_id', 'decided_notch_adjustment', 'decided_score') for i in internal_score_existing_obj_values: decided_score = i['decided_score'] decided_notch = i['decided_notch_adjustment'] try: decided_score = RATING_INDICATIVE_REVERSE[ decided_score].lower() + \ ' (' + str(decided_score) + ')' except KeyError: decided_score = None existing_scores[i['subfactor_id']] = { 'decided_notch_adjustment': decided_notch, 'decided_score': decided_score } # Return existing rating try: if internal_score_existing_obj: existing_calculated_rating = PCRRating( generate_rating_dict( issuer_obj.issuer_type.description, list(internal_score_existing_obj), 'decided')) else: existing_calculated_rating = 'n/a' except: # noqa E722 existing_calculated_rating = 'n/a' except: # noqa E722 existing_calculated_rating = 'n/a' existing_scores = False ##################################################### # Previews of images ##################################################### tmp_file_name_thumb = None tmp_external_file_name_thumb = None try: if s == 'editor_phase' or s == 'chair_final_approval_phase' or \ s == 'publishing_phase': # Define file paths tmp_file_name = 'dl_{}.pdf'.format(uuid.uuid4()) fp = djangoSettings.BASE_DIR + '/tmp/' target_file = fp + tmp_file_name # Get ID# of report if s == 'chair_final_approval_phase' or \ s == 'publishing_phase': tmp_external_file_name_thumb = tmp_file_name + '_thumb.jpg' # Display the report that will be published externally document = get_public_external_report(rating_decision_obj) target_file_tmp = fp + tmp_external_file_name_thumb else: tmp_file_name_thumb = tmp_file_name + '_thumb.jpg' # Setup file names target_file_tmp = fp + tmp_file_name_thumb document = get_public_report(rating_decision_obj) # Point to file location at AWS filepath = AWS_ANALYTICAL_MEDIA_LOCATION + '/' + str( document.upload) # Download file from AWS S3 download_file(filepath, target_file) # Use MagicImage to convert pdf to img params = ['convert', target_file + '[0]', target_file_tmp] subprocess.check_call(params) # Delete the files in the future to avoid race condition later = datetime.datetime.utcnow() + timedelta(minutes=3) delete_files_task.apply_async([target_file_tmp, target_file], eta=later) except Exception as e: logger.error(e) except: # noqa E722 existing_calculated_rating = 'n/a' existing_scores = False tmp_file_name_thumb = None tmp_external_file_name_thumb = None proposed_calculated_rating = False decided_calculated_rating = False methodology_link_obj = [] process_obj = False press_release_obj = False rating_job_insiders_obj = False rating_decision_obj = False editor_obj = False subscores = False control_questions = False show_existing_scores = False rating_committee_member_obj = False error_messages = [] context_data = { 'proposed_rating': proposed_calculated_rating, 'decided_rating': decided_calculated_rating, 'rating_job_insiders': rating_job_insiders_obj, 'process': process_obj, 'committee_members': rating_committee_member_obj, 'editors': editor_obj, 'methodologies': methodology_link_obj, 'subscores': subscores, 'rating_decision': rating_decision_obj, 'press_release': press_release_obj, 'control_questions': control_questions, 'preview': { 'internal_external_pdf': tmp_file_name_thumb, 'external_pdf': tmp_external_file_name_thumb, }, 'existing': { 'scores': existing_scores, 'calc_rating': existing_calculated_rating, 'decision': current_rating_obj, }, } return_dict = { 'rating_decision_obj': rating_decision_obj, 'show_existing_scores': show_existing_scores, 'context_data': context_data, 'error_messages': error_messages, } return return_dict
def form_valid(self, form): """Custom form_valid method.""" # Save the score immediately so it's available below obj = form.save(commit=False) obj.save() subscore_data_list = [] for key, value in sorted(form.cleaned_data.items()): try: a = key.split('_')[0] b = key.split('_')[1] obj = AssessmentSubscoreData.objects.get(pk=b) subscore_data_list.append(obj.assessment.id) if a == 's': # n/a is represented as empty value if value == '': value = None obj.decided_score = value elif a == 'n': obj.decided_notch_adjustment = value elif a == 'w': # 0% is represented as empty value if value == '': value = None obj.weight = value obj.save() except (IndexError, ValueError): pass # Loop through all subscores that were affected by the change # and update the calculated rating for each # Add the clicked issuer subscore to the list to loop through subscore_data_list.append(form.instance.assessment.id) for d in AssessmentJob.objects.filter(id__in=subscore_data_list): # Store the current assessment level, as we need to get the # relative value of each issue level # Has to be initialized here, before the rating is updated issue_assessment_dict = get_issues_relative_level(d) internal_score_obj = AssessmentSubscoreData.objects.filter( assessment_id=d.id ).all() try: # Issuer type id is used to create the rating below issuer_type_id = d.issuer.issuer_type.id # Return indicative ratings based on score input proposed_rating = PCRRating(generate_rating_dict( issuer_type_id, internal_score_obj, 'decided', version=2) ) # Assign and save the assessment d.assessment_lt = RATING_LONG_TERM[ proposed_rating.issuer_rating] for key in issue_assessment_dict: v = SeniorityLevelAssessment.objects.get(pk=key) v.decided_lt = d.assessment_lt - issue_assessment_dict[key] v.save() except Exception: d.assessment_lt = None d.save() messages.add_message( self.request, messages.INFO, 'Saved sub factor assessments.') return super(EditSubfactorPeerView, self).form_valid(form)
def list_assessment(request, type): """View a list of issuers, their latest rating decision and respective sub scores.""" output_list = [] if int(type) == 1: include_types = [1, 3] template = 'issuer/assessment/list_all_v2.html' else: include_types = [2] template = 'issuer/assessment/list_all_v2.html' issuers = Issuer.objects.list_all_assessment( include_types ) # Create a dict of all users to reduce db hits user_dict = {} users = User.objects.all() for u in users: user_dict[u.id] = { 'short_name': u.first_name[:1] + u.last_name[:1], 'name': u.first_name + ' ' + u.last_name } ##################################################### # Authentication ##################################################### group_list = request.user.groups.all().values('name') user_groups = [] for group in group_list: user_groups.append(group['name']) for i in issuers: # Create dict to store data for this issuer issuer_data = {} # Version for the dict sent to pycreditrating version = 2 # Store information about the issuer issuer_data['issuer'] = i issuer_data['user_data'] = {} issuer_data['user_data'] = user_dict[i.initiated_by] if i.rating_id: score_data = InternalScoreData.objects.filter( rating_decision_id=i.rating_id, ).select_related('subfactor') elif i.progress_id: score_data = AssessmentSubscoreData.objects.filter( assessment_id=i.progress_id, ).select_related('subfactor').\ select_related('assessment__highestlowest') else: score_data = AssessmentSubscoreData.objects.filter( assessment_id=i.current_id, ).select_related('subfactor').\ select_related('assessment__highestlowest') # All scores issuer_data['score_data'] = {} for x in score_data: # For backwards compatibility if x.subfactor.id == 5: version = 1 issuer_data['score_data'][ x.subfactor.name] = { 'score_display': x.get_decided_score_display(), 'score_value': x.decided_score, 'weight': x.weight, 'adjustment_value': x.decided_notch_adjustment, 'subfactor': x.subfactor.name, 'id': x.id, } # Calculated rating calculated_rating = PCRRating( generate_rating_dict( i.i_id, score_data, 'decided', version=version, ) ) issuer_data['calculated_rating'] = calculated_rating # Ratings per issuer seniority level if i.rating_id: seniority_level = RatingDecisionIssue.objects.filter( rating_decision_id=i.rating_id, ).select_related('seniority') elif i.progress_id: seniority_level = SeniorityLevelAssessment.objects.filter( assessment_id=i.progress_id, ).select_related('seniority') else: seniority_level = SeniorityLevelAssessment.objects.filter( assessment_id=i.current_id, ).select_related('seniority') issuer_data['seniority_level'] = {} for x in seniority_level: try: relative_notch = RATING_LONG_TERM[ calculated_rating.issuer_rating] - \ x.decided_lt except (TypeError, KeyError): relative_notch = 'n/a' issuer_data['seniority_level'][ x.seniority.name] = { 'relative_score': relative_notch, 'score_display': x.get_decided_lt_display() } # The user that created the assessment must not be allowed to # edit the assessment issuer_data['misc'] = {} # If the assessment is in final approval phase, we want to make sure # the approval is not made by the same user that initiated the # assessment if i.progress_process_step == 2: if request.user.id == i.progress_initiated_by_id: issuer_data['misc']['allow_edit'] = False else: issuer_data['misc']['allow_edit'] = True else: # There is no assessment in progress, while one was made # in the past if i.current_id and not i.progress_id: issuer_data['misc']['allow_edit'] = False else: if i.rating_id: issuer_data['misc']['allow_edit'] = False else: issuer_data['misc']['allow_edit'] = True if 'Analyst' not in user_groups: issuer_data['misc']['allow_edit'] = False output_list.append(issuer_data) context = { 'object_list': output_list, 'type': int(type), } return render( request, template, context )
def form_valid(self, form): """Custom form_valid method.""" d = form.save(commit=False) issue_seniority_lvl = {} for key, value in sorted(form.cleaned_data.items()): try: a = key.split('_')[0] b = key.split('_')[1] if a == 'i': issue_seniority_lvl[int(b)] = int(value) else: obj = AssessmentSubscoreData.objects.get(pk=b) if a == 's': # n/a is represented as empty value if value == '': value = None obj.decided_score = value elif a == 'n': obj.decided_notch_adjustment = value elif a == 'w': # 0% is represented as empty value if value == '': value = None obj.weight = value obj.save() except (IndexError, ValueError): pass try: internal_score_obj = AssessmentSubscoreData.objects.filter( assessment_id=self.kwargs['assessment_pk'] ).all() # Issuer type id is used to create the rating below issuer_type_id = d.issuer.issuer_type.id # Return indicative ratings based on score input proposed_rating = PCRRating(generate_rating_dict( issuer_type_id, internal_score_obj, 'decided', version=2) ) ass = RATING_LONG_TERM[proposed_rating.issuer_rating] d.assessment_lt = ass except Exception: d.assessment_lt = None try: # Save issue level assessments i_lvl = SeniorityLevelAssessment.objects.filter( assessment_id=self.kwargs['assessment_pk'], ) for i in i_lvl: try: # The assessments are stored relative to the issuer # assessment i.decided_lt = d.assessment_lt - issue_seniority_lvl[i.id] i.save() except ValueError: pass except Exception: pass if form.cleaned_data['ready_for_approval']: # The user has marked the assessment as ready for approval, # flag it as such d.process_step = 2 d.initiated_by = self.request.user messages.add_message( self.request, messages.INFO, 'The assessment has been flagged as ready for approval.') elif form.cleaned_data['give_final_approval']: # Mark all previous assessment for issuer as non-current AssessmentJob.objects.filter( issuer=d.issuer ).update( is_current=False ) # This makes the decision valid and official d.is_current = True # Finish the process d.process_step = 10 # Committee timestamp is now d.date_time_approval = timezone.now() messages.add_message( self.request, messages.INFO, 'Assessment approved and saved to database.') else: messages.add_message( self.request, messages.INFO, 'Saved assessment.') d.save() return super(AssessmentUpdateView, self).form_valid(form)