/// <summary> /// Validates all summation concepts found in the current calculation link. /// </summary> /// <param name="CurrentCalculationLink"> /// The calculation link whose containing summation concepts should be validated. /// </param> private void Validate(CalculationLink CurrentCalculationLink) { foreach (SummationConcept CurrentSummationConcept in CurrentCalculationLink.SummationConcepts) { // Validate the main items in the fragment. ValidateSummationConcept(CurrentCalculationLink, CurrentSummationConcept, this.ValidatedFragment.Facts); // Look for any tuples in the fragment and validate their items as well. This action // satisfies tests in the XBRL-CONF-CR3-2007-03-05 conformance suite such as 397.13. foreach (var CurrentFact in this.ValidatedFragment.Facts) { if (CurrentFact is Tuple) { var CurrentTuple = CurrentFact as Tuple; ValidateSummationConcept(CurrentCalculationLink, CurrentSummationConcept, CurrentTuple.Facts); } } } }
/// <summary> /// Validates a given summation concept. /// </summary> /// <param name="CurrentCalculationLink"> /// The calculation link that defines the given summation concept. /// </param> /// <param name="CurrentSummationConcept"> /// The summation concept to be validated. /// </param> /// <param name="FactList"> /// The collection of items that should be searched when looking for summation or contributing items. /// </param> private void ValidateSummationConcept(CalculationLink CurrentCalculationLink, SummationConcept CurrentSummationConcept, FactCollection FactList) { Element SummationConceptElement = LocateElement(CurrentSummationConcept.SummationConceptLocator); Item SummationConceptItem = LocateItem(SummationConceptElement, FactList); // If the summation concept item doesn't exist, then there is no calculation // to perform. if (SummationConceptItem == null) { return; } // If the summation concept item has a "nil" value, then there is no calculation // to perform. if (SummationConceptItem.NilSpecified == true) { return; } double SummationConceptRoundedValue = SummationConceptItem.RoundedValue; double ContributingConceptRoundedValueTotal = 0; var ContributingConceptItemsFound = false; var AtLeastOneItemWithZeroPrecision = false; foreach (Locator CurrentLocator in CurrentSummationConcept.ContributingConceptLocators) { // Some decisions need to be made before the code can actually add the value of the // contributing concept to the total that the code is keeping. var IncludeContributingConceptItemInCalculation = true; // Find the calculation arc for the given calculation link. CalculationArc ContributingConceptCalculationArc = CurrentCalculationLink.GetCalculationArc(CurrentLocator); if (ContributingConceptCalculationArc == null) { IncludeContributingConceptItemInCalculation = false; } // Find the elemement for the given locator. Element ContributingConceptElement = LocateElement(CurrentLocator); if (ContributingConceptElement == null) { IncludeContributingConceptItemInCalculation = false; } // Find all items for the given element. If there is more than one, and at least // one of them is not p-equals with at least one of the other ones, then // the entire calculation validation is forfeit, according to test 397.12 in // the XBRL-CONF-CR3-2007-03-05 conformance suite. var AllMatchingItems = LocateItems(ContributingConceptElement, FactList); if (AllItemsNotPEquals(AllMatchingItems) == false) { return; } // Find the item for the given element. if (AllMatchingItems.Count == 0) { IncludeContributingConceptItemInCalculation = false; } else { foreach (var ContributingConceptItem in AllMatchingItems) { if (IncludeContributingConceptItemInCalculation == true) { IncludeContributingConceptItemInCalculation = ContributingConceptItemEligibleForUseInCalculation(ContributingConceptItem, SummationConceptItem); } if (IncludeContributingConceptItemInCalculation == true) { ContributingConceptItemsFound = true; if ((ContributingConceptItem.PrecisionSpecified == true) && (ContributingConceptItem.Precision == 0) && (ContributingConceptItem.InfinitePrecision == false)) { AtLeastOneItemWithZeroPrecision = true; } double ContributingConceptRoundedValue = ContributingConceptItem.RoundedValue; if (ContributingConceptCalculationArc.Weight != (decimal)(1.0)) { ContributingConceptRoundedValue = ContributingConceptRoundedValue * (double)(ContributingConceptCalculationArc.Weight); } ContributingConceptRoundedValueTotal += ContributingConceptRoundedValue; } } } } if (ContributingConceptItemsFound == true) { if (AtLeastOneItemWithZeroPrecision == true) { var MessageBuilder = new StringBuilder(); string StringFormat = AssemblyResources.GetName("SummationConceptUsesContributingItemWithPrecisionZero"); MessageBuilder.AppendFormat(StringFormat, SummationConceptItem.Name); ValidatedFragment.AddValidationError(new SummationConceptValidationError(CurrentSummationConcept, MessageBuilder.ToString())); return; } ContributingConceptRoundedValueTotal = SummationConceptItem.Round(ContributingConceptRoundedValueTotal); if (SummationConceptRoundedValue != ContributingConceptRoundedValueTotal) { var MessageBuilder = new StringBuilder(); string StringFormat = AssemblyResources.GetName("SummationConceptError"); MessageBuilder.AppendFormat(StringFormat, SummationConceptItem.Name, SummationConceptRoundedValue, ContributingConceptRoundedValueTotal); ValidatedFragment.AddValidationError(new SummationConceptValidationError(CurrentSummationConcept, MessageBuilder.ToString())); return; } } }
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------ internal SummationConcept(CalculationLink link, Locator SummationConceptLocator) { this.Link = link; this.SummationConceptLocator = SummationConceptLocator; this.ContributingConceptLocators = new List<Locator>(); }