/// <summary> /// Creates a list of unique columns based on their segments and scenarios. /// </summary> /// <returns></returns> private List <InstanceReportColumn> GetSegmentScenarioColumnsForSegmentProcessing() { //#1 - this will be our X axis - a set of unique segments and scenarios // It will be our "master" list of columns for the equity report List <InstanceReportColumn> uniqueSegmentScenarioColumns = new List <InstanceReportColumn>(); for (int c = 0; c < this.Columns.Count; c++) { InstanceReportColumn column = this.Columns[c]; bool exists = ReportUtils.Exists(uniqueSegmentScenarioColumns, tmp => { if (!tmp.SegmentAndScenarioEquals(column)) { return(false); } //if( !tmp.CurrencyEquals( column ) ) // return false; return(true); }); if (!exists) { //create a clone so that we can digest this data without affecting other references InstanceReportColumn newColumn = (InstanceReportColumn)column.Clone(); uniqueSegmentScenarioColumns.Add(newColumn); } } return(uniqueSegmentScenarioColumns); }
private void ValidateEquityStructure(string equityMembersXml, out XmlDocument membersXDoc) { membersXDoc = new XmlDocument(); bool hasBeginningBalance = ReportUtils.Exists(this.Rows, row => row.IsBeginningBalance); if (!hasBeginningBalance) { throw new IncompleteEquityException(IncompleteEquityException.ErrorType.MissingBeginningBalance); } bool hasEndingBalance = ReportUtils.Exists(this.Rows, row => row.IsEndingBalance); if (!hasEndingBalance) { throw new IncompleteEquityException(IncompleteEquityException.ErrorType.MissingEndingBalance); } string equityMembersXmlPath = RulesEngineUtils.GetResourcePath(RulesEngineUtils.ReportBuilderFolder.Rules, equityMembersXml); if (!File.Exists(equityMembersXmlPath)) { throw new IncompleteEquityException(IncompleteEquityException.ErrorType.MissingMembersFile); } try { membersXDoc.Load(equityMembersXmlPath); } catch { throw new IncompleteEquityException(IncompleteEquityException.ErrorType.MembersFileFormat); } }
private Dictionary <int, List <InstanceReportColumn> > GetSegmentScenarioCalendars(List <InstanceReportColumn> uniqueSegmentColumns) { Dictionary <int, List <InstanceReportColumn> > calendarsBySegment = new Dictionary <int, List <InstanceReportColumn> >(); foreach (InstanceReportColumn uSegCol in uniqueSegmentColumns) { List <InstanceReportColumn> uniqueCalendars = new List <InstanceReportColumn>(); foreach (InstanceReportColumn anyCol in this.Columns) { if (!uSegCol.SegmentAndScenarioEquals(anyCol)) { continue; } if (!ReportUtils.Exists(uniqueCalendars, uCal => uCal.ReportingPeriodEquals(anyCol))) { //create a clone so that we can slowly digest this data without affecting other references InstanceReportColumn clone = (InstanceReportColumn)anyCol.Clone(); uniqueCalendars.Add(clone); } } if (uniqueCalendars.Count > 0) { calendarsBySegment[uSegCol.Id] = uniqueCalendars; } } return(calendarsBySegment); }
/// <summary> /// Determine if the other units within this instance are custom. /// </summary> /// <returns>A <see cref="bool"/> indicating if any of the other units /// are custom.</returns> public bool HasCustomUnits() { if (this.OtherUnits == null) { return(false); } return(ReportUtils.Exists(this.OtherUnits, InstanceReportColumn.IsCustomUnit)); }
private static bool DoCalendarsOverlap(Dictionary <int, List <InstanceReportColumn> > calendarsBySegment, out List <InstanceReportColumn> allCalendars) { allCalendars = new List <InstanceReportColumn>(); bool contains = true; foreach (KeyValuePair <int, List <InstanceReportColumn> > kvpCalendars in calendarsBySegment) { contains = true; foreach (KeyValuePair <int, List <InstanceReportColumn> > kvpMatches in calendarsBySegment) { if (int.Equals(kvpCalendars.Key, kvpMatches.Key)) { continue; } foreach (InstanceReportColumn match in kvpMatches.Value) { contains = ReportUtils.Exists(kvpCalendars.Value, cal => ContainsCalendar(cal, match, false, false)); if (!contains) { break; } } if (!contains) { break; } } if (contains) { allCalendars = kvpCalendars.Value; break; } } if (!contains) { return(false); } allCalendars.ForEach( cal => { foreach (Segment seg in cal.Segments) { cal.Labels.RemoveAll(ll => ll.Label == seg.ValueName); } cal.Segments = new ArrayList(); }); return(true); }
public bool HasPerShare() { if (this.MCU == null || this.MCU.UPS == null || this.MCU.UPS.Count == 0) { return(false); } if (ReportUtils.Exists(this.MCU.UPS, IsEPSUnit)) { return(true); } return(false); }
public bool HasMonetary() { if (this.MCU == null || this.MCU.UPS == null || this.MCU.UPS.Count == 0) { return(false); } if (ReportUtils.Exists(this.MCU.UPS, IsMonetaryUnit)) { return(true); } return(false); }
public bool HasExchangeRate() { if (this.MCU == null || this.MCU.UPS == null || this.MCU.UPS.Count == 0) { return(false); } if (ReportUtils.Exists(this.MCU.UPS, IsExchangeRateUnit)) { return(true); } return(false); }
public bool IsDimensionMatch(ColumnRowRequirement columnRowRequirement) { foreach (Segment mySeg in this.Segments) { bool dimensionExists = ReportUtils.Exists(columnRowRequirement.Segments, iSeg => string.Equals(mySeg.DimensionInfo.dimensionId, iSeg.DimensionInfo.dimensionId)); if (!dimensionExists) { return(false); } } return(true); }
/// <summary> /// Load the calendar columns from the base report. /// </summary> /// <param name="baseReport">The base report to load calendar items /// from.</param> public void LoadCalendarColumns(InstanceReport baseReport) { List <InstanceReportColumn> uniqueCalendars = new List <InstanceReportColumn>(); foreach (InstanceReportColumn baseCol in baseReport.Columns) { if (!ReportUtils.Exists(uniqueCalendars, col => col.ReportingPeriodEquals(baseCol))) { //create a clone so that we can slowly digest this data without affecting other references InstanceReportColumn newCol = (InstanceReportColumn)baseCol.Clone(); uniqueCalendars.Add(newCol); } } uniqueCalendars.Sort(InstanceReport.CompareCalendars); this.DurationCalendars = new List <InstanceReportColumn>(uniqueCalendars); this.InstantCalendars = SplitCalendars(uniqueCalendars); }
//TODO make private public void AddOtherUnits(params UnitProperty[] upList) { foreach (UnitProperty up in upList) { if (this.UnderlyingUnitProperty != null && string.Equals(this.UnitID, up.UnitID)) { continue; } if (this.OtherUnits == null) { this.OtherUnits = new List <UnitProperty>(); } else if (this.OtherUnits.Count > 0) { if (ReportUtils.Exists(this.OtherUnits, ou => string.Equals(ou.UnitID, up.UnitID))) { continue; } } this.OtherUnits.Add(up); } }
private void ProcessColumnMaps(List <ColumnInstantDurationMap> columnMaps) { //Merge columns in the column map if (columnMaps == null || columnMaps.Count == 0) { return; } ProcessMissingMapsMultiCurrency(columnMaps); //ANY columns that appear in our column map have been approved for merging //THEREFORE we will merge the units from the instant into the duration columnMaps.ForEach( (colMap) => { InstanceReportColumn ircDuration = this.Columns[colMap.DurationColumnIndex] as InstanceReportColumn; InstanceReportColumn ircInstant = this.Columns[colMap.InstantColumnIndex] as InstanceReportColumn; //If the merged column does not have a currency, apply the currency and the currency label if (string.IsNullOrEmpty(ircDuration.CurrencyCode) && !string.IsNullOrEmpty(ircInstant.CurrencyCode)) { ircDuration.CurrencyCode = ircInstant.CurrencyCode; ircDuration.CurrencySymbol = ircInstant.CurrencySymbol; //we MIGHT need to apply the unit label to the duration column LabelLine llCurrency = ircInstant.Labels[ircInstant.Labels.Count - 1]; if (llCurrency.Label.StartsWith(ircInstant.CurrencyCode) && llCurrency.Label.Contains(ircInstant.CurrencySymbol)) { ircDuration.Labels.Add(llCurrency); } } //Merge all units ircInstant.MCU.UPS.ForEach( (iUP) => { bool durationAlreadyHasUnitID = ReportUtils.Exists(ircDuration.MCU.UPS, (dUP) => { bool idMatches = dUP.UnitID == iUP.UnitID; return(idMatches); }); if (!durationAlreadyHasUnitID) { ircDuration.MCU.UPS.Add(iUP); } } ); } ); //Do not allow destination columns to be deleted Dictionary <int, bool> destinationColumns = new Dictionary <int, bool>(); //Only try to delete "source" columns Dictionary <int, Dictionary <string, bool> > sourceColumns = new Dictionary <int, Dictionary <string, bool> >(); //we don't want to remove these - retain them so that 'ProcessBeginningEndingBalance' has some work to do List <ColumnInstantDurationMap> bbMaps = new List <ColumnInstantDurationMap>(); List <ColumnInstantDurationMap> otherMaps = new List <ColumnInstantDurationMap>(); foreach (ColumnInstantDurationMap colMap in columnMaps) { InstanceReportColumn ircInstant = this.Columns[colMap.InstantColumnIndex] as InstanceReportColumn; InstanceReportColumn ircDuration = this.Columns[colMap.DurationColumnIndex] as InstanceReportColumn; //is this a beginning balance column mapping? if (ircInstant.MCU.contextRef.PeriodStartDate == ircDuration.MCU.contextRef.PeriodStartDate.AddDays(-1) || ircInstant.MCU.contextRef.PeriodStartDate == ircDuration.MCU.contextRef.PeriodStartDate) { bbMaps.Add(colMap); } else { otherMaps.Add(colMap); } } Dictionary <int, bool> columnsMapped = new Dictionary <int, bool>(); //For each map, go through the rows and switch the colID foreach (InstanceReportRow irr in this.Rows) { if (irr.IsBeginningBalance) { ProcessMapsOnRow(irr, bbMaps, destinationColumns, sourceColumns); } else { ProcessMapsOnRow(irr, otherMaps, destinationColumns, sourceColumns); } } //Get a SORTED list of all columns to remove List <int> columnsToRemove = new List <int>(); foreach (int col in sourceColumns.Keys) { if (destinationColumns.ContainsKey(col)) { continue; } if (columnsToRemove.Contains(col)) { continue; } int populatedCells = this.CountColumnPopulatedElements(col); if (populatedCells <= sourceColumns[col].Count) { columnsToRemove.Add(col); } else { Dictionary <string, bool> elementLookup = sourceColumns[col]; foreach (InstanceReportRow row in this.Rows) { if (!elementLookup.ContainsKey(row.ElementName)) { continue; } ((Cell)row.Cells[col]).Clear(); } } } columnsToRemove.Sort(); //Remove columns for (int index = columnsToRemove.Count - 1; index >= 0; index--) { this.RemoveColumn(columnsToRemove[index]); } this.SynchronizeGrid(); }
public bool HasNonBalanceRows() { bool hasNonBalanceRows = ReportUtils.Exists(this.Rows, row => !(row.IsCalendarTitle || row.IsAbstractGroupTitle)); return(hasNonBalanceRows); }
public bool HasCustomUnits() { return(ReportUtils.Exists(this.Units, InstanceReportColumn.IsCustomUnit)); }
/// <summary> /// Creates and saves a list of unique columns based on their segments and scenarios. /// </summary> /// <param name="baseReport">The base report to load segment scenarios /// from.</param> public void LoadSegmentScenarioColumns(InstanceReport baseReport) { Dictionary <string, Segment> uniqueAdjustments = new Dictionary <string, Segment>(); Dictionary <string, Segment> uniquePrevious = new Dictionary <string, Segment>(); List <InstanceReportColumn> consolidatedColumns = new List <InstanceReportColumn>(); List <InstanceReportColumn> uniqueSegmentColumns = new List <InstanceReportColumn>(); foreach (InstanceReportColumn baseColumn in baseReport.Columns) { //create a clone so that we can digest this data without affecting other references InstanceReportColumn clone = (InstanceReportColumn)baseColumn.Clone(); int index; if (clone.IsAdjusted(this.AdjustedAndPRMemberLookup, out index)) { Segment seg = (Segment)clone.Segments[index]; uniqueAdjustments[seg.DimensionInfo.dimensionId] = seg; clone.RemoveAdjustedPreviouslyReported(this.AdjustedAndPRMemberLookup); clone.RemoveMissingSegmentLabels(); } else if (clone.IsAsPreviouslyReported(this.AdjustedAndPRMemberLookup, out index)) { Segment seg = (Segment)clone.Segments[index]; uniquePrevious[seg.DimensionInfo.dimensionId] = seg; clone.RemoveAdjustedPreviouslyReported(this.AdjustedAndPRMemberLookup); clone.RemoveMissingSegmentLabels(); } bool exists = ReportUtils.Exists(uniqueSegmentColumns, tmp => { if (!tmp.SegmentAndScenarioEquals(clone)) { return(false); } if (!tmp.CurrencyEquals(clone)) { return(false); } return(true); }); if (!exists) { if (clone.Segments == null || clone.Segments.Count == 0) { consolidatedColumns.Add(clone); } uniqueSegmentColumns.Add(clone); } } if (consolidatedColumns != null && consolidatedColumns.Count > 0) { foreach (InstanceReportColumn cCol in consolidatedColumns) { uniqueSegmentColumns.Remove(cCol); uniqueSegmentColumns.Add(cCol); cCol.Labels[0].Label = InstanceReport.EQUITY_TOTAL_HEADER; } } this.EquityCandidate.Columns.AddRange(uniqueSegmentColumns); //now clean off the calendars this.SegmentColumns.ForEach(col => col.ClearReportingPeriod()); //and sort according to presentation this.SegmentColumns.Sort(baseReport.CompareSegments); this.AdjustmentMembers = new List <Segment>(uniqueAdjustments.Values); this.PreviousMembers = new List <Segment>(uniquePrevious.Values); }
public static bool AreSameExceptCurrency(ColumnRowRequirement thisRow, ColumnRowRequirement nextRow) { if (thisRow.ElementKey != nextRow.ElementKey) { return(false); } if (thisRow.PeriodLabel != nextRow.PeriodLabel) { return(false); } bool nextIsEmpty = nextRow.Segments == null || nextRow.Segments.Count == 0; if (thisRow.Segments == null || thisRow.Segments.Count == 0) { if (nextIsEmpty) { return(true); } else { return(false); } } else if (nextIsEmpty) { return(false); } if (thisRow.Segments.Count != nextRow.Segments.Count) { return(false); } foreach (Segment iSeg in thisRow.Segments) { bool found = ReportUtils.Exists(nextRow.Segments, oSeg => { if (iSeg.DimensionInfo.dimensionId != oSeg.DimensionInfo.dimensionId) { return(false); } if (iSeg.DimensionInfo.Id != oSeg.DimensionInfo.Id) { return(false); } return(true); }); if (!found) { return(false); } } return(true); }
public bool ProcessSegments_Rule(BooleanWrapper processed) { //collect all of the segments to be permuted vertically List <InstanceReportColumn> uniqueSegmentColumns = this.GetSegmentScenarioColumnsForSegmentProcessing(); //if( uniqueSegmentColumns.Count < 2 ) // return false; //collect all of the calendars to be retained horizontally Dictionary <int, List <InstanceReportColumn> > calendarsBySegment = this.GetSegmentScenarioCalendars(uniqueSegmentColumns); //if( uniqueSegmentColumns.Count < 2 ) // return false; //find the set of `allCalendars` which will hold all data without any adjustment List <InstanceReportColumn> allCalendars; bool doCalendarsOverlap = DoCalendarsOverlap(calendarsBySegment, out allCalendars); if (!doCalendarsOverlap) { return(false); } List <Segment> commonSegmentsToPromote = GetCommonSegments(uniqueSegmentColumns); PromoteConsolidatedSegment(uniqueSegmentColumns, commonSegmentsToPromote); //set up a temporary holder for the rows - this helps with debugging InstanceReport segmentCandidate = new InstanceReport(); segmentCandidate.Columns.AddRange(allCalendars); //The first row in every report is usually `IsReportTitle` - copy it to the temporary report InstanceReportRow reportTitleRow = this.FindCloneAndTruncate(row => row.IsReportTitle, allCalendars.Count); if (reportTitleRow != null) { reportTitleRow.Id = 0; segmentCandidate.Rows.Add(reportTitleRow); } //Now, for every `segmentSet`, rebuild the data vertically foreach (InstanceReportColumn segmentSet in uniqueSegmentColumns) { //If this segment set has segments, create an `IsSegmentTitle` row if (segmentSet.Segments != null && segmentSet.Segments.Count > 0) { string label = string.Empty; foreach (Segment seg in segmentSet.Segments) { if (commonSegmentsToPromote != null && commonSegmentsToPromote.Count > 0) { bool isCommon = ReportUtils.Exists(commonSegmentsToPromote, cSeg => cSeg.Equals(seg)); if (isCommon) { continue; } } if (!string.IsNullOrEmpty(label)) { label += " | "; } label += seg.ValueName; } if (!string.IsNullOrEmpty(label)) { InstanceReportRow segmentRow = new InstanceReportRow(label, allCalendars.Count); segmentRow.IsSegmentTitle = true; segmentRow.Id = segmentCandidate.Rows.Count; segmentRow.OriginalInstanceReportColumn = (InstanceReportColumn)segmentSet.Clone(); segmentCandidate.Rows.Add(segmentRow); } } //`segmentSets` combined with `rows` provide our vertical (y) axis //for each row in the "base" report, we need to pull in the data InstanceReportRow lastAbstract = null; foreach (InstanceReportRow row in this.Rows) { if (row.IsReportTitle) { continue; } //retain abstracts... if (row.IsAbstractGroupTitle) { //...unless they're consecutive - retain the most recent one if (lastAbstract != null) { int at = segmentCandidate.Rows.IndexOf(lastAbstract); if (at == segmentCandidate.Rows.Count - 1) { segmentCandidate.Rows.RemoveAt(at); } } InstanceReportRow abstractRow = CloneAndTruncate(row, allCalendars.Count); abstractRow.Id = segmentCandidate.Rows.Count; segmentCandidate.Rows.Add(abstractRow); lastAbstract = abstractRow; continue; } //`calendars` provide our horizontal (x) axis //`calendars` (x) combined with `segmentSets` & `rows` (y) allow us to look up the correct cell bool hasData = false; InstanceReportRow currentRow = new InstanceReportRow(); foreach (InstanceReportColumn calendar in allCalendars) { List <InstanceReportColumn> matches = this.GetMatchingColumns(calendar, segmentSet, row); //apply exact match InstanceReportColumn exactColumn = matches.Find(m => m.ReportingPeriodEquals(calendar)); if (exactColumn != null) { Cell exactCell = row.Cells.Find(c => c.Id == exactColumn.Id); if (exactCell != null && exactCell.HasData) { hasData = true; Cell newCell = (Cell)exactCell.Clone(); newCell.EmbeddedReport = exactCell.EmbeddedReport; if (!string.IsNullOrEmpty(segmentSet.CurrencyCode)) { if ((int)row.Unit == (int)UnitType.Monetary || (int)row.Unit == (int)UnitType.EPS) { newCell.CurrencyCode = segmentSet.CurrencyCode; newCell.CurrencySymbol = segmentSet.CurrencySymbol; } } currentRow.Cells.Add(newCell); continue; } } //apply similar matches { List <Cell> cells = matches.ConvertAll(col => row.Cells.Find(c => c.Id == col.Id)); //Now reduce our cells to those with values... cells.RemoveAll(c => c == null || !c.HasData); //...and non-duplicates for (int c = 0; c < cells.Count; c++) { Cell curCell = cells[c]; cells.RemoveAll(cell => cell.Id != curCell.Id && cell.NumericAmount == curCell.NumericAmount); } switch (cells.Count) { case 0: Cell emptyCell = new Cell(); currentRow.Cells.Add(emptyCell); break; case 1: hasData = true; Cell newCell = (Cell)cells[0].Clone(); newCell.EmbeddedReport = cells[0].EmbeddedReport; if (!string.IsNullOrEmpty(segmentSet.CurrencyCode)) { if ((int)row.Unit == (int)UnitType.Monetary || (int)row.Unit == (int)UnitType.EPS) { newCell.CurrencyCode = segmentSet.CurrencyCode; newCell.CurrencySymbol = segmentSet.CurrencySymbol; } } currentRow.Cells.Add(newCell); break; default: Debug.Assert(false, "Too many cells"); break; } } } //if we actually found data for this row, let's clone the original, and swap out the cells if (hasData) { InstanceReportRow clonedRow = (InstanceReportRow)row.Clone(false, false); clonedRow.Cells.AddRange(currentRow.Cells); clonedRow.Id = segmentCandidate.Rows.Count; segmentCandidate.Rows.Add(clonedRow); } } //Same as above, don't preserve consecutive abstract rows if (lastAbstract != null) { int at = segmentCandidate.Rows.IndexOf(lastAbstract); if (at == segmentCandidate.Rows.Count - 1) { segmentCandidate.Rows.RemoveAt(at); } } } //now that the permutation is complete, apply the new rows and columns to the "base" report this.Columns.Clear(); this.Columns.AddRange(segmentCandidate.Columns); this.Rows.Clear(); this.Rows.AddRange(segmentCandidate.Rows); this.SynchronizeGrid(); //this.InstantValues(); processed.Value = true; return(true); }
/// <summary> /// Go thorugh each column to determine if the columns should be removed -- /// if all elements (that have data) in the columns can be found in other reports then consider this a flow thru column and delete it. /// For "disclosures", if one element or one dimension member s unique, do remove ANY columns from the disclosure /// </summary> /// <param name="rh"></param> /// <param name="inUseElements"></param> /// <param name="inUseSegments"></param> private void CleanupColumns(ReportHeader rh, Dictionary <string, int> inUseElements, Dictionary <string, int> inUseSegments) { string filePath = Path.Combine(this.currentReportDirectory, rh.XmlFileName); InstanceReport report = InstanceReport.LoadXml(filePath); if (report == null) { return; } List <InstanceReportColumn> columnsToRemove = new List <InstanceReportColumn>(); List <InstanceReportRow> uniqueRows = report.Rows.FindAll( row => { if (string.IsNullOrEmpty(row.ElementName)) { return(false); } if (row.IsEmpty()) { return(false); } if (inUseElements.ContainsKey(row.ElementName)) { return(false); } return(true); }); bool hasAnyUniqeRows = uniqueRows.Count > 0; for (int c = 0; c < report.Columns.Count; c++) { InstanceReportColumn col = report.Columns[c]; bool columnHasUniqueSegments = false; bool columnHasUniqueCells = ReportUtils.Exists(uniqueRows, row => row.Cells[c].HasData); if (!columnHasUniqueCells) //this column might need to be removed { Dictionary <string, int> colSegments = report.GetUniqueInUseSegments(col); foreach (string key in colSegments.Keys) { if (!inUseSegments.ContainsKey(key)) { columnHasUniqueSegments = true; break; } } } if (!(columnHasUniqueCells || columnHasUniqueSegments)) { columnsToRemove.Add(col); } } if (columnsToRemove.Count > 0 && columnsToRemove.Count < report.Columns.Count) { foreach (InstanceReportColumn col in columnsToRemove) { col.RemoveSelf(report); } if (report.Columns.Count > 1) { report.PromoteSharedColumnLabelsAfterRemoveFlowThroughColumns(); } report.BuildXMLDocument(filePath, false, false, this.currentFilingSummary); } }