private void CheckMissingMandatoryElements(IPluglet currentPluglet, IDocumentFragment currentDocumentFragment) { foreach (IPluglet childPluglet in currentPluglet.Children) { if (childPluglet.IsMandatory == false) { continue; } bool childExist = false; foreach (IDocumentFragment childDocumentFragment in currentDocumentFragment.Children) { if (childDocumentFragment.Pluglet.Tag == childPluglet.Tag) { childExist = true; break; } } EdiErrorType errorType = EdiErrorType.Error; if (childPluglet.IsIgnore) { errorType = EdiErrorType.Warning; } if (childExist == false) { Errors.AddSegmentError(childPluglet.Tag, X12ErrorCode.MandatorySegmentMissingCode , string.Format("{0} : {1}", X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.MandatorySegmentMissingCode), childPluglet.Tag) , CurrentElementNumber, CurrentLinePayloadStart + TotalPayloadLength, CurrentLinePayloadEnd + TotalPayloadLength, errorType); } } }
private IDocumentFragment ConstructNewDocumentFragment(string elementName, IPluglet currentPluglet, IDocumentFragment currentDocumentFragment) { IDocumentFragment newDocumentPluglet = null; IPluglet nextPluglet = null; // Special case for root pluglet if (CurrentElementNumber == 0) { nextPluglet = currentPluglet; string rootNodeName = elementName; int pos = elementName.IndexOf(":"); if (pos != -1) { rootNodeName = elementName.Substring(pos + 1); } if (string.Equals(nextPluglet.Tag, rootNodeName, StringComparison.InvariantCultureIgnoreCase) == false) { Errors.AddSegmentError(elementName, -1, string.Format("Invalid root node name. Expected: {0}, Actual {1}", nextPluglet.Tag, rootNodeName), CurrentElementNumber, CurrentLinePayloadStart + TotalPayloadLength, CurrentLinePayloadEnd + TotalPayloadLength, EdiErrorType.Error); } } else { foreach (IPluglet childPluglet in currentPluglet.Children) { if (string.Equals(childPluglet.Tag, elementName, StringComparison.InvariantCultureIgnoreCase)) { nextPluglet = childPluglet; break; } } } if (nextPluglet == null) { Errors.AddSegmentError(elementName, X12ErrorCode.UnrecognizedSegmentIDCode, X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.UnrecognizedSegmentIDCode), CurrentElementNumber, CurrentLinePayloadStart + TotalPayloadLength, CurrentLinePayloadEnd + TotalPayloadLength, EdiErrorType.Error); // TODO: Should we add 'Unrecognized segment' pluglet here? } else { newDocumentPluglet = new DocumentFragment() { Parent = currentDocumentFragment, Pluglet = nextPluglet, Value = elementName, }; if (currentDocumentFragment.Children == null) { ((DocumentFragment)currentDocumentFragment).Children = new List <IDocumentFragment>(); } currentDocumentFragment.Children.Add(newDocumentPluglet); } return(newDocumentPluglet); }
/// <summary> /// Find corrosponding Pluglet for given segmentname and create new segment /// </summary> /// <param name="segmentName"></param> /// <param name="segmentDetails"></param> private void CreateAndAddNewSegment(string segmentName, string[] segmentDetails) { const string firstSegmentName = "ST"; string errorMsgs = string.Empty; IPluglet nextPluglet; string location = "EDIReader.CreateAndAddNewSegment"; Logger.Debug(location, "Adding {0} segment", segmentName); string missingMandatorySegments; nextPluglet = CurrentPluglet.GetSegmentPluglet(segmentName, segmentDetails, firstSegmentName, out missingMandatorySegments); // First add missing mandatory segment errors if (nextPluglet != null && !string.IsNullOrWhiteSpace(missingMandatorySegments)) { string error = string.Format("Missing mandatory segments ({0}) between {1} and {2}" , missingMandatorySegments, CurrentPluglet.Tag, segmentName); if (FatpipeDocumentInst.Errors == null) { FatpipeDocumentInst.Errors = new List <string>(); } FatpipeDocumentInst.Errors.Add(error); Logger.Error("EDIReader.CreateAndAddNewSegment", EventId.EDIReaderMissingMandatorySegment, "{0} - {1}", GetCurrentPosContext(), error); EdiErrorType errorType = nextPluglet.IsIgnore ? EdiErrorType.Warning : EdiErrorType.Error; foreach (string segment in missingMandatorySegments.Split(',')) { Errors.AddSegmentError(segmentName, X12ErrorCode.MandatorySegmentMissingCode , string.Format("{0} : {1}", X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.MandatorySegmentMissingCode), segment) , SegmentNumber, this.CurrentSegmentStartPos, this.CurrentSegmentEndPos - 1, errorType); } } if (nextPluglet == null) { /* //TODO: Revisit following if condition - do we really want to ignore ISA/GS segment missing in schema? * if (segmentName != "ISA" && segmentName != "GS") * { * errors = string.Format("{0} segment not found in schema after {1}", segmentName, CurrentPluglet.Name); * * Logger.Error(location, EventId.EDIReaderUnknownSegment, "{0} - {1}", GetCurrentPosContext(), errors); * Errors.AddSegmentError(segmentName, X12ErrorCode.UnrecognizedSegmentIDCode * , X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.UnrecognizedSegmentIDCode), SegmentNumber); * } */ //experimenting with unknown here above is actual //IPluglet unknown = new Pluglet("UNRECOGNIZED_SEGMENT", "Unknown Segment", PlugletType.Segment, CurrentPluglet.Parent); IPluglet unknown = new Pluglet( new PlugletInput() { Name = "UNRECOGNIZED_SEGMENT", Definition = "Unknown Segment", Type = PlugletType.Segment, Parent = CurrentPluglet.Parent, IsIgnore = false, AddToParent = false, IsTagSameAsName = true, }); // IPluglet x = new Pluglet("child"+i, "Unknown Data", PlugletType.Data, unknown); //unknown.Children.Add(x); //} //DocumentFragment newFragment = unknown.ConstructDocumentFragment(segmentDetails, false, EDIDelimiters, out errors); errorMsgs = string.Format("{0} segment not found in schema after {1}", segmentName, CurrentPluglet.Name); Errors.AddSegmentError(segmentName, X12ErrorCode.UnrecognizedSegmentIDCode , X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.UnrecognizedSegmentIDCode), SegmentNumber , this.CurrentSegmentStartPos, this.CurrentSegmentEndPos - 1, EdiErrorType.Error); DocumentFragment newFragment = new DocumentFragment() { Pluglet = unknown, Children = new List <IDocumentFragment>(), }; IPluglet childPluglet = new Pluglet("Data", "Data", PlugletType.Data, null); DocumentFragment child = new DocumentFragment() { Parent = newFragment, Pluglet = childPluglet, Children = null, SequenceNumber = SegmentNumber, StartOffset = this.CurrentSegmentStartPos, EndOffset = this.CurrentSegmentEndPos - 1, }; newFragment.Children.Add(child); child.Value = CurrentSegment; if (newFragment == null) { errorMsgs = string.Format("{0} DocumentFragment creation failed. Errors: {1}", segmentName, errorMsgs); Logger.Error(location, EventId.EDIReaderDocFragmentCreation, "{0} - {1}", GetCurrentPosContext(), errorMsgs); //TODO: what should be the code here? //Errors.AddGenericError(segmentName, X12ErrorCode.??? } else { ((DocumentFragment)FatpipeDocumentInst.RootFragment).AddDocumentFragment(newFragment); // CurrentPluglet = newFragment.Pluglet; } //experimenting with unknown here } else { if (nextPluglet.RepetitionInfo.MaxOccurs == 0) { Errors.AddSegmentError(segmentName, X12ErrorCode.UnexpectedSegmentCode , string.Format("{0} : {1}", X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.UnexpectedSegmentCode), nextPluglet.Tag) , SegmentNumber, this.CurrentSegmentStartPos, this.CurrentSegmentEndPos - 1, EdiErrorType.Error); } else { DocumentFragment newFragment = nextPluglet.ConstructDocumentFragment(segmentDetails, false, EDIDelimiters, SegmentNumber, this.CurrentSegmentStartPos, this.CurrentSegmentEndPos - 1, ref errors, out errorMsgs); if (newFragment == null) { //errorMsgs = string.Format("{0} DocumentFragment creation failed. Errors: {1}", segmentName, errorMsgs); Logger.Error(location, EventId.EDIReaderDocFragmentCreation, "{0} - {1}", GetCurrentPosContext(), errorMsgs); // TODO: Replace UnexpectedSegmentCode with appropriate one Errors.AddGenericError(segmentName, X12ErrorCode.UnexpectedSegmentCode, errorMsgs, SegmentNumber, this.CurrentSegmentStartPos, this.CurrentSegmentEndPos); } else { ((DocumentFragment)FatpipeDocumentInst.RootFragment).AddDocumentFragment(newFragment); CurrentPluglet = newFragment.Pluglet; } } } if (!string.IsNullOrEmpty(errorMsgs)) { if (FatpipeDocumentInst.Errors == null) { FatpipeDocumentInst.Errors = new List <string>(); } FatpipeDocumentInst.Errors.Add(errorMsgs); } }
private void ValidateContingencies() { // Assumption: If id data segment is not present then this function will not report error // as we must have already reported that data segment as missing segment earlier Dictionary <string, List <IDocumentFragment> > contingencyOccurances = new Dictionary <string, List <IDocumentFragment> >(); ReadSegmentsWithIdDataTypeChildrens(contingencyOccurances, FatpipeDocumentInst.RootFragment); foreach (string path in contingencyOccurances.Keys) { // Select pluglet for current path // Selecting pluglet from the 1st documentFragment as pluglet will be // same for all documentFragments with same path IDocumentFragment documentFragment = contingencyOccurances[path][0]; IPluglet pluglet = documentFragment.Pluglet; // Pluglet will point to segment, process all child with data type as X12_IdDataType // Filter out non-mandatory data type pluglets foreach (Pluglet child in pluglet.Children) { if (child.PlugletType == PlugletType.Data && child.DataType is X12_IdDataType && child.IsMandatory == true) { List <string> presentValues = GetAllPresentValues(contingencyOccurances[path], child); X12_IdDataType dataType = child.DataType as X12_IdDataType; foreach (string allowedValue in dataType.AllowedValues.Keys) { Contingency contingencies = dataType.GetContingencies(allowedValue); // TODO: Use Ignore flag at id value level // If Id value does not have any contingency then segment with that value must exist if (contingencies == null || contingencies.ContingencyValues.Count == 0) { if (presentValues.Contains(allowedValue) == false && dataType.IsOptionalValue(allowedValue) == false) { Errors.AddSegmentError(pluglet.Tag, X12ErrorCode.DeMandatoryIdValueMissingCode , string.Format("{0} : {1}", X12ErrorCode.GetDataElementErrorDescription(X12ErrorCode.DeMandatoryIdValueMissingCode), allowedValue) , documentFragment.SequenceNumber, documentFragment.StartOffset, documentFragment.EndOffset, EdiErrorType.Error); } } // If Id value has contingencies of type Enumeration then segment with that value or any contingency value must exist else if (contingencies.Type == ContingencyType.Enumeration) { bool valuePresent = presentValues.Contains(allowedValue); if (valuePresent == false) { foreach (string alternateValue in contingencies.ContingencyValues) { valuePresent = presentValues.Contains(alternateValue); if (valuePresent) { break; } } } if (valuePresent == false) { Errors.AddSegmentError(pluglet.Tag, X12ErrorCode.DeMandatoryIdValueOrAlternativeValueMissingCode , string.Format("{0} : {1}", X12ErrorCode.GetDataElementErrorDescription(X12ErrorCode.DeMandatoryIdValueOrAlternativeValueMissingCode), allowedValue) , documentFragment.SequenceNumber, documentFragment.StartOffset, documentFragment.EndOffset, EdiErrorType.Error); } } // If contingency type is cross segment then either both values must exist or both values missing else if (contingencies.Type == ContingencyType.CrossSegment) { // TODO: handle all values in contingencies.ContingencyValues string xPath = contingencies.ContingencyValues[0]; bool currentValuePresent = presentValues.Contains(allowedValue); bool crossSegmentValuePresent = IsCrossSegmentValuePresent(contingencyOccurances, xPath, pluglet.PathSeperator); if (currentValuePresent != crossSegmentValuePresent) { Errors.AddSegmentError(pluglet.Tag, X12ErrorCode.DeCrossSegmentIdValueOccurancesDoesNotMatch , string.Format("{0} : {1} {2}", X12ErrorCode.GetDataElementErrorDescription(X12ErrorCode.DeCrossSegmentIdValueOccurancesDoesNotMatch), allowedValue, xPath) , documentFragment.SequenceNumber, documentFragment.StartOffset, documentFragment.EndOffset, EdiErrorType.Error); } } } } } } }
// Return value indicate if ST segment is valid or not private bool ProcessSTSegment() { string location = "EDIReader.ProcessSTSegment"; string errors = string.Empty; Stopwatch sw = new Stopwatch(); sw.Start(); LastState = EDIState.ST; int currentTransactionSetType; if (CurrentSegmentDetails == null || CurrentSegmentDetails.Length < 2 || int.TryParse(CurrentSegmentDetails[1], out currentTransactionSetType) == false) { InvalidTransactionSetCount++; //TODO: Add error Logger.Error(location, EventId.EDIReaderInvalidSegment, "{0} - Invalid segment - {1}", GetCurrentPosContext(), CurrentSegment); Errors.AddSegmentError(CurrentSegment, X12ErrorCode.UnexpectedSegmentCode , X12ErrorCode.GetStandardSegmentErrorDescription(X12ErrorCode.UnexpectedSegmentCode), SegmentNumber , this.CurrentSegmentStartPos, this.CurrentSegmentEndPos - 1, EdiErrorType.Error); } else { ValidTransactionSetCount++; // TODO: Optimization - Load DocumentPlug, reconstruct ISA and GA segment if transaction set type changed //if (PrevTransactionSetType != currentTransactionSetType) { // Make sure that ISA and GA fields are already present if (ISARecordFields == null || GSRecordFields == null) { throw new EDIReaderException( string.Format("ISA and GA segments should be present before ST segment. {0}", GetCurrentPosContext())); } if (ISARecordFields.Length != MaxISAFieldRecordCount || GSRecordFields.Length == 0) { throw new EDIReaderException( string.Format("ISA and GA segments length ({0}, {1}) does not match expected length ({2}, non-zero). {3}", ISARecordFields.Length, GSRecordFields.Length, MaxISAFieldRecordCount, GetCurrentPosContext())); } //TODO: For testing invoking DocumentPlugFactory.CreateEDIDocumentPlug if (DocumentPlug == null) { if (FPManager == null) { DocumentPlug = DocumentPlugFactory.CreateEDIDocumentPlug(currentTransactionSetType); } else { DocumentPlug = CreateEDIDocumentPlug(currentTransactionSetType, ISARecordFields); } } else // Make sure that DocumentPlug and ST document type match { // DocumentPlug.DocumentType = 0 indicates that there was problem retrieving DocumentType // while constructing DocumentPlug if (DocumentPlug.DocumentType != 0 && DocumentPlug.DocumentType != currentTransactionSetType) { string errorDescription = "Spec Cert relates to document {0}, however ST01 value is {1}.; test File is rejected"; errorDescription = string.Format(errorDescription, DocumentPlug.DocumentType, currentTransactionSetType); FieldError fieldError = DataTypeHelper.GenerateFieldError(X12ErrorCode.DeInvalidCodeValueCode, errorDescription, CurrentSegmentDetails[0]); long currentSegmentFieldStartIndex = this.CurrentSegmentStartPos + 3; // length of "ST<delimiter>" long currentSegmentFieldEndIndex = currentSegmentFieldStartIndex + CurrentSegmentDetails[1].Length - 1; Logger.Error(location, EventId.EDIReaderInvalidTransactionSetType, errorDescription); Errors.AddFieldError(CurrentSegmentDetails[0], "ST01", fieldError.ErrorCode, fieldError.Description, SegmentNumber, 1, CurrentSegmentDetails[1], currentSegmentFieldStartIndex, currentSegmentFieldEndIndex, EdiErrorType.Error); return(false); } } CurrentPluglet = DocumentPlug.RootPluglet; CurrentPluglet.ResetCurrentOccurances(); // Construct start segment list CurrentPluglet.InitializeStartSegmentList(); FatpipeDocumentInst.TransactionSetType = currentTransactionSetType; if (CurrentSegmentDetails.Length > 2) { FatpipeDocumentInst.TransactionNumber = CurrentSegmentDetails[2]; } FatpipeDocumentInst.DocumentPlug = DocumentPlug; FatpipeDocumentInst.RootFragment = CurrentPluglet.ConstructDocumentFragment(null, null); // Construct ISA node //CreateAndAddNewSegment(EDIState.ISA.ToString(), ISARecordFields); // Construct GS node //CreateAndAddNewSegment(EDIState.GS.ToString(), GSRecordFields); //GSSegmentProcessed = true; //GSPluglet = CurrentPluglet; PrevTransactionSetType = currentTransactionSetType; } //else //{ // // Move to GS node to start new segment // CurrentPluglet = GSPluglet; // // Remove previous TransactionSet // if (FatpipeDocumentInst.RootFragment.Children != null) // { // IDocumentFragment transactionSetChild = FatpipeDocumentInst.RootFragment.Children.Any( c => c.Pluglet.Tag == "TransactionSet"); // FatpipeDocumentInst.RootFragment.Children.Remove(transactionSetChild); // } // // Set errors to null // FatpipeDocumentInst.Errors = null; //} // Construct ST node CreateAndAddNewSegment(EDIState.ST.ToString(), CurrentSegmentDetails); } sw.Stop(); Logger.Debug(location, "Stop - {0}. Elapsed time {1} ms", GetCurrentPosContext(), sw.ElapsedMilliseconds); return(true); }