|
| 1 | +package examples |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "os" |
| 6 | + "testing" |
| 7 | + "time" |
| 8 | + |
| 9 | + "github.com/moov-io/iso8583" |
| 10 | + "github.com/moov-io/iso8583/encoding" |
| 11 | + "github.com/moov-io/iso8583/field" |
| 12 | + "github.com/moov-io/iso8583/padding" |
| 13 | + "github.com/moov-io/iso8583/prefix" |
| 14 | + "github.com/moov-io/iso8583/sort" |
| 15 | + "github.com/stretchr/testify/require" |
| 16 | +) |
| 17 | + |
| 18 | +var spec *iso8583.MessageSpec = &iso8583.MessageSpec{ |
| 19 | + Name: "ISO 8583 CardFlow Playgroud ASCII Specification", |
| 20 | + Fields: map[int]field.Field{ |
| 21 | + 0: field.NewString(&field.Spec{ |
| 22 | + Length: 4, |
| 23 | + Description: "Message Type Indicator", |
| 24 | + Enc: encoding.BCD, |
| 25 | + Pref: prefix.BCD.Fixed, |
| 26 | + }), |
| 27 | + 1: field.NewBitmap(&field.Spec{ |
| 28 | + Length: 8, |
| 29 | + Description: "Bitmap", |
| 30 | + Enc: encoding.Binary, |
| 31 | + Pref: prefix.Binary.Fixed, |
| 32 | + }), |
| 33 | + 2: field.NewString(&field.Spec{ |
| 34 | + Length: 19, |
| 35 | + Description: "Primary Account Number (PAN)", |
| 36 | + Enc: encoding.BCD, |
| 37 | + Pref: prefix.ASCII.LL, |
| 38 | + }), |
| 39 | + 3: field.NewString(&field.Spec{ |
| 40 | + Length: 6, |
| 41 | + Description: "Amount", |
| 42 | + Enc: encoding.BCD, |
| 43 | + Pref: prefix.BCD.Fixed, |
| 44 | + Pad: padding.Left('0'), |
| 45 | + }), |
| 46 | + 4: field.NewString(&field.Spec{ |
| 47 | + Length: 12, |
| 48 | + Description: "Transmission Date & Time", // YYMMDDHHMMSS |
| 49 | + Enc: encoding.BCD, |
| 50 | + Pref: prefix.BCD.Fixed, |
| 51 | + }), |
| 52 | + 5: field.NewString(&field.Spec{ |
| 53 | + Length: 2, |
| 54 | + Description: "Approval Code", |
| 55 | + Enc: encoding.BCD, |
| 56 | + Pref: prefix.BCD.Fixed, |
| 57 | + }), |
| 58 | + 6: field.NewString(&field.Spec{ |
| 59 | + Length: 6, |
| 60 | + Description: "Authorization Code", |
| 61 | + Enc: encoding.BCD, |
| 62 | + Pref: prefix.BCD.Fixed, |
| 63 | + }), |
| 64 | + 7: field.NewString(&field.Spec{ |
| 65 | + Length: 3, |
| 66 | + Description: "Currency", |
| 67 | + Enc: encoding.BCD, |
| 68 | + Pref: prefix.BCD.Fixed, |
| 69 | + }), |
| 70 | + 8: field.NewString(&field.Spec{ |
| 71 | + Length: 4, |
| 72 | + Description: "Card Verification Value (CVV)", |
| 73 | + Enc: encoding.BCD, |
| 74 | + Pref: prefix.BCD.Fixed, |
| 75 | + }), |
| 76 | + 9: field.NewString(&field.Spec{ |
| 77 | + Length: 4, |
| 78 | + Description: "Card Expiration Date", |
| 79 | + Enc: encoding.BCD, |
| 80 | + Pref: prefix.BCD.Fixed, |
| 81 | + }), |
| 82 | + 10: field.NewComposite(&field.Spec{ |
| 83 | + Length: 999, |
| 84 | + Description: "Acceptor Information", |
| 85 | + Pref: prefix.ASCII.LLL, |
| 86 | + Tag: &field.TagSpec{ |
| 87 | + Length: 2, |
| 88 | + Enc: encoding.ASCII, |
| 89 | + Sort: sort.StringsByInt, |
| 90 | + }, |
| 91 | + Subfields: map[string]field.Field{ |
| 92 | + "01": field.NewString(&field.Spec{ |
| 93 | + Length: 99, |
| 94 | + Description: "Merchant Name", |
| 95 | + Enc: encoding.ASCII, |
| 96 | + Pref: prefix.ASCII.LL, |
| 97 | + }), |
| 98 | + "02": field.NewString(&field.Spec{ |
| 99 | + Length: 4, |
| 100 | + Description: "Merchant Category Code (MCC)", |
| 101 | + Enc: encoding.ASCII, |
| 102 | + Pref: prefix.ASCII.Fixed, |
| 103 | + }), |
| 104 | + "03": field.NewString(&field.Spec{ |
| 105 | + Length: 10, |
| 106 | + Description: "Merchant Postal Code", |
| 107 | + Enc: encoding.ASCII, |
| 108 | + Pref: prefix.ASCII.LL, |
| 109 | + }), |
| 110 | + "04": field.NewString(&field.Spec{ |
| 111 | + Length: 299, |
| 112 | + Description: "Merchant Website", |
| 113 | + Enc: encoding.ASCII, |
| 114 | + Pref: prefix.ASCII.LLL, |
| 115 | + }), |
| 116 | + }, |
| 117 | + }), |
| 118 | + 11: field.NewString(&field.Spec{ |
| 119 | + Length: 6, |
| 120 | + Description: "Systems Trace Audit Number (STAN)", |
| 121 | + Enc: encoding.BCD, |
| 122 | + Pref: prefix.BCD.Fixed, |
| 123 | + }), |
| 124 | + }, |
| 125 | +} |
| 126 | + |
| 127 | +func TestMessagePackingAndUnpacking(t *testing.T) { |
| 128 | + // We use field tags to map the struct fields to the ISO 8583 fields |
| 129 | + type AcceptorInformation struct { |
| 130 | + MerchantName string `iso8583:"01"` |
| 131 | + MerchantCategoryCode string `iso8583:"02"` |
| 132 | + MerchantPostalCode string `iso8583:"03"` |
| 133 | + MerchantWebsite string `iso8583:"04"` |
| 134 | + } |
| 135 | + |
| 136 | + type AuthorizationRequest struct { |
| 137 | + MTI string `iso8583:"0"` |
| 138 | + PAN string `iso8583:"2"` |
| 139 | + Amount int64 `iso8583:"3"` |
| 140 | + TransactionDatetime string `iso8583:"4"` |
| 141 | + Currency string `iso8583:"7"` |
| 142 | + CVV string `iso8583:"8"` |
| 143 | + ExpirationDate string `iso8583:"9"` |
| 144 | + AcceptorInformation *AcceptorInformation `iso8583:"10"` |
| 145 | + STAN string `iso8583:"11"` |
| 146 | + } |
| 147 | + |
| 148 | + // Create a new message |
| 149 | + requestMessage := iso8583.NewMessage(spec) |
| 150 | + |
| 151 | + // use time from our example |
| 152 | + timeFromExample := "240812160140" |
| 153 | + processingTime, err := time.Parse("060102150405", timeFromExample) |
| 154 | + require.NotEmpty(t, processingTime) |
| 155 | + require.NoError(t, err) |
| 156 | + |
| 157 | + // Set the message fields |
| 158 | + err = requestMessage.Marshal(&AuthorizationRequest{ |
| 159 | + MTI: "0100", |
| 160 | + PAN: "4242424242424242", |
| 161 | + Amount: 1000, |
| 162 | + // TransactionDatetime: processingTime.Format("060102150405"), |
| 163 | + TransactionDatetime: time.Now().Format("060102150405"), |
| 164 | + Currency: "840", |
| 165 | + CVV: "7890", |
| 166 | + ExpirationDate: "2512", |
| 167 | + AcceptorInformation: &AcceptorInformation{ |
| 168 | + MerchantName: "Merchant Name", |
| 169 | + MerchantCategoryCode: "1234", |
| 170 | + MerchantPostalCode: "1234567890", |
| 171 | + MerchantWebsite: "https://www.merchant.com", |
| 172 | + }, |
| 173 | + STAN: "000001", |
| 174 | + }) |
| 175 | + require.NoError(t, err) |
| 176 | + |
| 177 | + // Pack the message |
| 178 | + packed, err := requestMessage.Pack() |
| 179 | + require.NoError(t, err) |
| 180 | + |
| 181 | + // Unpack the message |
| 182 | + requestMessage = iso8583.NewMessage(spec) |
| 183 | + err = requestMessage.Unpack(packed) |
| 184 | + require.NoError(t, err) |
| 185 | + |
| 186 | + // Unmarshal the message fields |
| 187 | + var authorizationRequest AuthorizationRequest |
| 188 | + err = requestMessage.Unmarshal(&authorizationRequest) |
| 189 | + require.NoError(t, err) |
| 190 | + |
| 191 | + // Check the message fields |
| 192 | + require.Equal(t, "0100", authorizationRequest.MTI) |
| 193 | + require.Equal(t, "4242424242424242", authorizationRequest.PAN) |
| 194 | + require.Equal(t, int64(1000), authorizationRequest.Amount) |
| 195 | + // require.Equal(t, timeFromExample, authorizationRequest.TransactionDatetime) |
| 196 | + require.Equal(t, "840", authorizationRequest.Currency) |
| 197 | + require.Equal(t, "7890", authorizationRequest.CVV) |
| 198 | + require.Equal(t, "2512", authorizationRequest.ExpirationDate) |
| 199 | + require.Equal(t, "Merchant Name", authorizationRequest.AcceptorInformation.MerchantName) |
| 200 | + require.Equal(t, "1234", authorizationRequest.AcceptorInformation.MerchantCategoryCode) |
| 201 | + require.Equal(t, "1234567890", authorizationRequest.AcceptorInformation.MerchantPostalCode) |
| 202 | + require.Equal(t, "https://www.merchant.com", authorizationRequest.AcceptorInformation.MerchantWebsite) |
| 203 | + require.Equal(t, "000001", authorizationRequest.STAN) |
| 204 | + |
| 205 | + // Here is the example of the packed message |
| 206 | + examplePackedMessage := "010073E000000000000031364242424242424242001000240812160140084078902512303636303131334D65726368616E74204E616D653032313233343033313031323334353637383930303430323468747470733A2F2F7777772E6D65726368616E742E636F6D000001" |
| 207 | + |
| 208 | + // Check the packed message |
| 209 | + // using %X to convert the byte slice to a hex string in uppercase |
| 210 | + require.Equal(t, examplePackedMessage, fmt.Sprintf("%X", packed)) |
| 211 | + |
| 212 | + err = iso8583.Describe(requestMessage, os.Stdout) |
| 213 | + require.NoError(t, err) |
| 214 | +} |
0 commit comments