;WALKTHROUGH:Documentation
TITLE
NACHA file

SUMMARY
This module provides procedures for reading a file in the NACHA format
and taking apart the fixed-format record into its individual data items.

DOCUMENTATION
Include the module in your program with:

do %nacha.r

NACHA-OPEN-INPUT
Perform this procedure first.  It will read the file into memory.
If you don't like the default name of the file (which is meaningless, really,
because it is the name of a NACHA file from the vendor), assign a new value to
NACHA-FILE-ID.

NACHA-READ
Do this proceure until NACHA-EOF is true.
After each call, use NACHA-CURRENT-TYPE to decide what kind of record you
have, and then refer to the appropriate data names (in the code below) to
access the fields in the record.

SCRIPT
REBOL [
    Title: "NACHA file"
]

;; [---------------------------------------------------------------------------]
;; [ Substring function used for extracting parts of a fixed-format record.    ]
;; [---------------------------------------------------------------------------]

GLB-SUBSTRING: func [
    "Return a substring from the start position to the end position"
    INPUT-STRING [series!] "Full input string"
    START-POS    [number!] "Starting position of substring"
    END-POS      [number!] "Ending position of substring"
] [
    if END-POS = -1 [END-POS: length? INPUT-STRING]
    return skip (copy/part INPUT-STRING END-POS) (START-POS - 1)
]

;WALKTHROUGH:Purpose
;; [---------------------------------------------------------------------------]
;; [ This module defines a text file in the NACHA format for                   ]
;; [ getting money electronically from the bank,                               ]
;; [ This is the file that Cogsdale makes and that we send every               ]
;; [ Monday.                                                                   ]
;; [ This file differs slightly from the file we get from the bank             ]
;; [ every DAY with internet payments, but the difference seems                ]
;; [ to be in field uses and not field positions.                              ]     
;; [---------------------------------------------------------------------------]

NACHA-FILE: []                 ;; Holds the whole file in memory
NACHA-FILE-ID: %NATC0001.TXT   ;; Default name of the file
NACHA-EOF: false               ;; End-of-file flag for reading
NACHA-REC: ""                  ;; One record, for reading or writing 
NACHA-REC-COUNT: 0             ;; Counter, upped by 1 as we read or write 

NACHA-CURRENT-TYPE: ""         ;; Type code of record in memory

;WALKTHROUGH:Data fields
;; [---------------------------------------------------------------------------]
;; [ When we read a record, we will take it apart in to its                    ]
;; [ fields and store the fields below.  The CURRENT-TYPE field                ]
;; [ indicates which record we currently have our hands on.                    ]
;; [ For those record that contain numbers or amounts, some of the             ]
;; [ numbers or amounts are converted to appropriate data types                ]
;; [ so they can be used in appropriate ways (currency, for example).          ]
;; [---------------------------------------------------------------------------]

NACHA-1-RECORD-TYPE-CODE: ""
NACHA-1-PRIORITY-CODE: ""
NACHA-1-IMMEDIATE-DESTINATION: ""
NACHA-1-IMMEDIATE-ORIGIN: ""
NACHA-1-TRANSMISSION-DATE: ""
NACHA-1-TRANSMISSION-TIME: ""
NACHA-1-FILE-ID-MODIFIER: ""
NACHA-1-RECORD-SIZE: ""
NACHA-1-BLOCKING-FACTOR: ""
NACHA-1-FORMAT-CODE: ""
NACHA-1-DESTINATION-NAME: ""
NACHA-1-ORIGIN: ""
NACHA-1-REFERENCE-CODE: ""

NACHA-5-RECORD-TYPE-CODE: ""
NACHA-5-SERVICE-CLASS-CODE: ""
NACHA-5-BILLER-NAME: ""
NACHA-5-RESERVED: ""
NACHA-5-BILLER-ID-NUMBER: ""
NACHA-5-ENTRY-CLASS: ""
NACHA-5-ENTRY-DESCRIPTION: ""
NACHA-5-DESCRIPTIVE-DATE: ""
NACHA-5-EFFECTIVE-DATE: ""
NACHA-5-SETTLEMENT-DATE: ""
NACHA-5-CONCENTRATOR-STATUS: ""
NACHA-5-NACHA-ID-NUMBER: ""
NACHA-5-BATCH-NUMBER: ""

NACHA-5-EFFECTIVE-DATE-E: ""

NACHA-6-RECORD-TYPE-CODE: ""
NACHA-6-TRANSACTION-CODE: ""
NACHA-6-NACHA-ID-NUMBER: ""
NACHA-6-MERCHANT-ACCOUNT-NBR: ""
NACHA-6-AMOUNT: ""
NACHA-6-CONSUMER-ACCOUNT-NBR: ""
NACHA-6-CONSUMER-NAME: ""
NACHA-6-NACHA-FLAG: ""
NACHA-6-ADDENDUM-RECORD-IND: ""
NACHA-6-TRACE-NUMBER: ""
NACHA-6-SEQUENCE-NUMBER: ""

NACHA-6-AMOUNT-N: ""

NACHA-8-RECORD-TYPE-CODE: ""
NACHA-8-SERVICE-CLASS-CODE: ""
NACHA-8-ENTRY-ADDENDA-COUNT: ""
NACHA-8-ENTRY-HASH: ""
NACHA-8-TOTAL-DEBIT: ""
NACHA-8-TOTAL-CREDIT: ""
NACHA-8-BILLER-ID-NUMBER: ""
NACHA-8-MAC: ""
NACHA-8-FILLER-1: ""
NACHA-8-NACHA-ID-NUMBER: ""
NACHA-8-BATCH-NUMBER: ""

NACHA-8-TOTAL-DEBIT-N: ""
NACHA-8-TOTAL-CREDIT-N: ""

NACHA-9-RECORD-TYPE-CODE: ""
NACHA-9-BATCH-COUNT: ""
NACHA-9-BLOCK-COUNT: ""
NACHA-9-ENTRY-ADDENDA-COUNT: ""
NACHA-9-ENTRY-HASH: ""
NACHA-9-TOTAL-DEBIT: ""
NACHA-9-TOTAL-CREDIT: ""
NACHA-9-FILLER-1: ""

NACHA-9-TOTAL-DEBIT-N: ""
NACHA-9-TOTAL-CREDIT-N: ""

;WALKTHROUGH:Open-close-read-write
NACHA-OPEN-INPUT: does [
    NACHA-FILE: copy []
    NACHA-FILE: read/lines NACHA-FILE-ID
    NACHA-EOF: false
    NACHA-REC-COUNT: 0
]

NACHA-READ: does [
    NACHA-REC-COUNT: NACHA-REC-COUNT + 1
    NACHA-REC: copy ""
    NACHA-CURRENT-TYPE: copy ""
    if none? NACHA-REC: pick NACHA-FILE NACHA-REC-COUNT [
        NACHA-EOF: true
    ]
    if not NACHA-EOF [
        NACHA-UNSTRING-RECORD
    ]
]

NACHA-CLOSE-INPUT: does [
    NACHA-FILE: copy []
    NACHA-REC: copy ""
]

NACHA-OPEN-OUTPUT: does [
    NACHA-FILE: copy []
    NACHA-REC: copy ""
    NACHA-REC-COUNT: 0
]

NACHA-WRITE: does [
    append NACHA-FILE NACHA-REC
    NACHA-REC-COUNT: NACHA-REC-COUNT + 1
]

NACHA-CLOSE-OUTPUT: does [
    write/lines NACHA-FILE-ID NACHA-FILE
    NACHA-FILE: copy []
    NACHA-REC: copy ""
]

;WALKTHROUGH:Unstringing data
NACHA-UNSTRING-RECORD: does [
    NACHA-CURRENT-TYPE: GLB-SUBSTRING NACHA-REC 1 1
    if = NACHA-CURRENT-TYPE "1" [
        NACHA-UNSTRING-1
    ]
    if = NACHA-CURRENT-TYPE "5" [
        NACHA-UNSTRING-5
    ]
    if = NACHA-CURRENT-TYPE "6" [
        NACHA-UNSTRING-6
    ]
    if = NACHA-CURRENT-TYPE "8" [
        NACHA-UNSTRING-8
    ]
    if = NACHA-CURRENT-TYPE "9" [
        NACHA-UNSTRING-9
    ] 
]

NACHA-UNSTRING-1: does [
    NACHA-1-RECORD-TYPE-CODE: copy ""
    NACHA-1-PRIORITY-CODE: copy ""
    NACHA-1-IMMEDIATE-DESTINATION: copy ""
    NACHA-1-IMMEDIATE-ORIGIN: copy ""
    NACHA-1-TRANSMISSION-DATE: copy ""
    NACHA-1-TRANSMISSION-TIME: copy ""
    NACHA-1-FILE-ID-MODIFIER: copy ""
    NACHA-1-RECORD-SIZE: copy ""
    NACHA-1-BLOCKING-FACTOR: copy ""
    NACHA-1-FORMAT-CODE: copy ""
    NACHA-1-DESTINATION-NAME: copy ""
    NACHA-1-ORIGIN: copy ""
    NACHA-1-REFERENCE-CODE: copy ""
    NACHA-1-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-1-PRIORITY-CODE: GLB-SUBSTRING NACHA-REC 2 3
    NACHA-1-IMMEDIATE-DESTINATION: GLB-SUBSTRING NACHA-REC 4 13
    NACHA-1-IMMEDIATE-ORIGIN: GLB-SUBSTRING NACHA-REC 14 23
    NACHA-1-TRANSMISSION-DATE: GLB-SUBSTRING NACHA-REC 24 29
    NACHA-1-TRANSMISSION-TIME: GLB-SUBSTRING NACHA-REC 30 33
    NACHA-1-FILE-ID-MODIFIER: GLB-SUBSTRING NACHA-REC 34 34
    NACHA-1-RECORD-SIZE: GLB-SUBSTRING NACHA-REC 35 37
    NACHA-1-BLOCKING-FACTOR: GLB-SUBSTRING NACHA-REC 38 39
    NACHA-1-FORMAT-CODE: GLB-SUBSTRING NACHA-REC 40 40
    NACHA-1-DESTINATION-NAME: GLB-SUBSTRING NACHA-REC 41 63
    NACHA-1-ORIGIN: GLB-SUBSTRING NACHA-REC 64 86
    NACHA-1-REFERENCE-CODE: GLB-SUBSTRING NACHA-REC 87 94
]

NACHA-UNSTRING-5: does [
    NACHA-5-RECORD-TYPE-CODE: copy ""
    NACHA-5-SERVICE-CLASS-CODE: copy ""
    NACHA-5-BILLER-NAME: copy ""
    NACHA-5-RESERVED: copy ""
    NACHA-5-BILLER-ID-NUMBER: copy ""
    NACHA-5-ENTRY-CLASS: copy ""
    NACHA-5-ENTRY-DESCRIPTION: copy ""
    NACHA-5-DESCRIPTIVE-DATE: copy ""
    NACHA-5-EFFECTIVE-DATE: copy ""
    NACHA-5-SETTLEMENT-DATE: copy ""
    NACHA-5-CONCENTRATOR-STATUS: copy ""
    NACHA-5-NACHA-ID-NUMBER: copy ""
    NACHA-5-BATCH-NUMBER: copy ""
    NACHA-5-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-5-SERVICE-CLASS-CODE: GLB-SUBSTRING NACHA-REC 2 4
    NACHA-5-BILLER-NAME: GLB-SUBSTRING NACHA-REC 5 20
    NACHA-5-RESERVED: GLB-SUBSTRING NACHA-REC 21 40
    NACHA-5-BILLER-ID-NUMBER: GLB-SUBSTRING NACHA-REC 41 50
    NACHA-5-ENTRY-CLASS: GLB-SUBSTRING NACHA-REC 51 53
    NACHA-5-ENTRY-DESCRIPTION: GLB-SUBSTRING NACHA-REC 54 63
    NACHA-5-DESCRIPTIVE-DATE: GLB-SUBSTRING NACHA-REC 64 69
    NACHA-5-EFFECTIVE-DATE: GLB-SUBSTRING NACHA-REC 70 75
    NACHA-5-SETTLEMENT-DATE: GLB-SUBSTRING NACHA-REC 76 78
    NACHA-5-CONCENTRATOR-STATUS: GLB-SUBSTRING NACHA-REC 79 79
    NACHA-5-ID-NUMBER: GLB-SUBSTRING NACHA-REC 80 87
    NACHA-5-BATCH-NUMBER: GLB-SUBSTRING NACHA-REC 88 94
    NACHA-5-EFFECTIVE-DATE-E: rejoin [
        GLB-SUBSTRING NACHA-5-EFFECTIVE-DATE 3 4
        "/"
        GLB-SUBSTRING NACHA-5-EFFECTIVE-DATE 5 6
        "/"
        "20"
        GLB-SUBSTRING NACHA-5-EFFECTIVE-DATE 1 2
    ]
]

NACHA-UNSTRING-6: does [
    NACHA-6-RECORD-TYPE-CODE: copy ""
    NACHA-6-TRANSACTION-CODE: copy ""
    NACHA-6-NACHA-ID-NUMBER: copy ""
    NACHA-6-MERCHANT-ACCOUNT-NBR: copy ""
    NACHA-6-AMOUNT: copy ""
    NACHA-6-CONSUMER-ACCOUNT-NBR: copy ""
    NACHA-6-CONSUMER-NAME: copy ""
    NACHA-6-NACHA-FLAG: copy ""
    NACHA-6-ADDENDUM-RECORD-IND: copy ""
    NACHA-6-TRACE-NUMBER: copy ""
    NACHA-6-SEQUENCE-NUMBER: copy ""
    NACHA-6-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-6-TRANSACTION-CODE: GLB-SUBSTRING NACHA-REC 2 3
    NACHA-6-NACHA-ID-NUMBER: GLB-SUBSTRING NACHA-REC 4 12
    NACHA-6-MERCHANT-ACCOUNT-NBR: GLB-SUBSTRING NACHA-REC 13 29
    NACHA-6-AMOUNT: GLB-SUBSTRING NACHA-REC 30 39
    NACHA-6-CONSUMER-ACCOUNT-NBR: GLB-SUBSTRING NACHA-REC 40 54
    NACHA-6-CONSUMER-NAME: GLB-SUBSTRING NACHA-REC 55 76
    NACHA-6-NACHA-FLAG: GLB-SUBSTRING NACHA-REC 77 78
    NACHA-6-ADDENDUM-RECORD-IND: GLB-SUBSTRING NACHA-REC 79 79
    NACHA-6-TRACE-NUMBER: GLB-SUBSTRING NACHA-REC 80 87
    NACHA-6-SEQUENCE-NUMBER: GLB-SUBSTRING NACHA-REC 88 94
    NACHA-6-AMOUNT-N: to-money divide to-decimal NACHA-6-AMOUNT 100
]

NACHA-UNSTRING-8: does [
    NACHA-8-RECORD-TYPE-CODE: copy ""
    NACHA-8-SERVICE-CLASS-CODE: copy ""
    NACHA-8-ENTRY-ADDENDA-COUNT: copy ""
    NACHA-8-ENTRY-HASH: copy ""
    NACHA-8-TOTAL-DEBIT: copy ""
    NACHA-8-TOTAL-CREDIT: copy ""
    NACHA-8-BILLER-ID-NUMBER: copy ""
    RPPT-8-MAC: copy ""
    NACHA-8-FILLER-1: copy ""
    NACHA-8-NACHA-ID-NUMBER: copy ""
    NACHA-8-BATCH-NUMBER: copy ""
    NACHA-8-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-8-SERVICE-CLASS-CODE: GLB-SUBSTRING NACHA-REC 2 4
    NACHA-8-ENTRY-ADDENDA-COUNT: GLB-SUBSTRING NACHA-REC 5 10
    NACHA-8-ENTRY-HASH: GLB-SUBSTRING NACHA-REC 11 20
    NACHA-8-TOTAL-DEBIT: GLB-SUBSTRING NACHA-REC 21 32
    NACHA-8-TOTAL-CREDIT: GLB-SUBSTRING NACHA-REC 33 44
    NACHA-8-BILLER-ID-NUMBER: GLB-SUBSTRING NACHA-REC 45 54
    NACHA-8-MAC: GLB-SUBSTRING NACHA-REC 55 73
    NACHA-8-FILLER-1: GLB-SUBSTRING NACHA-REC 74 79
    NACHA-8-NACHA-ID-NUMBER: GLB-SUBSTRING NACHA-REC 80 87
    NACHA-8-BATCH-NUMBER: GLB-SUBSTRING NACHA-REC 88 94
    NACHA-8-TOTAL-DEBIT-N: to-money divide to-decimal NACHA-8-TOTAL-DEBIT 100
    NACHA-8-TOTAL-CREDIT-N: to-money divide to-decimal NACHA-8-TOTAL-CREDIT 100  
]

NACHA-UNSTRING-9: does [
    NACHA-9-RECORD-TYPE-CODE: copy "" 
    NACHA-9-BATCH-COUNT: copy "" 
    NACHA-9-BLOCK-COUNT: copy "" 
    NACHA-9-ENTRY-ADDENDA-COUNT: copy "" 
    NACHA-9-ENTRY-HASH: copy "" 
    NACHA-9-TOTAL-DEBIT: copy "" 
    NACHA-9-TOTAL-CREDIT: copy "" 
    NACHA-9-FILLER-1: copy "" 
    NACHA-9-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-9-BATCH-COUNT: GLB-SUBSTRING NACHA-REC 2 7
    NACHA-9-BLOCK-COUNT: GLB-SUBSTRING NACHA-REC 8 13
    NACHA-9-ENTRY-ADDENDA-COUNT: GLB-SUBSTRING NACHA-REC 14 21
    NACHA-9-ENTRY-HASH: GLB-SUBSTRING NACHA-REC 22 31
    NACHA-9-TOTAL-DEBIT: GLB-SUBSTRING NACHA-REC 32 43
    NACHA-9-TOTAL-CREDIT: GLB-SUBSTRING NACHA-REC 44 55
    NACHA-9-FILLER-1: GLB-SUBSTRING NACHA-REC 56 94
    NACHA-9-TOTAL-DEBIT-N: to-money divide to-decimal NACHA-9-TOTAL-DEBIT 100
    NACHA-9-TOTAL-CREDIT-N: to-money divide to-decimal NACHA-9-TOTAL-CREDIT 100  
]

;; -------------------------------------------------------------------