Mastercard supports various transaction types, including:
- Purchase
- Cash Advance
- Balance Inquiry
- Refund
Each of these transaction types has specific requirements and data elements that need to be included in the ISO-8583 message.
Mastercard uses several specific data elements in their ISO-8583 implementation. Here are some of the key fields:
This field is used for various purposes, including additional transaction data, loyalty program information, and other Mastercard-specific data.
This field contains information about the point-of-sale terminal and transaction environment.
This field is used for network-specific information and can contain various subfields.
Let's implement a Java class to handle Mastercard-specific data elements:
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOException;
import org.springframework.stereotype.Component;
@Component
public class MastercardDataElementHandler {
public void setAdditionalData(ISOMsg isoMsg, String additionalData) throws ISOException {
isoMsg.set(48, additionalData);
}
public void setPOSData(ISOMsg isoMsg, String posData) throws ISOException {
isoMsg.set(61, posData);
}
public void setNetworkData(ISOMsg isoMsg, String networkData) throws ISOException {
isoMsg.set(63, networkData);
}
public String getAdditionalData(ISOMsg isoMsg) throws ISOException {
return isoMsg.getString(48);
}
public String getPOSData(ISOMsg isoMsg) throws ISOException {
return isoMsg.getString(61);
}
public String getNetworkData(ISOMsg isoMsg) throws ISOException {
return isoMsg.getString(63);
}
}Mastercard uses specific processing codes to identify the type of transaction. Here are some common processing codes:
- Purchase: 00
- Cash Advance: 01
- Void: 02
- Refund: 20
Let's implement a Java enum to represent these processing codes:
public enum MastercardProcessingCode {
PURCHASE("00"),
CASH_ADVANCE("01"),
VOID("02"),
REFUND("20");
private final String code;
MastercardProcessingCode(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public static MastercardProcessingCode fromCode(String code) {
for (MastercardProcessingCode processingCode : values()) {
if (processingCode.getCode().equals(code)) {
return processingCode;
}
}
throw new IllegalArgumentException("Invalid Mastercard processing code: " + code);
}
}Now, let's create a service to handle Mastercard transactions:
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MastercardTransactionService {
@Autowired
private MastercardDataElementHandler dataElementHandler;
public ISOMsg createPurchaseRequest(String pan, String amount, String merchantId) throws ISOException {
ISOMsg isoMsg = new ISOMsg();
isoMsg.setMTI("0200");
isoMsg.set(2, pan);
isoMsg.set(3, MastercardProcessingCode.PURCHASE.getCode());
isoMsg.set(4, amount);
isoMsg.set(42, merchantId);
// Set additional Mastercard-specific data
dataElementHandler.setAdditionalData(isoMsg, "Additional data for purchase");
dataElementHandler.setPOSData(isoMsg, "POS data for purchase");
dataElementHandler.setNetworkData(isoMsg, "Network data for purchase");
return isoMsg;
}
public ISOMsg createCashAdvanceRequest(String pan, String amount, String merchantId) throws ISOException {
ISOMsg isoMsg = new ISOMsg();
isoMsg.setMTI("0200");
isoMsg.set(2, pan);
isoMsg.set(3, MastercardProcessingCode.CASH_ADVANCE.getCode());
isoMsg.set(4, amount);
isoMsg.set(42, merchantId);
// Set additional Mastercard-specific data
dataElementHandler.setAdditionalData(isoMsg, "Additional data for cash advance");
dataElementHandler.setPOSData(isoMsg, "POS data for cash advance");
dataElementHandler.setNetworkData(isoMsg, "Network data for cash advance");
return isoMsg;
}
public ISOMsg createRefundRequest(String pan, String amount, String merchantId, String originalTransactionId) throws ISOException {
ISOMsg isoMsg = new ISOMsg();
isoMsg.setMTI("0200");
isoMsg.set(2, pan);
isoMsg.set(3, MastercardProcessingCode.REFUND.getCode());
isoMsg.set(4, amount);
isoMsg.set(42, merchantId);
isoMsg.set(37, originalTransactionId);
// Set additional Mastercard-specific data
dataElementHandler.setAdditionalData(isoMsg, "Additional data for refund");
dataElementHandler.setPOSData(isoMsg, "POS data for refund");
dataElementHandler.setNetworkData(isoMsg, "Network data for refund");
return isoMsg;
}
public boolean isApproved(ISOMsg response) throws ISOException {
String responseCode = response.getString(39);
return "00".equals(responseCode);
}
}Now, let's create a test class to verify the functionality of our Mastercard transaction service:
import org.jpos.iso.ISOMsg;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
public class MastercardTransactionServiceTest {
@Mock
private MastercardDataElementHandler dataElementHandler;
@InjectMocks
private MastercardTransactionService transactionService;
@Test
public void testCreatePurchaseRequest() throws Exception {
ISOMsg purchaseRequest = transactionService.createPurchaseRequest("1234567890123456", "100000", "MERCHANT01");
assertThat(purchaseRequest.getMTI()).isEqualTo("0200");
assertThat(purchaseRequest.getString(2)).isEqualTo("1234567890123456");
assertThat(purchaseRequest.getString(3)).isEqualTo(MastercardProcessingCode.PURCHASE.getCode());
assertThat(purchaseRequest.getString(4)).isEqualTo("100000");
assertThat(purchaseRequest.getString(42)).isEqualTo("MERCHANT01");
verify(dataElementHandler).setAdditionalData(purchaseRequest, "Additional data for purchase");
verify(dataElementHandler).setPOSData(purchaseRequest, "POS data for purchase");
verify(dataElementHandler).setNetworkData(purchaseRequest, "Network data for purchase");
}
@Test
public void testCreateCashAdvanceRequest() throws Exception {
ISOMsg cashAdvanceRequest = transactionService.createCashAdvanceRequest("1234567890123456", "50000", "MERCHANT01");
assertThat(cashAdvanceRequest.getMTI()).isEqualTo("0200");
assertThat(cashAdvanceRequest.getString(2)).isEqualTo("1234567890123456");
assertThat(cashAdvanceRequest.getString(3)).isEqualTo(MastercardProcessingCode.CASH_ADVANCE.getCode());
assertThat(cashAdvanceRequest.getString(4)).isEqualTo("50000");
assertThat(cashAdvanceRequest.getString(42)).isEqualTo("MERCHANT01");
verify(dataElementHandler).setAdditionalData(cashAdvanceRequest, "Additional data for cash advance");
verify(dataElementHandler).setPOSData(cashAdvanceRequest, "POS data for cash advance");
verify(dataElementHandler).setNetworkData(cashAdvanceRequest, "Network data for cash advance");
}
@Test
public void testCreateRefundRequest() throws Exception {
ISOMsg refundRequest = transactionService.createRefundRequest("1234567890123456", "25000", "MERCHANT01", "123456789");
assertThat(refundRequest.getMTI()).isEqualTo("0200");
assertThat(refundRequest.getString(2)).isEqualTo("1234567890123456");
assertThat(refundRequest.getString(3)).isEqualTo(MastercardProcessingCode.REFUND.getCode());
assertThat(refundRequest.getString(4)).isEqualTo("25000");
assertThat(refundRequest.getString(42)).isEqualTo("MERCHANT01");
assertThat(refundRequest.getString(37)).isEqualTo("123456789");
verify(dataElementHandler).setAdditionalData(refundRequest, "Additional data for refund");
verify(dataElementHandler).setPOSData(refundRequest, "POS data for refund");
verify(dataElementHandler).setNetworkData(refundRequest, "Network data for refund");
}
@Test
public void testIsApproved() throws Exception {
ISOMsg approvedResponse = new ISOMsg();
approvedResponse.set(39, "00");
ISOMsg declinedResponse = new ISOMsg();
declinedResponse.set(39, "05");
assertThat(transactionService.isApproved(approvedResponse)).isTrue();
assertThat(transactionService.isApproved(declinedResponse)).isFalse();
}
}This implementation covers the main aspects of Mastercard-specific ISO-8583 message handling, including:
- Creating purchase, cash advance, and refund requests
- Handling Mastercard-specific data elements (fields 48, 61, and 63)
- Using the correct processing codes for different transaction types
- Checking the approval status of a response message