-
Example, i need to define different field spec for different type of mesasge
any idea how to handle this during unpacking ? when i pack, that is fine as we know what we want to generate. but for incoming messages, this is a challenge. |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments
-
Hey @Achuthen! From my experience working the all of the major card brands, the way iso8583 messaging works is this:
In some cases, when 52: field.NewString(&field.Spec{
Length: 300, // let's say spec says that length of the data is 300 bytes
Description: "Private Use Data",
Enc: encoding.Binary,
Pref: prefix.Binary.Fixed,
}),
type NetworkManagementRequest struct {
MTI *field.String `index:"0"`
TransmissionDateTime *field.String `index:"7"`
STAN *field.String `index:"11"`
// in example spec there is no field 70, but usually field 70 is used for network management code
NetworkManagementCode *field.String `index:"70"`
}
type NetworkManagementResponse struct {
MTI *field.String `index:"0"`
TransmissionDateTime *field.String `index:"7"`
STAN *field.String `index:"11"`
ResponseCode *field.String `index:"39"`
}
signOnRequest := &NetworkManagementRequest{
MTI: field.NewStringValue("0800"),
TransmissionDateTime: field.NewStringValue(time.Now().UTC().Format(YourDateTimeFormat)),
STAN: field.NewStringValue(stan),
NetworkManagementCode: field.NewStringValue(NetworkManagementCodeSignOn),
}
requestMessage := iso8583.NewMessage(YourFullSpecification)
err := requestMessage.Marshal(request)
if err != nil {
// handle error
}
// send requestMessage to server using iso8583-connection
responseMessage, err := conn.Send(requestMessage)
if err != nil {
// handle error
}
signOnResponse := &NetworkManagementResponse{}
err = responseMessage.Unmarshal(signOnResponse)
if err != nil {
// handle error
}
// now you can use values from signOnResponse
if signOnResponse.ResponseCode.Value() != ResponseCodeApproved {
// do something
} I would suggest you to create function that you can use universally for all messages. Here is the example of such func: func sendData(conn *iso8583.Connection, requestData, responseData interface{}) error {
requestMessage := iso8583.NewMessage(YourFullSpecification)
err := requestMessage.Marshal(requestData)
if err != nil {
return fmt.Errorf("setting data to message: %w", err)
}
responseMessage, err := conn.Send(requestMessage)
if err != nil {
return fmt.Errorf("sending message: %w", err)
}
err = responseMessage.Unmarshal(responseData)
if err != nil {
return fmt.Errorf("getting data from message: %w", err)
}
return nil
} Here is the demo code (I didn't try to compile it, but I think it's mostly correct): func demoSendNetworkManagementData() {
// conn is iso8583-connection
signOnRequest := &NetworkManagementRequest{
MTI: field.NewStringValue("0800"),
TransmissionDateTime: field.NewStringValue(time.Now().UTC().Format(YourDateTimeFormat)),
STAN: field.NewStringValue(stan),
NetworkManagementCode: field.NewStringValue(NetworkManagementCodeSignOn),
}
// prepare empty response
signOnResponse := &NetworkManagementResponse{}
err := sendData(conn, signOnRequest, signOnResponse)
if err != nil {
// handle error
}
// now you can use values from signOnResponse
if signOnResponse.ResponseCode.Value() != ResponseCodeApproved {
// do something
}
}
func demoSendAuthorizationData() {
// conn is iso8583-connection
authorizationRequest := &AuthorizationRequest{
MTI: field.NewStringValue("0200"),
TransmissionDateTime: field.NewStringValue(time.Now().UTC().Format(YourDateTimeFormat)),
STAN: field.NewStringValue(stan),
PAN: field.NewStringValue(pan),
ProcessingCode: field.NewStringValue(processingCode),
Amount: field.NewStringValue(amount),
// ...
}
// prepare empty response
authorizationResponse := &AuthorizationResponse{}
err := sendData(conn, authorizationRequest, authorizationResponse)
if err != nil {
// handle error
}
// now you can use values from authorizationResponse
if authorizationResponse.ResponseCode.Value() != ResponseCodeApproved {
// do something
}
} I hope this is helpful. P.S. To send/receive messages, I recommend to use our https://github.com/moov-io/iso8583-connection package ;) |
Beta Was this translation helpful? Give feedback.
-
Can you update the readme? This is awesome @alovak |
Beta Was this translation helpful? Give feedback.
-
@Achuthen, if you think that the answer helped you, you can click on "Mark as answer" |
Beta Was this translation helpful? Give feedback.
-
thanks for you feedback man. i am practicing something similar to your example. i am working directly on the messages without the data structs for common validations and initialisations. these examples you gave worth to be on readme :) my challenge is this, the spec i am working is little weird. the bit 48 is actually defined differently depends on the message type. the difference is not just the length. but the spec itself.
and there is 2 more options for this. :( |
Beta Was this translation helpful? Give feedback.
-
Oh, I see. To be honest, I'm not sure about the case where spec is different for different messages. When you unpack the message you should know which spec to use. How do you know if it's network management message or auth? Do you have to read MTI separately and only then build message using according spec? One of the options is to manually build the value for such field. Something like: // create individual fields like the following
field48a := field.NewString(&field.Spec{
Length: 3,
Description: "Network Management Code",
Enc: encoding.ASCII,
Pref: prefix.ASCII.Fixed,
})
field48a.SetValue("123")
field48b := field.NewString(&field.Spec{
Length: 10,
Description: "Network Management Something",
Enc: encoding.ASCII,
Pref: prefix.ASCII.Fixed,
})
field48b.SetValue("1234567890")
fields := []field.Field{field48a, field48b}\
var packed []byte
for _, field := range fields {
bs, err := field.Pack()
// handle error
packed = append(packed, bs...)
}
// now, you can use `packed` as value for the field 48
err := message.BinaryField(48, packed)
// handle error It seems that if we add var field48Var1 = field.NewComposite(&field.Spec{
Length: 0, // It should read all data it is given
Description: "Network Management",
Pref: prefix.ASCII.None,
Tag: &field.TagSpec{
Sort: sort.StringsByInt,
},
Subfields: map[string]field.Field{
"1": field.NewString(&field.Spec{
Length: 3,
Description: "Network Management Code",
Enc: encoding.ASCII,
Pref: prefix.ASCII.Fixed,
}),
"2": field.NewString(&field.Spec{
Length: 10,
Description: "Network Management Something",
Enc: encoding.ASCII,
Pref: prefix.ASCII.Fixed,
}),
},
})
// here we can use data structs to set field values
field48Var1.Marshal(&DataForField48{
Code: field.NewStringValue("123"),
Something: field.NewStringValue("1234567890"),
})
packed, err := field48Var1.Pack()
// handle err
err := message.BinaryField(48, packed) All code I shared above may contain compilation errors as it represents the general ideas, not concrete the implementations. |
Beta Was this translation helpful? Give feedback.
Hey @Achuthen! From my experience working the all of the major card brands, the way iso8583 messaging works is this:
In some cases, when
field N
is a composite field (field with subfields) but you don't need to work with it now or in the future, you can just define it asBinary
field in your spec without digging deeper. In this way d…