Closed Achuthen closed 1 year ago
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 as Binary
field in your spec without digging deeper. In this way during unpacking you will read the field as a whole and ignore its data. Something like:
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"`
}
Marshal
. When you receive response message, you do the opposite - set values of the data struct with values from the message fields using Unmarshal
. Here is the example: 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 ;)
Can you update the readme? This is awesome @alovak
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.