Closed emacampolo closed 1 year ago
If you can share more details about the specification, then we can work together to implement the header as you mentioned. We can do it privately. Please, find me in Moov's iso8583 Slack channel, and I'll try to help you.
Thank you for the quick response @alovak . Do I need an invitation to join the slack channel?
@emacampolo You can signup to our slack: https://slack.moov.io/
Thank you both for the assistance and specially @alovak for reaching out on slack so quickly. I have an initial implementation that may work. Below you will find a exploratory test (assertions are skipped):
func TestUnpack(t *testing.T) {
// Given
hexMessage := "01020029000000000000000000000000000000000001004000000000000000104761340000000019"
bytesMessage, err := hex.DecodeString(hexMessage)
require.NoError(t, err)
spec := []field.Field{
field.NewString(&field.Spec{
Length: 1,
Description: "H2",
Enc: encoding.ASCIIHexToBytes,
Pref: prefix.ASCII.Fixed,
}),
field.NewString(&field.Spec{
Length: 1,
Description: "H3",
Enc: encoding.ASCIIHexToBytes,
Pref: prefix.ASCII.Fixed,
}),
field.NewString(&field.Spec{
Length: 2,
Description: "H4",
Enc: encoding.ASCIIHexToBytes,
Pref: prefix.ASCII.Fixed,
}),
}
// When
var off int
fields := map[string]field.Field{}
for _, f := range spec {
read, err := f.Unpack(bytesMessage[off:])
require.NoError(t, err)
off += read
fields[f.Spec().Description] = f
}
// Then
b, err := json.Marshal(field.OrderedMap(fields))
require.NoError(t, err)
fmt.Print(string(b)) // {"H2":"01","H3":"02","H4":"0029"}
}
@emacampolo Great that you were able to make it work!
Here is a slightly modified version using a composite field. It lets you get the same result without iterating over the fields, reading data using the offset, etc.
func TestUnpack2(t *testing.T) {
// Given
hexMessage := "01020029000000000000000000000000000000000001004000000000000000104761340000000019"
bytesMessage, err := hex.DecodeString(hexMessage)
require.NoError(t, err)
// describe your header using field Spec with Subfields
headerSpec := &field.Spec{
Length: 4,
Description: "Header",
Pref: prefix.ASCII.Fixed,
Tag: &field.TagSpec{
Sort: sort.StringsByInt,
},
Subfields: map[string]field.Field{
"1": field.NewString(&field.Spec{
Length: 1,
Description: "H2",
Enc: encoding.ASCIIHexToBytes,
Pref: prefix.ASCII.Fixed,
}),
"2": field.NewString(&field.Spec{
Length: 1,
Description: "H3",
Enc: encoding.ASCIIHexToBytes,
Pref: prefix.ASCII.Fixed,
}),
"3": field.NewString(&field.Spec{
Length: 2,
Description: "H4",
Enc: encoding.ASCIIHexToBytes,
Pref: prefix.ASCII.Fixed,
}),
},
}
headerField := field.NewComposite(headerSpec)
// When
_, err = headerField.Unpack(bytesMessage)
require.NoError(t, err)
// Then
b, err := json.Marshal(headerField)
require.NoError(t, err)
fmt.Println(string(b)) // {"H2":"01","H3":"02","H4":"0029"}
}
I also added an example of how you can get subfield values and create value of your custom type (e.g., VisaHeader
). Using it all, you can create a helper method with the raw message as input and a header with fields as output.
// When (taken from the previous example)
_, err = headerField.Unpack(bytesMessage)
// here is a more convenient way to get the value of a subfields
type Header struct {
H2 *field.String `index:"1"`
H3 *field.String `index:"2"`
H4 *field.String `index:"3"`
}
var header Header
// load headerField subfields values into header
err = headerField.Unmarshal(&header)
fmt.Printf("H2: %s\n", header.H2.Value()) // H2: 01
fmt.Printf("H3: %s\n", header.H3.Value()) // H3: 02
fmt.Printf("H4: %s\n", header.H4.Value()) // H4: 0029
// you can return your custom type with values of subfields
type VisaHeader struct {
H2 string
H3 string
H4 string
}
visaHeader := VisaHeader{
H2: header.H2.Value(),
H3: header.H3.Value(),
H4: header.H4.Value(),
}
fmt.Printf("%+v\n", visaHeader) // {H2:01 H3:02 H4:0029}
}
@emacampolo if you think we are done with the issue, feel free to close it :D
Nice, much better! Thank you for the detailed response. I'll give it a try xD
Hello! I'm trying to decode an ISO8583 message using a VTS (VISA test simulator) and the iso8583 package from this module.
The format of a BASE I message is: [header][mti][bitmap(s)][data-elements].
This header length and type may vary. It contains fixed-length fields, plus a bitmap in the 13th header field that specifies the number of fields present after that bitmap.
Below there is example of a standard header (without the extra bitmap), extracted from the simulator:
AFAIK, Moov, as a payment processor, has already integrated with VISA, using an EAS for transacting online payments and therefore, parsing online authorizations. Even though this header is not strictly part of a generic iso message, do you plan adding capabilities to this module for also parsing this value?
Thanks!