Skip to content

Latest commit

 

History

History
262 lines (199 loc) · 9.5 KB

File metadata and controls

262 lines (199 loc) · 9.5 KB

6. Mastercard-specific Implementation

6.1. Mastercard transaction types

Mastercard supports various transaction types, including:

  1. Purchase
  2. Cash Advance
  3. Balance Inquiry
  4. Refund

Each of these transaction types has specific requirements and data elements that need to be included in the ISO-8583 message.

6.2. Mastercard-specific data elements

Mastercard uses several specific data elements in their ISO-8583 implementation. Here are some of the key fields:

6.2.1. Field 48: Additional Data - Private Use

This field is used for various purposes, including additional transaction data, loyalty program information, and other Mastercard-specific data.

6.2.2. Field 61: Point-of-Service (POS) Data

This field contains information about the point-of-sale terminal and transaction environment.

6.2.3. Field 63: Network Data

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);
    }
}

6.3. Mastercard processing codes

Mastercard uses specific processing codes to identify the type of transaction. Here are some common processing codes:

  1. Purchase: 00
  2. Cash Advance: 01
  3. Void: 02
  4. 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:

  1. Creating purchase, cash advance, and refund requests
  2. Handling Mastercard-specific data elements (fields 48, 61, and 63)
  3. Using the correct processing codes for different transaction types
  4. Checking the approval status of a response message