//parse ach header line public static ACH ParseHeader(string achHeader, ACH ach, string internalString) { //if achHeader null or not 94 chars, error message string headerRecordTypeCode = achHeader.Substring(0, 1); string priorityCode = achHeader.Substring(1, 2); string immediateDestination = achHeader.Substring(3, 10); string immediateOrigin = achHeader.Substring(13, 10); string fileCreationDate = achHeader.Substring(23, 6); string fileCreationTime = achHeader.Substring(29, 4); string fileIdModifier = achHeader.Substring(33, 1); string recordSize = achHeader.Substring(34, 3); string blockingFactor = achHeader.Substring(37, 2); string formatCode = achHeader.Substring(39, 1); string immediateDestinationName = achHeader.Substring(40, 23); string immediateOriginName = achHeader.Substring(63, 23); string referenceCode = achHeader.Substring(86, 8); ach.SetHeader(internalString, headerRecordTypeCode, priorityCode, immediateDestination, immediateOrigin, fileCreationDate, fileCreationTime, fileIdModifier, recordSize, blockingFactor, formatCode, immediateDestinationName, immediateOriginName, referenceCode); return(ach); }
public static string PrintControl(ACH ach) { return(ach.ControlRecordTypeCode + ach.BatchCount + ach.BlockCount + ach.EntryAddendaCount + ach.EntryHash + ach.TotalDebit + ach.TotalCredit + ach.Reserved); }
public static string PrintBatches(ACH ach) { string batchStr = ""; string prepend = ""; foreach (Batch batch in ach.Batches) { batchStr += prepend + BatchPrinter.PrintBatch(batch); prepend = "\n"; } return(batchStr); }
public static string PrintACH(ACH ach) { string achString = ""; if (!string.IsNullOrEmpty(ach.InternalString)) { achString += PrintInternal(ach) + "\n"; } achString += PrintHeader(ach); achString += "\n" + PrintBatches(ach); achString += "\n" + PrintControl(ach); return(achString); }
public static string PrintHeader(ACH ach) { return(ach.HeaderRecordTypeCode + ach.PriorityCode + ach.ImmediateDestination + ach.ImmediateOrigin + ach.FileCreationDate + ach.FileCreationTime + ach.FileIdModifier + ach.RecordSize + ach.BlockingFactor + ach.FormatCode + ach.ImmediateDestinationName + ach.ImmediateOriginName + ach.ReferenceCode); }
static void Main(string[] args) { //TODO test that create with auto gen of everything also passes all verifies //this is what knows about files (as should any user of the NACHO library) if (args.Length <= 0) { //TODO print usage } else { System.IO.StreamReader reader = new System.IO.StreamReader(args[0]); string messages; ACH ach = ACHParser.ParseStream(reader, out messages); //TODO verify ach System.Console.WriteLine(messages); System.Console.WriteLine("\n" + ACHPrinter.PrintACH(ach)); System.Console.WriteLine(ach.Verify()); Entry entry = new Entry( "6", "27", "07640125", "0", "".PadLeft(17), "".PadLeft(10), "".PadLeft(15), "".PadLeft(22), " ", "0", "".PadLeft(15)); entry.CheckDigit = Entry.GenerateCheckDigit(entry.ReceivingDFI); Entry myEntry = Entry.CreateEntry(Entry.DEBIT_FOR_CHECKING, "012345678", "12345678901234567", "1000", "personid1234", "jon doe", ""); Batch batch = Batch.CreateBatch(Batch.SERVICE_CLASS_DEBIT_ONLY, "", "", "", Batch.STANDARD_ENTRY_PPD, "Wlfare Pln", "", "", "", 0); batch.AddEntry(myEntry); ACH myach = ACH.CreateACH("", " 123456789", "0123456789", "A", "my bank", "my company", ""); myach.AddBatch(batch); myach.SetAutoValues(); string msg = myach.Verify(); } }
//parse ach footer line public static ACH ParseControl(string achControl, ACH ach) { //TODO if achControl null or not 94 chars then error message string controlRecordType = achControl.Substring(0, 1); string controlBatchCount = achControl.Substring(1, 6); string controlBlockCount = achControl.Substring(7, 6); string controlEntryAddendaCount = achControl.Substring(13, 8); string controlEntryHash = achControl.Substring(21, 10); string controlTotalDebit = achControl.Substring(31, 12); string controlTotalCredit = achControl.Substring(43, 12); string controlReserved = achControl.Substring(55, 39); ach.SetControl(controlRecordType, controlBatchCount, controlBlockCount, controlEntryAddendaCount, controlEntryHash, controlTotalDebit, controlTotalCredit, controlReserved); return(ach); }
public static string PrintInternal(ACH ach) { return(ach.InternalString); }
//parse whole file, calls batch parser, returns new ach public static ACH ParseStream(System.IO.StreamReader reader, out string messages) { //or leave null, return null on (initial, not all) error? ACH ach = new ACH(); string internalString = ""; uint currentLineNumber = 1; messages = ""; //set to false once we see a valid entry record type code //used to determine when we should stop seeing internal lines that //should only be at the beginning of the file bool didNotRecieveEntry = true; bool recievedAchControlEntry = false; int recordType; string internalNewLine = ""; while ((recordType = reader.Peek()) != -1) { //if we recieved the ach control entry then add message that another line not expected (except empty line) //(but that should be handled by didNotRecieveEntry else case as error) //make sure all paths consume at least one line or infinite loop will result if (didNotRecieveEntry) { //check if first char is a valid record type if (recordType != BATCH_HEADER_RECORD_TYPE_ASCII_VALUE && recordType != ENTRY_RECORD_TYPE_ASCII_VALUE && recordType != ADDENDA_RECORD_TYPE_ASCII_VALUE && recordType != BATCH_CONTROL_RECORD_TYPE_ASCII_VALUE && recordType != ACH_CONTROL_RECORD_TYPE_ASCII_VALUE) { //this is basically the only valid path, all others should be error that appends message if (recordType != ACH_HEADER_RECORD_TYPE_ASCII_VALUE) { //still an internal message, just append to internal message (with newlines between) internalString += reader.ReadLine(); if (internalString != null)//shouldn't get null if recordType peek was successful, but just in case { internalString = internalNewLine + internalString; internalNewLine = "\n"; ++currentLineNumber; } else { //TODO report error it was null } } else { //got the ach header entry, set values, go into batch parse call string achHeader = reader.ReadLine(); if (achHeader != null)//shouldn't be null if recordType was successful, but just in case { ParseHeader(achHeader, ach, internalString); //TODO handle if there there's a message from setheader //if setheadermessage not null or ws then say so and add to messages ++currentLineNumber;//update line number after possible use in error message } else { //TODO report unexpected null } //while next char is a new batch header (message if not a batch header or ach control record type, also error if end of stream -1) //for each batch while ((recordType = reader.Peek()) == BATCH_HEADER_RECORD_TYPE_ASCII_VALUE) { string batchMessages; //TODO pass in a new line count int, add to total current line number count uint linesRead = 0; Batch batch = BatchParser.ParseStream(reader, out batchMessages, out linesRead, currentLineNumber); messages += batchMessages; if (batch != null) { ach.Batches.Add(batch); } } //for now test batch parse that just consumes non-ach control entries //when out of batch parse call, reader probably pointing at ach control entry //set more values with that if (recordType != ACH_CONTROL_RECORD_TYPE_ASCII_VALUE) { //TODO consume line and give error message } else { //get ach control data string achControl = reader.ReadLine(); if (achControl != null) { ParseControl(achControl, ach); recievedAchControlEntry = true; //TODO if controlmessage is not null/ws then add error to message //TODO check control values (number of entries, hash, etc) here or in SetControl? Probably SetControl ++currentLineNumber; //TODO error if any non-null/ws lines still in file at this point } } didNotRecieveEntry = false; } } else { messages += "\nReceived what looks like a batch, entry, or ACH control unexpectedly before an ACH header on line " + currentLineNumber.ToString() + ": '" + reader.ReadLine() + "'"; ++currentLineNumber; } } else { messages += "\nError on line " + currentLineNumber.ToString() + ": '" + reader.ReadLine() + "'"; ++currentLineNumber; } } if (didNotRecieveEntry && !recievedAchControlEntry) { messages += "\nDid not recieve both an ACH header and control"; } return(ach); }