-
Notifications
You must be signed in to change notification settings - Fork 1
/
file_header.go
122 lines (109 loc) · 3.65 KB
/
file_header.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package cadeft
import (
"fmt"
"strings"
"time"
)
// FileHeader represents Logical Record Type A in the EFT 005 spec.
// Every EFT file should have a header entry which contains information about the originator, currency and creation dates.
// the supported currency should be CAD or USD.
type FileHeader struct {
RecordHeader
CreationDate *time.Time `json:"creation_date" validate:"required"`
DestinationDataCenterNo int64 `json:"destination_data_center" validate:"min=0,max=99999,numeric"`
DirectClearerCommunicationArea string `json:"communication_area" validate:"max=20"`
CurrencyCode string `json:"currency_code" validate:"required,eft_cur,len=3"`
}
func NewFileHeader(
originatorId string,
fileCreationNum int64,
creationDate *time.Time,
destinationDataCenterNo int64,
currencyCode string,
opts ...HeaderOpts) *FileHeader {
fh := &FileHeader{
RecordHeader: RecordHeader{
RecordType: HeaderRecord,
recordCount: 1,
OriginatorID: originatorId,
FileCreationNum: fileCreationNum,
},
CreationDate: creationDate,
DestinationDataCenterNo: destinationDataCenterNo,
CurrencyCode: currencyCode,
}
for _, o := range opts {
o(fh)
}
return fh
}
type HeaderOpts func(*FileHeader)
// This option will add an optional direct clearer communication area field to the header
func WithDirectClearerCommunicationArea(comm string) HeaderOpts {
return func(fh *FileHeader) {
fh.DirectClearerCommunicationArea = comm
}
}
func (fh *FileHeader) parse(line string) error {
var err error
recordHeader := RecordHeader{}
if len(line) < aRecordMinLength {
return fmt.Errorf("invalid header record length")
}
err = recordHeader.parse(line)
if err != nil {
return fmt.Errorf("failed to parse record header: %w", err)
}
fh.RecordHeader = recordHeader
creationDate, err := parseDate(line[24:30])
if err != nil {
return fmt.Errorf("failed to parse creation date for file header: %w", err)
}
fh.CreationDate = &creationDate
fh.DestinationDataCenterNo, err = parseNum(line[30:35])
if err != nil {
return fmt.Errorf("failed to parse destination data center for file header: %w", err)
}
fh.DirectClearerCommunicationArea = strings.TrimSpace(line[35:55])
fh.CurrencyCode = strings.TrimSpace(line[55:58])
return nil
}
// Validate checks whether the fields of a FileHeader struct contain the correct fields that are required when writing/reading an EFT file.
// The validation check can be found on Section D of EFT standard 005.
func (fh FileHeader) Validate() error {
if err := eftValidator.Struct(&fh); err != nil {
return err
}
return nil
}
func (fh FileHeader) buildHeader(currRecordCount int) (string, error) {
var sb strings.Builder
rh, err := fh.RecordHeader.buildRecordHeader()
if err != nil {
return "", fmt.Errorf("failed to write record header for file header: %w", err)
}
sb.WriteString(rh)
if fh.CreationDate != nil {
sb.WriteString(convertTimestampToEftDate(*fh.CreationDate))
} else {
sb.WriteString(convertNumToZeroPaddedString(0, 6))
}
sb.WriteString(convertNumToZeroPaddedString(fh.DestinationDataCenterNo, 5))
// add buffering of 20 empty characters Reserved Customer-Direct Clearer Communication area
if fh.DirectClearerCommunicationArea == "" {
sb.WriteString(createFillerString(20))
} else {
sb.WriteString(padStringWithBlanks(fh.DirectClearerCommunicationArea, 20))
}
sb.WriteString(padStringWithBlanks(fh.CurrencyCode, 3))
sb.WriteString(createFillerString(1406))
return sb.String(), nil
}
func isHeaderRecordType(s string) bool {
switch s {
case string(HeaderRecord), string(NoticeOfChangeHeader):
return true
default:
return false
}
}