def rating_identifier_formatted(self): """An identifier that follows the rating through its live span.""" # Preliminary ratings have their own ID's if self.rating_decision.is_preliminary: b = 'P_' else: b = '' b += (format_reference_number(number=self.rating_identifier, object_type='rating_decision') + '_' + self.qtratingaction.qtratinginfo.get_time_horizon_display()) try: # This is an issue rating, add issuer suffic if self.qtratingaction.qtratinginfo.qtinstrumentinfo.\ instrument_internal_code: b += '_' + self.qtratingaction.qtratinginfo.\ qtinstrumentinfo.instrument_internal_code except: # noqa: E722 # todo: catch RelatedObjectDoesNotExist pass return b
def preliminary_rating_identifier(self): """ESMA-specified unique identifier for preliminary rating. If instrument is true, return instrument identifier, else rating identifier.""" if self.preceding_preliminary_rating_flag: b = 'P_' b += format_reference_number( number=self.rating_info.rating_action.rating_create_data. rating_decision.esma_rating_identifier, object_type='rating_decision', ) b += self.rating_info.rating_action.\ qtratinginfo.get_time_horizon_display() try: b += self.rating_info.qtinstrumentinfo.instrument_internal_code except: # noqa: E722 pass return b
def instrument_internal_code(self): """Internal ID for the issue.""" return format_reference_number(number=self.issue.pk, object_type='issue')
def rating_scale_code(self): """A code used internally by ESMA""" return format_reference_number(number=self.rating_scale.pk, object_type='rating_scale')
def issuer_internal_code(self): """A unique identifier for this record?.""" return format_reference_number( number=self.rating_info.rating_action.rating_create_data. rating_decision.issuer.pk, object_type='issuer')
def populate_rating_scale(xml_file): """Scan original model and return change reason as well as change type.""" create_record = False esma_record = None create_or_update_id = [] reporting_reason_dict = {} reporting_type_dict = {} change_reason_dict = {} """Rating scale.""" for rating_scale in RatingScaleOrig.objects.order_by('id').all(): """Do a field by field comparison""" # Unique identifier for this model unique_identifier_rating_scale = format_reference_number( object_type='rating_scale', number=rating_scale.id) try: esma_record = RatingScaleESMA.objects.filter( rating_scale_code=unique_identifier_rating_scale, xml_file__status_code=1).order_by('-id').all()[0] except (IndexError, RatingScaleESMA.DoesNotExist): """There is no record in the ESMA model, create it.""" create_record = True # Create a list of IDs that should be inserted create_or_update_id.append(rating_scale.id) reporting_type_dict[rating_scale.id] = 1 # 1=NEW # must be list reporting_reason_dict[rating_scale.id] = [STRING_NEW_ITEM] if not create_record: """There is an existing parent, check for differences and if differences, generate change reason and change.""" reporting_reason_dict[rating_scale.id] = [] for compare_obj in RSCALE_COMPARE_FIELDS: """Compare value of field in base model with ESMA record.""" if (getattr(rating_scale, compare_obj['field_orig']) != getattr(esma_record, compare_obj['field_esma'])): create_or_update_id.append(rating_scale.id) reporting_type_dict[ rating_scale.id] = compare_obj['reporting_type'] change_reason_dict[ rating_scale.id] = compare_obj['change_reason'] reporting_reason_dict[rating_scale.id].append( compare_obj['reporting_reason']) """Scope.""" for orig_scope_record in RatingScopeOrig.objects.filter( rating_scale=rating_scale).order_by('-id').all(): unique_identifier_rating_scope = format_reference_number( object_type='rating_scope', number=orig_scope_record.id) esma_record_scope = RatingScopeESMA.objects.filter( rating_scope_code=unique_identifier_rating_scope).order_by( '-id')[0] for compare_obj in RSCOPE_COMPARE_FIELDS: """Compare value of field in base model with ESMA record.""" if (getattr(orig_scope_record, compare_obj['field_orig']) != getattr(esma_record_scope, compare_obj['field_esma'])): # Should be top level id create_or_update_id.append(rating_scale.id) reporting_type_dict[ rating_scale.id] = compare_obj['reporting_type'] change_reason_dict[ rating_scale.id] = compare_obj['change_reason'] reporting_reason_dict[rating_scale.id].append( compare_obj['reporting_reason']) """Category.""" for orig_category_record in RatingCategoryOrig.objects.filter( rating_scale=rating_scale).order_by('-id').all(): unique_identifier_rating_category = format_reference_number( object_type='rating_category', number=orig_category_record.id) esma_record_category = RatingCategoryESMA.objects.filter( rating_category_code=unique_identifier_rating_category ).order_by('-id')[0] for compare_obj in RCATEGORY_COMPARE_FIELDS: """Compare value of field in base model with ESMA record.""" if (getattr(orig_category_record, compare_obj['field_orig']) != getattr( esma_record_category, compare_obj['field_esma'])): # Should be top level id create_or_update_id.append(rating_scale.id) reporting_type_dict[ rating_scale.id] = compare_obj['reporting_type'] change_reason_dict[ rating_scale.id] = compare_obj['change_reason'] reporting_reason_dict[rating_scale.id].append( compare_obj['reporting_reason']) """Notch.""" for orig_notch_record in RatingNotchOrig.objects.filter( rating_category=orig_category_record).order_by( '-id').all(): unique_identifier_rating_notch = \ format_reference_number( object_type='rating_notch', number=orig_notch_record.id) esma_record_notch = RatingNotchESMA.objects.filter( rating_notch_code=unique_identifier_rating_notch ).order_by('-id')[0] for compare_obj in RNOTCH_COMPARE_FIELDS: """Compare value of field in base model with ESMA record.""" if (getattr(orig_notch_record, compare_obj['field_orig']) != getattr( esma_record_notch, compare_obj['field_esma'])): # Should be top level id create_or_update_id.append(rating_scale.id) reporting_type_dict[ rating_scale. id] = compare_obj['reporting_type'] change_reason_dict[ rating_scale. id] = compare_obj['change_reason'] reporting_reason_dict[rating_scale.id].append( compare_obj['reporting_reason']) # Looks like nothing happened with this record, delete it if len(reporting_reason_dict[rating_scale.id]) == 0: del reporting_reason_dict[rating_scale.id] for rating_scale_orig in RatingScaleOrig.objects.filter( pk__in=create_or_update_id).all(): reporting_type = reporting_type_dict[rating_scale_orig.id] reporting_reason = reporting_reason_dict[rating_scale_orig.id] try: change_reason = change_reason_dict[rating_scale_orig.id] except KeyError: change_reason = None unique_identifier_rating_scale = format_reference_number( object_type='rating_scale', number=rating_scale_orig.id) # Create a new ReportingTypeInfo record reporting_type_info, _ = get_or_create_reporting_type_info( reporting_type=reporting_type, change_reason=change_reason, reporting_reason_text=create_reporting_reason_string( reporting_reason), hash_string=create_hash_string(unique_identifier_rating_scale, reporting_type)) # Create a new record rating_scale_esma = RatingScaleESMA.objects.create( reporting_type_info=reporting_type_info, xml_file=xml_file, # Insert all model fields below here rating_scale_code=unique_identifier_rating_scale, start_date=rating_scale_orig.start_date, end_date=rating_scale_orig.end_date, description=rating_scale_orig.description, ) for rating_scope_orig in RatingScopeOrig.objects.filter( rating_scale=rating_scale_orig).order_by('id').all(): unique_identifier_rating_scope = format_reference_number( object_type='rating_scope', number=rating_scope_orig.id) # Create a new record RatingScopeESMA.objects.create( rating_scale=rating_scale_esma, # Insert all model fields below here rating_scope_code=unique_identifier_rating_scope, time_horizon=rating_scope_orig.time_horizon, rating_type=rating_scope_orig.rating_type, rating_scale_scope=rating_scope_orig.rating_scale_scope, relevant_for_cerep_flag=rating_scope_orig. relevant_for_cerep_flag, start_date=rating_scope_orig.start_date, end_date=rating_scope_orig.end_date, ) for rating_category_orig in RatingCategoryOrig.objects.filter( rating_scale=rating_scale_orig).order_by('id').all(): unique_identifier_rating_category = format_reference_number( object_type='rating_category', number=rating_category_orig.id) # Create a new record rating_category_esma = RatingCategoryESMA.objects.create( rating_scale=rating_scale_esma, # Insert all model fields below here rating_category_code=unique_identifier_rating_category, value=rating_category_orig.value, label=rating_category_orig.label, description=rating_category_orig.description, ) for rating_notch_orig in RatingNotchOrig.objects.filter( rating_category=rating_category_orig).order_by('id').all(): unique_identifier_rating_notch = format_reference_number( object_type='rating_notch', number=rating_notch_orig.id) # Create a new record RatingNotchESMA.objects.create( rating_category=rating_category_esma, # Insert all model fields below here rating_notch_code=unique_identifier_rating_notch, value=rating_notch_orig.value, label=rating_notch_orig.label, description=rating_notch_orig.description, )
def rating_action_identifier(self): """A unique identifier for this record?.""" return format_reference_number(number=self.pk, object_type='rating_action')
def pending_confirm_parameter(request, action, rating_decision_pk): """Update steps in the rating process model Process.""" hash = None if action: rating_decision_obj = RatingDecision.objects.get(pk=rating_decision_pk) rating_process_obj, created = Process.objects.get_or_create( rating_decision=rating_decision_obj) rating_job_id = format_reference_number(number=rating_decision_obj.id, object_type='rating_decision',) if action == 'setup_done': hash = 'setup_step_2' rating_decision_obj.process_step = 2 rating_process_obj.setup_done = timezone.now() to_list = [ rating_decision_obj.chair.email ] # Notify analysts and relationship manager cc_list = [ rating_decision_obj.issuer.analyst. primary_analyst.email, rating_decision_obj.issuer.analyst. secondary_analyst.email, rating_decision_obj.issuer.relationship_manager.email, ] # We want to notify Compliance in production if os.environ['ENVIRONMENT_MODE'] == 'PROD': cc_list.append('*****@*****.**') header = SETUP_HEADER.format( rating_decision_obj.issuer, rating_job_id, ) body = SETUP_BODY % rating_decision_obj.chair.first_name # Send notification to chair send_email.delay( header=header, body=body, to=to_list, from_sender=None, cc=cc_list) elif action == 'pre_committee_done': hash = 'setup_step_3' rating_decision_obj.process_step = 3 rating_process_obj.pre_committee_done = timezone.now() rating_decision_obj.chair_confirmed = True rating_decision_obj.date_time_committee_confirmed = True to_list = [ rating_decision_obj.issuer.analyst. primary_analyst.email, rating_decision_obj.issuer.analyst. secondary_analyst.email, ] cc_list = [ rating_decision_obj.issuer.relationship_manager.email, rating_decision_obj.chair.email, ] # We want to notify Compliance in production if os.environ['ENVIRONMENT_MODE'] == 'PROD': cc_list.append('*****@*****.**') header = PRE_COMMITTEE_HEADER.format( rating_decision_obj.issuer, rating_decision_obj.chair.get_full_name(), rating_job_id, ) # Send notification send_email.delay( header=header, body=PRE_COMMITTEE_BODY % rating_decision_obj.issuer.analyst. primary_analyst.first_name, to=to_list, from_sender=None, cc=cc_list,) elif action == 'analytical_phase_done': hash = 'setup_step_4' rating_decision_obj.process_step = 4 rating_process_obj.analytical_phase_done = timezone.now() # Send notification to chair and members of committee to_list = [ rating_decision_obj.issuer.analyst.primary_analyst.email, rating_decision_obj.issuer.analyst.secondary_analyst.email, rating_decision_obj.chair.email, ] cc_list = [ rating_decision_obj.issuer.relationship_manager.email, ] # We want to notify Compliance in production if os.environ['ENVIRONMENT_MODE'] == 'PROD': cc_list.append('*****@*****.**') # Get all members committee_members = list( JobMember.objects.confirmed_members().filter( rating_decision=rating_decision_obj, group_id=1)) for item in committee_members: to_list.append(item.member.email) local_dt = timezone.localtime( rating_decision_obj.date_time_committee, timezone.get_fixed_timezone(60)) header = ANALYTICAL_PHASE_HEADER.format( rating_decision_obj.issuer, local_dt.strftime('%Y-%m-%d %H:%M'), rating_job_id, ) send_email.delay( header=header, body=ANALYTICAL_PHASE_BODY, to=to_list, cc=cc_list, from_sender=None) elif action == 'post_committee_done': hash = 'setup_step_5' rating_decision_obj.process_step = 5 rating_process_obj.post_committee_done = timezone.now() # Contains the name and email of the editor editor_obj = JobMember.objects.get( rating_decision=rating_decision_obj, group=Group.objects.get(pk=2)) to_list = [ editor_obj.member.email, ] cc_list = [ rating_decision_obj.issuer.analyst.primary_analyst.email, rating_decision_obj.issuer.analyst.secondary_analyst.email, rating_decision_obj.chair.email, rating_decision_obj.issuer.relationship_manager.email, ] # We want to notify Compliance in production if os.environ['ENVIRONMENT_MODE'] == 'PROD': cc_list.append('*****@*****.**') header = EDITOR_HEADER.format( rating_decision_obj.issuer, rating_job_id, ) # Send email with link to admin control to editor send_email.delay(header=header, body=EDITOR_EMAIL % ( editor_obj.member.first_name, rating_decision_obj.issuer.analyst. primary_analyst.first_name), to=to_list, cc=cc_list, from_sender=None,) elif action == 'editor_phase_done': """Here, we're sending the draft report to the issuer.""" hash = 'setup_step_6' rating_decision_obj.process_step = 6 # External analysis send_public_report(rating_decision_obj) # Send notification to chair to_list = [ rating_decision_obj.issuer.relationship_manager.email, ] header = "{} | the draft report has been sent to the " \ "issuer".format(rating_decision_obj.issuer,) send_email.delay( header=header, body=' ', to=to_list, from_sender=None,) # Set a timestamp when se sent the report to the issuer rating_decision_obj.date_time_communicated_issuer = timezone.now() rating_process_obj.editor_review_done = timezone.now() elif action == 'issuer_confirmation_phase_done': hash = 'setup_step_7' rating_decision_obj.process_step = 7 to_list = [ rating_decision_obj.chair.email, rating_decision_obj.issuer.analyst.primary_analyst.email, rating_decision_obj.issuer.analyst.secondary_analyst.email, rating_decision_obj.issuer.relationship_manager.email, ] # We want to notify Compliance in production if os.environ['ENVIRONMENT_MODE'] == 'PROD': to_list.append('*****@*****.**') header = "{} | The issuer has confirmed the accuracy of the " \ "draft report for rating job {}".format( rating_decision_obj.issuer, rating_job_id, ) # Send notification send_email.delay( header=header, body='', to=to_list, from_sender=None,) rating_process_obj.issuer_confirmation_done = timezone.now() elif action == 'analyst_final_approval_phase_done': hash = 'setup_step_8' rating_process_obj.final_sign_off_analyst_done = timezone.now() rating_decision_obj.process_step = 8 to_list = [ rating_decision_obj.issuer.analyst.primary_analyst.email, ] cc_list = [ rating_decision_obj.chair.email, rating_decision_obj.issuer.analyst.secondary_analyst.email, rating_decision_obj.issuer.relationship_manager.email, ] # We want to notify Compliance in production if os.environ['ENVIRONMENT_MODE'] == 'PROD': cc_list.append('*****@*****.**') header = ANALYST_FINAL_APPROVAL_HEADER.format( rating_decision_obj.issuer ) # Send notification to chair send_email.delay( header=header, body=ANALYST_FINAL_APPROVAL_BODY % rating_decision_obj.issuer.analyst. primary_analyst.first_name, to=to_list, from_sender=None, cc=cc_list) elif action == 'chair_final_approval_phase_done': hash = 'setup_step_9' rating_decision_obj.process_step = 9 rating_process_obj.final_sign_off_chair_done = timezone.now() to_list = [ rating_decision_obj.issuer.analyst.primary_analyst.email, rating_decision_obj.issuer.analyst.secondary_analyst.email, ] cc_list = [ rating_decision_obj.chair.email, rating_decision_obj.issuer.relationship_manager.email, ] # We want to notify Compliance in production if os.environ['ENVIRONMENT_MODE'] == 'PROD': cc_list.append('*****@*****.**') header = CHAIR_FINAL_APPROVAL_HEADER.format( rating_decision_obj.issuer ) # Send notification to analyst send_email.delay(header=header, body=CHAIR_FINAL_APPROVAL_BODY % rating_decision_obj.issuer.analyst. primary_analyst.first_name, to=to_list, from_sender=None, cc=cc_list,) elif action == 'publishing_phase_done': hash = "" rating_decision_obj.date_time_published = timezone.now() to_list = [ rating_decision_obj.issuer.analyst.primary_analyst.email, rating_decision_obj.issuer.analyst.secondary_analyst.email, rating_decision_obj.chair.email, rating_decision_obj.issuer.relationship_manager.email, ] # We want to notify Compliance in production if os.environ['ENVIRONMENT_MODE'] == 'PROD': to_list.append('*****@*****.**') header = "{} | the rating job has been finalized".format( rating_decision_obj.issuer ) # Send notification send_email.delay(header=header, body='If this a public rating, the publishing ' 'process will now commence.', to=to_list, from_sender=None,) """If there is a previous decision, flag it as non-current.""" try: RatingDecision.objects.filter( pk=rating_decision_obj.previous_rating.pk).update( is_current=False,) except AttributeError: pass rating_decision_obj.is_current = True rating_process_obj.process_ended = timezone.now() # Create a DecisionAttribute object that # summarizes the rating decision refresh_decision_attributes(rating_decision_obj) # Create decisions on the issue level update_issue_rating(rating_decision_obj) # Create a draft campaign with MailChimp if rating_decision_obj.rating_type.id == 1: run_create_campaign.delay(rating_decision_obj.id) rating_decision_obj.process_step = 10 # Save changes rating_process_obj.save() rating_decision_obj.save() redirect_url = request.META.get('HTTP_REFERER', '/') + '#' + hash return http.HttpResponseRedirect(redirect_url)
def populate_cra_info(xml_file): """Scan original model and insert into ESMA model if required. This function does a field-by-field comparison against""" for orig_record in OrigModel.objects.all(): # As a default, don't do anything change_reason = None reporting_type = None reporting_reason = [] create_record = False # Unique identifier for this model unique_identifier = format_reference_number( object_type='cra_info', number=orig_record.id) try: esma_record = ESMAModel.objects.last_valid_record()[0] for compare_obj in COMPARE_FIELDS: """Compare value of field in base model with ESMA record.""" if (getattr(orig_record, compare_obj['field_orig']) != getattr(esma_record, compare_obj['field_esma'])): # Something has changed, create a new entry in ESMA-table. create_record = True reporting_type = compare_obj['reporting_type'] change_reason = compare_obj['change_reason'] reporting_reason.append( compare_obj['reporting_reason']) except (IndexError, ESMAModel.DoesNotExist): """The object is not existing in the ESMA table: create it.""" create_record = True reporting_type = 1 # 1=NEW reporting_reason.append(STRING_NEW_ITEM) if create_record: # Create a new ReportingTypeInfo record reporting_type_info, _ = get_or_create_reporting_type_info( reporting_type=reporting_type, change_reason=change_reason, reporting_reason_text=create_reporting_reason_string( reporting_reason), hash_string=create_hash_string( unique_identifier, reporting_type) ) # Because of the long variable name a = orig_record.\ solicited_unsolicited_rating_policy_description # Create a new record ESMAModel.objects.create( xml_file=xml_file, reporting_type_info=reporting_type_info, # Insert all model fields below here cra_info_code=unique_identifier, cra_name=orig_record.cra_name, cra_description=orig_record.cra_description, cra_methodology=orig_record.cra_methodology, cra_methodology_webpage_link=orig_record. cra_methodology_webpage_link, solicited_unsolicited_rating_policy_description=a, subsidiary_rating_policy=orig_record. subsidiary_rating_policy, global_reporting_scope_flag=orig_record. global_reporting_scope_flag, definition_default=orig_record.definition_default, cra_website_link=orig_record.cra_website_link, )
def rating_scale_code(self): return format_reference_number(number=self.pk, object_type='rating_scale')
def populate_issue_program(xml_file): """Scan original model and insert into ESMA model if required.""" for orig_record in OrigModel.objects.all(): # As a default, don't do anything change_reason = None reporting_type = None reporting_reason = [] create_record = False # Unique identifier for this model unique_identifier = format_reference_number( object_type='issue_program', number=orig_record.id) try: esma_record = ESMAModel.objects.last_valid_record().filter( program_code=unique_identifier)[0] for compare_obj in COMPARE_FIELDS: """Compare value of field in base model with ESMA record.""" if (getattr(orig_record, compare_obj['field_orig']) != getattr( esma_record, compare_obj['field_esma'])): create_record = True reporting_type = compare_obj['reporting_type'] change_reason = compare_obj['change_reason'] reporting_reason.append(compare_obj['reporting_reason']) except (IndexError, ESMAModel.DoesNotExist): """The rating scale is not existing in the ESMA table, create it.""" create_record = True reporting_type = 1 # 1=NEW reporting_reason.append(STRING_NEW_ITEM) if create_record: # Create a new ReportingTypeInfo record reporting_type_info, _ = get_or_create_reporting_type_info( reporting_type=reporting_type, change_reason=change_reason, reporting_reason_text=create_reporting_reason_string( reporting_reason), # Change the unique identifiere here hash_string=create_hash_string(unique_identifier, reporting_type)) # Create a new record ESMAModel.objects.create( xml_file=xml_file, reporting_type_info=reporting_type_info, # Insert all model fields below here program_code=unique_identifier, program_name=orig_record.name, program_description=orig_record.description, program_start_date=orig_record.start_date, program_end_date=orig_record.end_date, )
def create_campaign(**kwargs): """This function creates a campaign in MailChimp through their API.""" client = MailChimp( mc_user=djangoSettings.MC_USER, mc_api=djangoSettings.MC_API_KEY, ) # Set properties for campaign rating_job_id = kwargs['rating_job_id'] header = kwargs['header'] body = kwargs['body'] campaign_title = format_reference_number( number=rating_job_id, object_type='rating_decision', ) + ' - ' + header template_id = kwargs['template_id'] issuer_type_id = kwargs['issuer_type_id'] list_id = '801d23f631' # Web site signup folder_id = '7024652103' # Rating saved_segment_id = None if issuer_type_id == 1: # Corporate saved_segment_id = 29557 elif issuer_type_id == 2: # Financial saved_segment_id = 29565 elif issuer_type_id == 3: # Real estate saved_segment_id = 29569 # Override these settings in test environment if os.environ['ENVIRONMENT_MODE'] != 'PROD': folder_id = '53b0a3465b' list_id = '42a98c90a0' saved_segment_id = 29573 data = { 'recipients': { 'list_id': list_id, 'segment_opts': { 'saved_segment_id': saved_segment_id, } }, 'settings': { 'title': campaign_title, 'from_name': 'Nordic Credit Rating', 'reply_to': '*****@*****.**', 'template_id': template_id, # Mail headline # No more than 150 chars according to specs 'subject_line': header[0:150], # No more than 150 chars according to specs 'preview_text': strip_tags(body[0:150]), 'folder_id': folder_id, }, 'type': 'regular', } return client.campaigns.create(data)
def populate_rating_decision(issues=False): """Check today's decisions.""" # Check if the decision has been sent already # Ordering is important! # there is a constant in CONST defining how long to look back if issues: decision_backlog = IssueDecision.objects.esma() else: decision_backlog = RatingDecision.objects.esma() if issues: # Only the long-term perspective is relevant for issues PERSPECTIVES = [ 1, # Long-term ] else: PERSPECTIVES = [ 1, # Long-term 2, # Short-term ] # Loop through each record from the past n days for x in decision_backlog: logger.info(" analyzing decision: " + str(x)) # Pick up the decision attributes attributes = get_attributes(issues, x) # Reset the values iss = None debt_classification_code = None issuer_rating_type_code = None # Store previous rating decision, if available try: previous_rating = x.previous_rating except Exception: previous_rating = False if issues: # Issue instance iss = x # Rating decision instance dec = x.rating_decision_issue.rating_decision else: # Rating decision instance dec = x # Assume there is no previous rating prev_rating_preliminary = False if issues: rated_object = 2 # 2 = Issue # Should be seniority debt_classification_code = format_reference_number( number=iss.issue.seniority.id, object_type='debt_class') else: rated_object = 1 # 1 = Issuer issuer_rating_type_code = format_reference_number( number=1, object_type='rating_type') # 2 is financial institution if dec.issuer.issuer_type.id == 2: industry = 1 else: industry = 3 # Public rating not exclusively # produced for and disclosed # to investors for a fee if dec.rating_type.id == 1: type_of_rating_for_erp = 1 else: type_of_rating_for_erp = 2 # Logic as provided by ESMA during a call # Preliminary issuer ratings and issue ratings should not have # this flag if dec.decisionattributes.is_new_preliminary or rated_object != 1: relevant_for_cerep = False else: relevant_for_cerep = True # Loop through long-term and short-term for perspective in PERSPECTIVES: logger.info(" perspective: " + str(perspective)) # There's some unknown error going on # try to catch it try: TEMP = {} TEMP_L = {} action_type_list = [] # TODO: not implemented # Default these values to NULL in db owsd_status = None outlook_trend = None watch_review = None withdrawal_reason_type = None ############################################ # MISC VARIABLES ############################################ if perspective == 1: # Long-term rating_value = x.decided_lt else: rating_value = x.decided_st ############################################ # NEW PRELIMINARY RATING ############################################ # We have to create a new preliminary rating # and place an outlook if attributes.is_new_preliminary: action_type_list.append(2) # Place an outlook for long-term ratings # Issues dont have outlooks if perspective == 1 and not issues: action_type_list.append(10) TEMP[dec.id] = { 10: { 'owsd_status': 1, # place 'outlook_trend': get_outlook_trend(dec), 'validity_date': x.date_time_published + timedelta(minutes=1), } } ############################################ # NEW RATING ############################################ # We have to create a new rating and place # an outlook elif attributes.is_new: action_type_list.append(3) # Place an outlook for long-term ratings # Issues dont have outlooks if perspective == 1 and not issues: action_type_list.append(10) TEMP[dec.id] = { 10: { 'owsd_status': 1, # place 'outlook_trend': get_outlook_trend(dec), 'validity_date': x.date_time_published + timedelta(minutes=1), } } """Check if previous rating was preliminary.""" try: if issues: if iss.previous_rating.issuedecisionattributes. \ is_new_preliminary: prev_rating_preliminary = True else: if dec.previous_rating.decisionattributes. \ is_new_preliminary: prev_rating_preliminary = True except AttributeError: pass ############################################ # RATING SCALES ############################################ if attributes.is_new_preliminary: if perspective == 1: # Scale for long-term ratings rating_scale_id = 3 else: # Scale for short-term ratings rating_scale_id = 4 else: if perspective == 1: # Scale for long-term ratings rating_scale_id = 1 else: # Scale for short-term ratings rating_scale_id = 2 ############################################ # LONG-TERM UPGRADED ############################################ if attributes.is_lt_upgrade and perspective == 1: action_type_list.append(4) ############################################ # LONG-TERM DOWNGRADED ############################################ if attributes.is_lt_downgrade and perspective == 1: action_type_list.append(5) ############################################ # LONG-TERM AFFIRMED ############################################ if attributes.is_lt_affirmation and perspective == 1: action_type_list.append(6) ############################################ # SHORT-TERM UPGRADED ############################################ # Not valid for issue ratings, hence the # try/catch try: if attributes.is_st_upgrade and perspective == 2: action_type_list.append(4) except AttributeError: pass ############################################ # SHORT-TERM DOWNGRADED ############################################ # Not valid for issue ratings, hence the # try/catch try: if attributes.is_st_downgrade and perspective == 2: action_type_list.append(5) except AttributeError: pass ############################################ # SHORT-TERM AFFIRMED ############################################ # Not valid for issue ratings, hence the # try/catch try: if attributes.is_st_affirmation and perspective == 2: action_type_list.append(6) except AttributeError: pass ############################################ # DEFAULTS ############################################ # Regular default if attributes.is_default: action_type_list.append(7) if attributes.is_default: default_flag = True else: default_flag = False # Selective default if attributes.is_selective_default: action_type_list.append(7) ############################################ # RATING SUSPENDED ############################################ if attributes.is_suspension: action_type_list.append(8) ############################################ # RATING WITHDRAWN ############################################ # Note from ESMA: don't withdraw preliminary # ratings if attributes.is_withdrawal: action_type_list.append(9) try: if attributes.is_matured: TEMP[dec.id] = { 9: { 'action_type': 9, 'withdrawal_reason_type': 4, } } except AttributeError: pass ############################################ # RATING OUTLOOK CHANGED ############################################ # Outlook has changed # Only check this for long-term perspective # According to ESMA you first place an outlook # Then you remove the old outlook and place a new one try: # 1 = long-term and only for issuer ratings if perspective == 1 and not issues: if attributes.is_outlook_change: # Remove current outlook # Place outlook action_type_list.append(10) action_type_list.append(10) TEMP_L[dec.id] = { 10: [ { 'owsd_status': 3, # remove 'outlook_trend': get_outlook_trend(previous_rating), 'is_parsed': False, }, { 'owsd_status': 1, # Place 'outlook_trend': get_outlook_trend(dec), 'is_parsed': False, } ] } # Place a maintain # But not on a new rating elif not attributes.is_new and not \ attributes.is_new_preliminary: # Maintain current outlook action_type_list.append(10) TEMP[dec.id] = { 10: { 'owsd_status': 2, # Maintain 'outlook_trend': get_outlook_trend(dec), } } except AttributeError: pass ############################################ # RATING WATCH ############################################ try: if attributes.is_watch: # TODO: implement OSWD_status action_type_list.append(11) except AttributeError: pass except Exception as e: logger.info("Error: " + str(e)) # Run through all action types from above for t in action_type_list: logger.info(" action type: " + str(ACTION_TYPE[t])) # Defined as list to make sure order is maintained hash_input = [ x.date_time_published.strftime('%Y-%m-%d'), x.id, t, perspective ] hash_key = create_hash(*hash_input) # A list of action types has been sent, # TODO: this is not pretty, but I'm out of time try: if type(TEMP_L[dec.id][t]) == list: if not TEMP_L[dec.id][t][0]['is_parsed']: try: owsd_status = TEMP_L[ dec.id][t][0]['owsd_status'] except KeyError: pass try: outlook_trend = TEMP_L[ dec.id][t][0]['outlook_trend'] except KeyError: pass try: watch_review = TEMP_L[ dec.id][t][0]['watch_review'] except KeyError: pass try: withdrawal_reason_type = TEMP_L[ dec.id][t][0]['withdrawal_reason_type'] except KeyError: pass try: validity_date = TEMP_L[ dec.id][t][0]['validity_date'] except KeyError: # Standard time used in reporting # There is a special case to report outlooks # on new ratings as informed in an email # from ESMA on 2018-10-31, 14.43 with the # validity datetime of the OT action later than # the NW action (e.g. 1 minute later validity # datetime). validity_date = x.date_time_published TEMP_L[dec.id][t][0]['is_parsed'] = True elif not TEMP_L[dec.id][t][1]['is_parsed']: try: owsd_status = TEMP_L[ dec.id][t][1]['owsd_status'] except KeyError: pass try: outlook_trend = TEMP_L[ dec.id][t][1]['outlook_trend'] except KeyError: pass try: watch_review = TEMP_L[ dec.id][t][1]['watch_review'] except KeyError: pass try: withdrawal_reason_type = TEMP_L[ dec.id][t][1]['withdrawal_reason_type'] except KeyError: pass try: validity_date = TEMP_L[ dec.id][t][1]['validity_date'] except KeyError: # Standard time used in reporting # There is a special case to report outlooks # on new ratings as informed in an email # from ESMA on 2018-10-31, 14.43 with the # validity datetime of the OT action later # than the NW action (e.g. 1 minute later # validity datetime). validity_date = x.date_time_published TEMP_L[dec.id][t][1]['is_parsed'] = True else: try: owsd_status = TEMP[dec.id][t]['owsd_status'] except KeyError: pass try: outlook_trend = TEMP[dec.id][t]['outlook_trend'] except KeyError: pass try: watch_review = TEMP[dec.id][t]['watch_review'] except KeyError: pass try: withdrawal_reason_type = TEMP[ dec.id][t]['withdrawal_reason_type'] except KeyError: pass try: validity_date = TEMP[dec.id][t]['validity_date'] except KeyError: # Standard time used in reporting # There is a special case to report outlooks on # new ratings as informed in an email from ESMA # on 2018-10-31, 14.43 with the validity datetime # of the OT action later than the NW action # (e.g. 1 minute later validity datetime). validity_date = x.date_time_published except KeyError: try: owsd_status = TEMP[dec.id][t]['owsd_status'] except KeyError: pass try: outlook_trend = TEMP[dec.id][t]['outlook_trend'] except KeyError: pass try: watch_review = TEMP[dec.id][t]['watch_review'] except KeyError: pass try: withdrawal_reason_type = TEMP[ dec.id][t]['withdrawal_reason_type'] except KeyError: pass try: validity_date = TEMP[dec.id][t]['validity_date'] except KeyError: # Standard time used in reporting # There is a special case to report outlooks on # new ratings as informed in an email from ESMA # on 2018-10-31, 14.43 with the validity datetime # of the OT action later than the NW action # (e.g. 1 minute later validity datetime). validity_date = x.date_time_published logger.info(" inserting records in db") # If this data point has already been inserted successfully, # skip to the next step if QTRatingCreateData.objects.filter( hash=hash_key, xml_file__status_code=1).exists(): # We have already reported this successfully # work on next file instead continue else: create_rating_decision_xml_objects( hash_key, dec, x, validity_date, t, owsd_status, outlook_trend, watch_review, withdrawal_reason_type, rating_scale_id, rating_value, default_flag, rated_object, perspective, issuer_rating_type_code, debt_classification_code, industry, type_of_rating_for_erp, relevant_for_cerep, prev_rating_preliminary, issues, iss, attributes, )
def populate_debt_classification(xml_file): """Scan original model and insert into ESMA model if required.""" for orig_record in OrigModel.objects.all(): # As a default, don't do anything change_reason = None reporting_type = None reporting_reason = [] create_record = False # Unique identifier for this model unique_identifier = format_reference_number(object_type='debt_class', number=orig_record.id) try: esma_record = ESMAModel.objects.last_valid_record().filter( debt_classification_code=unique_identifier)[0] for compare_obj in COMPARE_FIELDS: """Compare value of field in base model with ESMA record.""" if (getattr(orig_record, compare_obj['field_orig']) != getattr( esma_record, compare_obj['field_esma'])): create_record = True reporting_type = compare_obj['reporting_type'] change_reason = compare_obj['change_reason'] reporting_reason.append(compare_obj['reporting_reason']) # Custom comparison of seniority due to the OrigModel # being a bit different if orig_record.seniority_level.id != esma_record.seniority: create_record = True reporting_type = 2 # 2=CHG change_reason = 1 # 2=U: Consider this to be an an update reporting_reason.append('seniority level') except (IndexError, ESMAModel.DoesNotExist): """The rating scale is not existing in the ESMA table, create it.""" create_record = True reporting_type = 1 # 1=NEW reporting_reason.append(STRING_NEW_ITEM) if create_record: # Create a new ReportingTypeInfo record reporting_type_info, _ = get_or_create_reporting_type_info( reporting_type=reporting_type, change_reason=change_reason, reporting_reason_text=create_reporting_reason_string( reporting_reason), hash_string=create_hash_string(unique_identifier, reporting_type)) # Create a new record ESMAModel.objects.create( xml_file=xml_file, reporting_type_info=reporting_type_info, # Insert all model fields below here debt_classification_code=unique_identifier, debt_classification_name=orig_record.name, debt_classification_description=orig_record.description, seniority=orig_record.seniority_level.id, debt_classification_start_date=orig_record.start_date, debt_classification_end_date=orig_record.end_date, )