public static void AddTransactionSetDetails(this InterchangeErrors errors, int tsNumber, string idCode, string ctrlNumber, bool updateExisting) { TransactionSetErrors transactionSetErrors = new TransactionSetErrors(tsNumber, idCode, ctrlNumber, new EdiSectionErrors()); FunctionalGroupErrors functionalGroupErrors; if (errors.FunctionalGroupErrors.Count == 0) { // TODO: Handle this error condition properly - Need to consider scenario where ST segment appear before GS // this should be error since TransactionSetDetails should be added only after functionalGroup functionalGroupErrors = errors.CreateNewFunctionalGroupErrorInfo(-1, "---", "----"); } else { functionalGroupErrors = errors.FunctionalGroupErrors.Last(); } if (functionalGroupErrors.TransactionSetErrors.Count > 0 && updateExisting == true) { functionalGroupErrors.TransactionSetErrors.Clear(); } functionalGroupErrors.TransactionSetErrors.Add(transactionSetErrors); }
public static void AddFunctionalGroupDetails(this InterchangeErrors errors, int groupNumber, string idCode, string ctrlNumber, bool updateExisting) { FunctionalGroupErrors functionalGroupErrors = new FunctionalGroupErrors(groupNumber, idCode, ctrlNumber); if (errors.FunctionalGroupErrors.Count > 0 && updateExisting == true) { errors.FunctionalGroupErrors.Clear(); } errors.FunctionalGroupErrors.Add(functionalGroupErrors); }
public static void AddGenericError(this InterchangeErrors errors, string segmentName, int errorCode, string errorDescription) { if (errors == null) { throw new ArgumentNullException("errors"); } GenericError genericError = new GenericError(errorCode, errorDescription, segmentName); EdiSectionErrors ediSectionErrors = GetEdiSectionErrors(errors, segmentName); ediSectionErrors.GenericErrorList.Add(genericError); }
public static void AddSegmentError(this InterchangeErrors errors, string segmentName, int errorCode, string errorDescription, int segmentNumber) { if (errors == null) { throw new ArgumentNullException("errors"); } string explicitLoopId = ""; SegmentError segmentError = new SegmentError(segmentName, segmentNumber, errorCode, errorDescription, explicitLoopId); EdiSectionErrors ediSectionErrors = GetEdiSectionErrors(errors, segmentName); ediSectionErrors.SegmentErrorList.Add(segmentError); }
private static EdiSectionErrors GetEdiSectionErrors(InterchangeErrors errors, string segmentName) { EdiSectionErrors ediSectionErrors; switch (segmentName.ToUpper()) { case "ISA": case "IEA": ediSectionErrors = errors.IsaIeaErrorList; break; case "GS": case "GE": // FunctionalGroupErrors will have at least 1 element when GS segment is parsed. // If we encounter error during GS segment itself then add error in ISaIeaErrorList if (errors.FunctionalGroupErrors.Count == 0) { ediSectionErrors = errors.IsaIeaErrorList; } else { ediSectionErrors = errors.FunctionalGroupErrors.Last().GsGeErrorList; } break; default: // FunctionalGroupErrors will have at least 1 element when GS segment is parsed. // Similararly TransactionSetErrors will have at least 1 element when ST segment is parsed. // If we encounter error during any segment and then check the order in reverse way if (errors.FunctionalGroupErrors.Count == 0) { ediSectionErrors = errors.IsaIeaErrorList; } else if (errors.FunctionalGroupErrors.Last().TransactionSetErrors.Count == 0) { ediSectionErrors = errors.FunctionalGroupErrors.Last().GsGeErrorList; } else { ediSectionErrors = errors.FunctionalGroupErrors.Last().TransactionSetErrors.Last().TsErrorList; } break; } return(ediSectionErrors); }
public static void AddFieldError(this InterchangeErrors errors, string segmentName, int errorCode, string errorDescription, int positionInSegment, string fieldValue) { int positionInField = -1; int repetitionCount = 0; string refDesignator = ""; if (errors == null) { throw new ArgumentNullException("errors"); } FieldError fieldError = new FieldError(positionInSegment, positionInField, repetitionCount, errorCode, errorDescription, fieldValue, refDesignator); EdiSectionErrors ediSectionErrors = GetEdiSectionErrors(errors, segmentName); ediSectionErrors.FieldErrorList.Add(fieldError); }
public static List <SegmentValidationResult> GetSegmentValidationResults(this InterchangeErrors ediErrors) { List <SegmentValidationResult> segmentValidationResults = new List <SegmentValidationResult>(); if (ediErrors != null && ediErrors.Count > 0) { if (ediErrors.IsaIeaErrorList != null && ediErrors.IsaIeaErrorList.Count > 0) { segmentValidationResults.AddRange(ediErrors.IsaIeaErrorList.GetSegmentValidationResults()); } if (ediErrors.FunctionalGroupErrors != null && ediErrors.FunctionalGroupErrors.Count > 0) { foreach (FunctionalGroupErrors functionalGroupErrors in ediErrors.FunctionalGroupErrors) { if (functionalGroupErrors.GsGeErrorList != null && functionalGroupErrors.GsGeErrorList.Count > 0) { segmentValidationResults.AddRange(functionalGroupErrors.GsGeErrorList.GetSegmentValidationResults()); } if (functionalGroupErrors.TransactionSetErrors != null && functionalGroupErrors.TransactionSetErrors.Count > 0) { foreach (TransactionSetErrors transactionSetErrors in functionalGroupErrors.TransactionSetErrors) { if (transactionSetErrors.TsErrorList != null && transactionSetErrors.TsErrorList.Count > 0) { segmentValidationResults.AddRange(transactionSetErrors.TsErrorList.GetSegmentValidationResults()); } } } } } } return(segmentValidationResults); }
/// <summary> /// Read xml file and construct IFatpipeDocument. /// Xml file reader will traverse Xml files and for each element /// match it with current pluglet. If match fails then it tries to /// find matching pluglet (similar to X12). /// </summary> /// <returns></returns> public IFatpipeDocument ReadFile(Stream xmlFileStream, IDocumentPlug documentPlug) { if (xmlFileStream == null) { throw new ArgumentNullException("xmlFileStream", "Xml file stream cannot be null"); } if (documentPlug == null) { throw new ArgumentNullException("documentPlug", "Document plug cannot be null"); } string location = "XmlFileReader.ReadFile"; Logger.Debug(location, "Start"); BeautifiedOriginalPayload = string.Empty; CurrentElementNumber = 0; TotalPayloadLength = 0; CurrentLinePayloadStart = 0; CurrentLinePayloadEnd = 0; CurrentLevel = 0; Stopwatch sw = new Stopwatch(); sw.Start(); errors = new InterchangeErrors(); // Since xml file doesn't have concept of ST/SE, ans we want to use InterchangeErrors for reporting purpose // create dummy transaction set details Errors.AddTransactionSetDetails(1, "", "", true); IPluglet currentPluglet = documentPlug.RootPluglet; currentPluglet.ResetCurrentOccurances(); currentPluglet.InitializeStartSegmentList(); FatpipeDocumentInst = new FatpipeDocument(); FatpipeDocumentInst.DocumentPlug = documentPlug; FatpipeDocumentInst.RootFragment = currentPluglet.ConstructDocumentFragment(null, null); IDocumentFragment currentDocumentFragment = FatpipeDocumentInst.RootFragment; IDocumentFragment newDocumentFragment = null; bool isLeafNode = false; try { XmlTextReader xmlReader = new XmlTextReader(xmlFileStream); // If some element doesn't match document plutlet then stop // TODO: Should we try to match other elements? If yes, which pluglet to start with? // Also we need to ignore this entire element bool stopProcessing = false; while (xmlReader.Read()) { switch (xmlReader.NodeType) { case XmlNodeType.Element: isLeafNode = false; AddStartElementToPayload(xmlReader.Name, xmlReader.IsEmptyElement); if (xmlReader.IsEmptyElement) { break; } if (stopProcessing == false) { currentDocumentFragment = ConstructNewDocumentFragment(xmlReader.Name, currentPluglet, currentDocumentFragment); } // If some element doesn't match document plutlet then stop // TODO: Should we try to match other elements? If yes, which pluglet to start with? // Also we need to ignore this entire element if (currentDocumentFragment == null) { stopProcessing = true; } else { currentPluglet = currentDocumentFragment.Pluglet; } CurrentLevel++; CurrentElementNumber++; break; case XmlNodeType.Text: isLeafNode = true; AddValueToPayload(xmlReader.Value); if (stopProcessing == false) { currentDocumentFragment.Value = xmlReader.Value; } // Assumption: Leaf nodes are on same line and non-leaf nodes are 1-per line (separate line for start and end element) // If this assumption is wrong then we can construct the xml in string format to match fulfill above assumption // and then Ux can use this string version of xml to highlight the errors. CurrentElementNumber--; // Decrement since leaf level elements are one line, so we need to increment element on endElement only. break; case XmlNodeType.EndElement: CurrentLevel--; AddEndElementToPayload(xmlReader.Name, isLeafNode); if (stopProcessing == false) { // Check if all mandatory segments were present CheckMissingMandatoryElements(currentPluglet, currentDocumentFragment); currentDocumentFragment = currentDocumentFragment.Parent; currentPluglet = currentPluglet.Parent; } CurrentElementNumber++; isLeafNode = false; break; default: break; } } } catch (XmlException xmlException) { // TODO: Pass start and end postition Errors.AddGenericError(currentPluglet == null ? "N/A" : currentPluglet.Name, X12ErrorCode.UnexpectedSegmentCode, string.Format("Error parsing XML document: {0}", xmlException.Message), CurrentElementNumber / 2, CurrentLinePayloadStart + TotalPayloadLength, CurrentLinePayloadEnd + TotalPayloadLength); } catch (Exception exception) { // TODO: Pass start and end postition (for all Errors.Add* calls) in this file. Errors.AddGenericError(currentPluglet == null ? "N/A" : currentPluglet.Name, X12ErrorCode.UnexpectedSegmentCode, "Internal error occurred, please contact Maarg", CurrentElementNumber / 2, CurrentLinePayloadStart + TotalPayloadLength, CurrentLinePayloadEnd + TotalPayloadLength); Logger.Error(location, EventId.XmlReaderUnhandledException, "Error occured during xml file processing: {0}", exception.ToString()); } FatpipeDocumentInst.BeautifiedOriginalPayloadBody = BeautifiedOriginalPayload; sw.Stop(); Logger.Debug(location, "Stop - Elapsed time {0} ms", sw.ElapsedMilliseconds); return(FatpipeDocumentInst); }
/// <summary> /// Initialize EDIReader with a stream. Verify that stream contains EDI document (ISA segment). /// </summary> /// <param name="stream"></param> /// <param name="fatpipeManager"></param> /// <param name="documentPlug"></param> /// <returns>true if EDI document otherwise false</returns> public bool Initialize(Stream stream, IFatpipeManager fatpipeManager, IDocumentPlug documentPlug) { if (stream == null) { throw new ArgumentNullException("stream"); } Stopwatch sw = new Stopwatch(); sw.Start(); Errors = new InterchangeErrors(); FPManager = fatpipeManager; DocumentPlug = documentPlug; long orgStartPos = stream.Position; Delimiters delimiters; InterchangeTokenizer tokenizer = new InterchangeTokenizer(stream); bool isValidEDIDocument = tokenizer.IsX12Interchange(out delimiters); FunctionalGroupNumber = TransactionSetNumber = SegmentNumberFromStart = SegmentNumber = 0; ValidTransactionSetCount = InvalidTransactionSetCount = 0; PrevTransactionSetType = 0; DocumentReader = null; if (isValidEDIDocument == true) { EDIDelimiters = delimiters; //TODO: Review following logic //Read ISA field till component separator - Do not include component separator ISASegment = tokenizer.ISARecord.Substring(0, tokenizer.ISARecord.IndexOf((char)EDIDelimiters.ComponentSeperator) + 1); //TODO: Suraj: confirm this special case - last value as data element separator ISARecordFields = ISASegment.Split((char)EDIDelimiters.FieldSeperator); SegmentNumberFromStart = 1; stream.Position = orgStartPos; this.DocumentReader = new StreamReader(stream, Encoding.UTF8); //TODO: Why is seek required here? this.CurrentSegmentStartPos = 0; this.CurrentSegmentEndPos = 0; //this.CurrentSegmentEndPos = this.CurrentSegmentStartPos + tokenizer.ISARecordLen - 1; //this.DocumentReader.BaseStream.Seek(this.CurrentSegmentEndPos + basePosition, SeekOrigin.Begin); FatpipeDocumentInst = new FatpipeDocument(); FatpipeDocumentInst.BeautifiedOriginalPayloadStartHeader = string.Empty; FatpipeDocumentInst.BeautifiedOriginalPayloadBody = string.Empty; FatpipeDocumentInst.BeautifiedOriginalPayloadEndHeader = string.Empty; SegmentDelimiter = ((char)EDIDelimiters.SegmentDelimiter).ToString(); FormattedSegmentDelimiter = SegmentDelimiter; bool crLFPresent = delimiters.SegmentDelimiter == Delimiters.CarriageReturn || delimiters.SegmentDelimiterSuffix1 == Delimiters.CarriageReturn; if (!crLFPresent) { FormattedSegmentDelimiter = string.Format("{0}{1}", FormattedSegmentDelimiter, Environment.NewLine); } Logger.Info("EDIReader.Initialize", "EDIDelimiters: SegmentDelimiter={0}, FieldSeperator={1}, ComponentSeperator={2}", (char)EDIDelimiters.SegmentDelimiter, (char)EDIDelimiters.FieldSeperator, (char)EDIDelimiters.ComponentSeperator); } else //invalid document code path { this.CurrentSegmentStartPos = orgStartPos; this.CurrentSegmentEndPos = orgStartPos + 3; Logger.Error("EDIReader.Initialize", EventId.EDIReaderInvalidDocument, "EDI document is not valid. Error: {0}", tokenizer.Error); Errors.AddGenericError("ISA", SchemaErrorCode.SchemaCode100EInvalidDocType, tokenizer.Error, SegmentNumber, this.CurrentSegmentStartPos, this.CurrentSegmentEndPos); StringBuilder sb = new StringBuilder(); int errorIndex = 1; Errors.IsaIeaErrorList.WriteError(sb, ref errorIndex); ISASegment = string.Empty; } LastState = EDIState.ISA; sw.Stop(); Logger.Debug("EDIReader.Initialize", "Elapsed time {0} ms", sw.ElapsedMilliseconds); return(isValidEDIDocument); }
/// <summary> /// Return flat file input and construct IFatpipeDocument /// IFatpipeDocument will NOT contain ISA and GA segments as it's not /// present in case of flat file. /// Since ISA segment is missing and there is no speific ST segment /// DocumentPlug is mandatory parameter. /// </summary> /// <returns></returns> public IFatpipeDocument ReadFile(Stream flatFileStream, IDocumentPlug documentPlug) { if (flatFileStream == null) { throw new ArgumentNullException("flatFileStream", "Flat file stream cannot be null"); } if (documentPlug == null) { throw new ArgumentNullException("documentPlug", "Document plug cannot be null"); } string location = "FlatFileReader.ReadFile"; Logger.Debug(location, "Start"); Stopwatch sw = new Stopwatch(); sw.Start(); errors = new InterchangeErrors(); DocumentPlug = documentPlug; long orgStartPos = flatFileStream.Position; FlatFileDelimiters = InitializeDelimiters(documentPlug); SegmentDelimiter = ((char)FlatFileDelimiters.SegmentDelimiter).ToString(); FormattedSegmentDelimiter = SegmentDelimiter; bool crLFPresent = FlatFileDelimiters.SegmentDelimiter == Delimiters.CarriageReturn || FlatFileDelimiters.SegmentDelimiterSuffix1 == Delimiters.CarriageReturn; if (!crLFPresent) { FormattedSegmentDelimiter = string.Format("{0}{1}", FormattedSegmentDelimiter, Environment.NewLine); } SegmentNumberFromStart = 0; CurrentSegmentStartPos = 0; this.DocumentReader = new StreamReader(flatFileStream, Encoding.UTF8); // Since flat file doesn't have concept of ST/SE, ans we want to use InterchangeErrors for reporting purpose // create dummy transaction set details Errors.AddTransactionSetDetails(1, "", "", true); CurrentPluglet = DocumentPlug.RootPluglet; CurrentPluglet.ResetCurrentOccurances(); // do we need this for flat files? CurrentPluglet.InitializeStartSegmentList(); FatpipeDocumentInst = new FatpipeDocument(); //FatpipeDocumentInst.TransactionSetType = ???; FatpipeDocumentInst.DocumentPlug = DocumentPlug; FatpipeDocumentInst.RootFragment = CurrentPluglet.ConstructDocumentFragment(null, null); while ((CurrentSegmentDetails = ReadNextSegment()) != null && CurrentSegmentDetails.Length > 0) { Logger.Debug(location, "{0} - Next segment {1}", GetCurrentPosContext(), CurrentSegmentDetails[0]); CreateAndAddNewSegment(CurrentSegmentDetails[0], CurrentSegmentDetails); if (string.IsNullOrWhiteSpace(FatpipeDocumentInst.OriginalPayload)) { FatpipeDocumentInst.OriginalPayload = CurrentSegment; } else { FatpipeDocumentInst.OriginalPayload += SegmentDelimiter + CurrentSegment; } if (string.IsNullOrWhiteSpace(FatpipeDocumentInst.BeautifiedOriginalPayloadBody)) { FatpipeDocumentInst.BeautifiedOriginalPayloadBody = CurrentSegment; } else { FatpipeDocumentInst.BeautifiedOriginalPayloadBody += FormattedSegmentDelimiter + CurrentSegment; } } sw.Stop(); Logger.Debug(location, "Stop - Elapsed time {0} ms", sw.ElapsedMilliseconds); return(FatpipeDocumentInst); }