def _doc_period_end_date_check(modelXbrl): """ Compares the value of DocumentPeriodEndDate against the end date of its context. If the difference is more than 3 days, fires a validation error. For each DocumentPeriodEndDate, if the above check doesn't fire, check all DEI fact context end dates against it. """ dped_facts, dei_facts = _setup_dei_facts(modelXbrl) default_dped_fact = _get_default_dped(dped_facts) result_group = [] if default_dped_fact is None: return result_group is_valid_dped = True # loop through the DocumentPeriodEndDate's to check for consistant dates for eop_facts in dped_facts.values(): eop_fact = eop_facts[0] eop_context = eop_fact.context if eop_context is None or eop_context.endDatetime is None: continue fact_eop_date = dateunionDate(eop_fact.xValue, subtractOneDay=True) # Arelle adjusts context end date to end-of-day midnight # Reverse the adjustment to get the expected date value by subtracting one day context_eop_date = dateunionDate(eop_context.endDatetime, subtractOneDay=True) delta = context_eop_date - fact_eop_date if abs(delta.days) > 3: is_valid_dped = False result_group.append(('{}.1'.format(_CODE_NAME_36), messages.get_message(_CODE_NAME_36), context_eop_date, eop_fact, default_dped_fact)) if is_valid_dped: # Don't loop through them if the DPED date is bad, since the date is incorrect. # loop through the dei facts and compare against their LEA's DocumentPeriodEndDate for lea_key, fact_group in dei_facts.items(): eop_fact = dped_facts.get(lea_key, default_dped_fact)[0] if eop_fact is None or eop_fact.context is None or eop_fact.context.endDatetime is None: continue fact_eop_date = dateunionDate(eop_fact.xValue, subtractOneDay=True) # Arelle adjusts context end date to end-of-day midnight # Reverse the adjustment to get the expected date value by subtracting one day context_eop_date = dateunionDate(eop_fact.context.endDatetime, subtractOneDay=True) if len(fact_group) > 0: #check all DEI facts against this DocumentPeriodEndDate. If the DocumentPeriodEndDate context check doesn't fire, we will check all dei fact context end dates against it. for fact in fact_group: if fact.context is None or fact.context.endDatetime is None or fact.concept.periodType != 'duration': continue if context_eop_date != dateunionDate(fact.context.endDatetime, subtractOneDay=True): result_group.append(('{}.2'.format(_CODE_NAME_33), messages.get_message(_CODE_NAME_33), fact.concept.label(), fact, default_dped_fact)) return result_group
def _doc_period_end_date_check(model_xbrl): """ Compares the value of DocumentPeriodEndDate against the end date of its context. If the difference is more than 3 days, fires a validation error. For each DocumentPeriodEndDate, if the above check doesn't fire, check all DEI fact context end dates against it. :param model_xbrl: ModelXbrl to check facts :type model_xbrl: :class:'~arelle.ModelXbrl.ModelXbrl' :return: list of tuples containing bad DocumentPeriodEndDates :rtype: list [tuple] """ dped_facts, dei_facts = _setup_dei_facts(model_xbrl) default_dped_fact = _get_default_dped(dped_facts) result_group = [] if default_dped_fact is None: return result_group not_valid_dped = [] no_dimensions = False # loop through the DocumentPeriodEndDate's to check for # consistent dates for eop_facts in dped_facts.values(): eop_fact = eop_facts[0] eop_context = eop_fact.context if ((not _is_valid_eop_fact(eop_fact) or eop_context is None or eop_context.endDatetime is None)): continue fact_eop_date = dateunionDate(eop_fact.xValue, subtractOneDay=True) # Arelle adjusts context end date to end-of-day midnight # Reverse the adjustment to get the expected date value # by subtracting one day context_eop_date = dateunionDate( eop_context.endDatetime, subtractOneDay=True ) delta = context_eop_date - fact_eop_date if abs(delta.days) > 3: if len(eop_fact.context.segDimValues) != 0: for axis, dim_value in eop_fact.context.segDimValues.items(): if 'LegalEntityAxis' in axis.qname.localName: not_valid_dped.append(dim_value.memberQname.localName) # Handles the case of no dimensions for the DPED fact else: no_dimensions = True result_group.append(( '{}.1'.format(_CODE_NAME_36), messages.get_message(_CODE_NAME_36), context_eop_date, eop_fact, default_dped_fact )) # Don't loop through them if the DPED date is bad, since the date # is incorrect. # loop through the dei facts and compare against their LEA's # DocumentPeriodEndDate for lea_key, fact_group in dei_facts.items(): eop_fact = dped_facts.get(lea_key, default_dped_fact)[0] if ((eop_fact is None or eop_fact.context is None or eop_fact.context.endDatetime is None )): continue # Arelle adjusts context end date to end-of-day midnight # Reverse the adjustment to get the expected date value # by subtracting one day context_eop_date = dateunionDate( eop_fact.context.endDatetime, subtractOneDay=True ) if len(fact_group) > 0: # Check all DEI facts against this DocumentPeriodEndDate. # If the DocumentPeriodEndDate context check doesn't fire, # we will check all dei fact context end dates against it. for fact in fact_group: if ((fact.context is None or fact.context.endDatetime is None or fact.concept.periodType != 'duration' )): continue # If there are no dimensions on the DPED (DQC36) fact and the # fact being checked for DQC33 has no dimensions, we do not # want to fire DQC33 so we go on to the next fact if no_dimensions and len(fact.context.segDimValues) == 0: continue if check_for_lea_member(fact, not_valid_dped): delta = context_eop_date - dateunionDate( fact.context.endDatetime, subtractOneDay=True ) if abs(delta.days) > 3: result_group.append(( '{}.2'.format(_CODE_NAME_33), messages.get_message(_CODE_NAME_33), fact.concept.label(), fact, eop_fact )) return result_group
def _doc_period_end_date_check(model_xbrl): """ Compares the value of DocumentPeriodEndDate against the end date of its context. If the difference is more than 3 days, fires a validation error. For each DocumentPeriodEndDate, if the above check doesn't fire, check all DEI fact context end dates against it. :param model_xbrl: ModelXbrl to check facts :type model_xbrl: :class:'~arelle.ModelXbrl.ModelXbrl' :return: list of tuples containing bad DocumentPeriodEndDates :rtype: list [tuple] """ dped_facts, dei_facts = _setup_dei_facts(model_xbrl) default_dped_fact = _get_default_dped(dped_facts) result_group = [] if default_dped_fact is None: return result_group not_valid_dped = [] # loop through the DocumentPeriodEndDate's to check for # consistent dates for eop_facts in dped_facts.values(): eop_fact = eop_facts[0] eop_context = eop_fact.context if ((not _is_valid_eop_fact(eop_fact) or eop_context is None or eop_context.endDatetime is None)): continue fact_eop_date = dateunionDate(eop_fact.xValue, subtractOneDay=True) # Arelle adjusts context end date to end-of-day midnight # Reverse the adjustment to get the expected date value # by subtracting one day context_eop_date = dateunionDate( eop_context.endDatetime, subtractOneDay=True ) delta = context_eop_date - fact_eop_date if abs(delta.days) > 3: for axis, dim_value in eop_fact.context.segDimValues.items(): if axis.qname.localName == 'LegalEntityAxis': not_valid_dped.append(dim_value.memberQname.localName) result_group.append(( '{}.1'.format(_CODE_NAME_36), messages.get_message(_CODE_NAME_36), context_eop_date, eop_fact, default_dped_fact )) # Don't loop through them if the DPED date is bad, since the date # is incorrect. # loop through the dei facts and compare against their LEA's # DocumentPeriodEndDate for lea_key, fact_group in dei_facts.items(): eop_fact = dped_facts.get(lea_key, default_dped_fact)[0] if ((eop_fact is None or eop_fact.context is None or eop_fact.context.endDatetime is None )): continue # Arelle adjusts context end date to end-of-day midnight # Reverse the adjustment to get the expected date value # by subtracting one day context_eop_date = dateunionDate( eop_fact.context.endDatetime, subtractOneDay=True ) if len(fact_group) > 0: # Check all DEI facts against this DocumentPeriodEndDate. # If the DocumentPeriodEndDate context check doesn't fire, # we will check all dei fact context end dates against it. for fact in fact_group: if ((fact.context is None or fact.context.endDatetime is None or fact.concept.periodType != 'duration' )): continue if check_for_lea_member(fact, not_valid_dped): delta = context_eop_date - dateunionDate( fact.context.endDatetime, subtractOneDay=True ) if delta.days != 0 and abs(delta.days) <= 3: result_group.append(( '{}.2'.format(_CODE_NAME_33), messages.get_message(_CODE_NAME_33), fact.concept.label(), fact, default_dped_fact )) return result_group