Skip to content

Instantly share code, notes, and snippets.

@PaymentComponents
Last active March 17, 2022 15:44
Show Gist options
  • Save PaymentComponents/3fdab3b73885450a65b24c889c93c974 to your computer and use it in GitHub Desktop.
Save PaymentComponents/3fdab3b73885450a65b24c889c93c974 to your computer and use it in GitHub Desktop.
Handle EPC SEPA Instant Messages
package com.paymentcomponents.sepa;
import gr.datamation.sepa.core.messages.common.MsgReplyInfo;
import gr.datamation.sepa.core.messages.common.ReasonCode;
import gr.datamation.sepa.core.messages.sct_inst.epc.camt.FIToFIPaymentCancellationRequest;
import gr.datamation.sepa.core.messages.sct_inst.epc.camt.ResolutionOfInvestigation;
import gr.datamation.sepa.core.messages.sct_inst.epc.pacs.FIToFICustomerCreditTransfer;
import gr.datamation.sepa.core.messages.sct_inst.epc.pacs.FIToFIPaymentStatusReport;
import gr.datamation.sepa.core.messages.sct_inst.epc.pacs.FIToFIPaymentStatusRequest;
import gr.datamation.sepa.core.messages.sct_inst.epc.pacs.PaymentReturn;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Collections;
public class SepaInstant {
public static void main(String... args) throws Exception {
execute();
}
public static void execute() throws Exception {
parseAndValidateMessage();
autoReplyPacs004();
autoReplyCamt056();
autoReplyCamt029();
autoReplyPacs028TransactionStatusInvestigation();
autoReplyPacs028StatusRequestForRecall();
autoReplyPacs002Positive();
autoReplyPacs002Negative();
}
private static FIToFICustomerCreditTransfer parseAndValidateMessage() {
//You have to initiate the message object using the suitable constructor.
//In order to parse and validate a pacs.008 you need to use FIToFICustomerCreditTransfer
//FIToFICustomerCreditTransfer > matches the xml element <FIToFICstmrCdtTrf>
//Advice https://github.com/Payment-Components/demo-sepa#epc---sepa-instant for all possible messages
FIToFICustomerCreditTransfer messageObject = new FIToFICustomerCreditTransfer();
try {
//Use parseAndValidateString() to fill the messageObject the content of the message and validate it
//validation fills the message variable errors object with any issue found during validation
messageObject.parseAndValidateString(validPacs008String);
//In order to validate against specific EPC SEPA Instant rules, you should call the below validate()
messageObject.validate(FIToFICustomerCreditTransfer.EpcType.CREDIT_TRANSFER);
Utils.printValidMessageOrErrors(messageObject);
return messageObject;
} catch (Exception e) {
e.printStackTrace();
System.err.println("Message cannot be parsed");
}
return null;
}
private static void autoReplyPacs004() throws Exception {
FIToFICustomerCreditTransfer messageObject = parseAndValidateMessage();
//You have to initiate the class for the return
PaymentReturn replyMessage = new PaymentReturn();
//You have to initiate MsgReplyInfo which contains information for the return
MsgReplyInfo msgReplyInfo = new MsgReplyInfo();
msgReplyInfo.setRtrid("RTRDE0920000891");
msgReplyInfo.setRCode(new ReasonCode());
msgReplyInfo.getRCode().setCharges(new BigDecimal("2.00")); //Optional
msgReplyInfo.getRCode().setTgmString("Additional Info");
//Reply message is filled with information of the original message and MsgReplyInfo
messageObject.autoReply(replyMessage, Collections.singletonList(msgReplyInfo));
//Fill extra elements, required for the reply message
replyMessage.setElement("/GrpHdr/MsgId", "1234");
replyMessage.setElement("/GrpHdr/IntrBkSttlmDt", Calendar.getInstance());
replyMessage.setElement("/GrpHdr/SttlmInf/SttlmMtd", "INDA");
//Validate the reply message
replyMessage.validate(PaymentReturn.EpcType.POSITIVE_RESPONSE_TO_RECALL);
//OR
// replyMessage.validate(PaymentReturn.EpcType.POSITIVE_RESPONSE_TO_RECALL_FROM_ORIGINATOR);
Utils.printValidMessageOrErrors(replyMessage);
}
private static void autoReplyCamt056() throws Exception {
FIToFICustomerCreditTransfer messageObject = parseAndValidateMessage();
//You have to initiate the class for the cancellation request
FIToFIPaymentCancellationRequest replyMessage = new FIToFIPaymentCancellationRequest();
//You have to initiate MsgReplyInfo which contains information for the cancellation request
MsgReplyInfo msgReplyInfo = new MsgReplyInfo();
msgReplyInfo.setRtrid("RTRDE0920000891");
msgReplyInfo.setRCode(new ReasonCode(ReasonCode.CD, "DUPL"));
//OR
// msgReplyInfo.setRCode(new ReasonCode(ReasonCode.PRTRY, "TECH"));
// msgReplyInfo.getRCode().setTgmString("Additional Info"); //Optional
//Reply message is filled with information of the original message and MsgReplyInfo
messageObject.autoReply(replyMessage, Collections.singletonList(msgReplyInfo));
//Fill extra elements, required for the reply message
replyMessage.setElement("/Assgnmt/Id", "1234");
replyMessage.setElement("/Assgnmt/Assgnr/Agt/FinInstnId/BIC", "TESTBICA");
replyMessage.setElement("/Assgnmt/Assgne/Agt/FinInstnId/BIC", "TESTBICB");
replyMessage.setElement("/Assgnmt/CreDtTm", Calendar.getInstance());
//Validate the reply message
replyMessage.validate(FIToFIPaymentCancellationRequest.EpcType.REQUEST_FOR_RECALL);
//OR
// replyMessage.validate(FIToFIPaymentCancellationRequest.EpcType.REQUEST_FOR_RECALL_FROM_ORIGINATOR);
Utils.printValidMessageOrErrors(replyMessage);
}
private static void autoReplyCamt029() throws Exception {
FIToFICustomerCreditTransfer messageObject = parseAndValidateMessage();
//You have to initiate the class for the resolution of investigation
ResolutionOfInvestigation replyMessage = new ResolutionOfInvestigation();
//You have to initiate MsgReplyInfo which contains information for the resolution of investigation
MsgReplyInfo msgReplyInfo = new MsgReplyInfo();
msgReplyInfo.setRtrid("RTRDE0920000891");
msgReplyInfo.setRCode(new ReasonCode(ReasonCode.CD, "LEGL"));
//OR
// msgReplyInfo.setRCode(new ReasonCode(ReasonCode.PRTRY, "ARDT"));
//CancellationId should start with ATR6(Request for Recall) or AT53(Request for Recall from Originator)
msgReplyInfo.getRCode().setCancellationId("ATR6 CANCELLATIONID");
msgReplyInfo.getRCode().setLegalReasonCode1("Reason1");
msgReplyInfo.getRCode().setLegalReasonCode2("Reason2");
//OR
// msgReplyInfo.getRCode().setFraudReason(new ArrayList<>());
// msgReplyInfo.getRCode().getFraudReason().add("Fraud1");
// msgReplyInfo.getRCode().getFraudReason().add("Fraud2");
//Reply message is filled with information of the original message and MsgReplyInfo
messageObject.autoReply(replyMessage, Collections.singletonList(msgReplyInfo));
//Fill extra elements, required for the reply message
replyMessage.setElement("/Assgnmt/Id", "1234");
replyMessage.setElement("/Assgnmt/Assgnr/Agt/FinInstnId/BIC", "TESTBICA");
replyMessage.setElement("/Assgnmt/Assgne/Agt/FinInstnId/BIC", "TESTBICB");
replyMessage.setElement("/Assgnmt/CreDtTm", Calendar.getInstance());
//Validate the reply message
replyMessage.validate(ResolutionOfInvestigation.EpcType.NEGATIVE_RESPONSE_TO_RECALL);
//OR
// replyMessage.validate(ResolutionOfInvestigation.EpcType.NEGATIVE_RESPONSE_TO_RECALL_FROM_ORIGINATOR);
Utils.printValidMessageOrErrors(replyMessage);
}
private static void autoReplyPacs028TransactionStatusInvestigation() throws Exception {
FIToFICustomerCreditTransfer messageObject = parseAndValidateMessage();
//You have to initiate the class for the payment status request
FIToFIPaymentStatusRequest replyMessage = new FIToFIPaymentStatusRequest();
//You have to initiate MsgReplyInfo which contains information for the payment status request
MsgReplyInfo msgReplyInfo = new MsgReplyInfo();
msgReplyInfo.setRtrid("RTRDE0920000891");
msgReplyInfo.setOrgnlMsgNmId("pacs.008");
//Reply message is filled with information of the original message and MsgReplyInfo
messageObject.autoReply(replyMessage, Collections.singletonList(msgReplyInfo));
//Fill extra elements, required for the reply message
replyMessage.setElement("/GrpHdr/MsgId", "1234");
replyMessage.setElement("/GrpHdr/CreDtTm", Calendar.getInstance());
//Validate the reply message
replyMessage.validate(FIToFIPaymentStatusRequest.EpcType.TRANSACTION_STATUS_INVESTIGATION);
Utils.printValidMessageOrErrors(replyMessage);
}
private static void autoReplyPacs028StatusRequestForRecall() throws Exception {
FIToFICustomerCreditTransfer messageObject = parseAndValidateMessage();
//You have to initiate the class for the payment status request
FIToFIPaymentStatusRequest replyMessage = new FIToFIPaymentStatusRequest();
//You have to initiate MsgReplyInfo which contains information for the payment status request
MsgReplyInfo msgReplyInfo = new MsgReplyInfo();
msgReplyInfo.setRtrid("RTRDE0920000891");
msgReplyInfo.setOrgnlMsgNmId("camt.056");
//Reply message is filled with information of the original message and MsgReplyInfo
messageObject.autoReply(replyMessage, Collections.singletonList(msgReplyInfo));
//Fill extra elements, required for the reply message
replyMessage.setElement("/GrpHdr/MsgId", "1234");
replyMessage.setElement("/GrpHdr/CreDtTm", Calendar.getInstance());
//Validate the reply message
replyMessage.validate(FIToFIPaymentStatusRequest.EpcType.REQUEST_FOR_STATUS_UPDATE_FOR_RECALL);
//OR
// replyMessage.validate(FIToFIPaymentStatusRequest.EpcType.REQUEST_FOR_STATUS_UPDATE_FOR_RECALL_FROM_ORIGINATOR);
Utils.printValidMessageOrErrors(replyMessage);
}
private static void autoReplyPacs002Positive() throws Exception {
FIToFICustomerCreditTransfer messageObject = parseAndValidateMessage();
//You have to initiate the class for the payment status report
FIToFIPaymentStatusReport replyMessage = new FIToFIPaymentStatusReport();
//You have to initiate MsgReplyInfo which contains information for the payment status report
MsgReplyInfo msgReplyInfo = new MsgReplyInfo();
msgReplyInfo.setRtrid("RTRDE0920000891");
//Reply message is filled with information of the original message and MsgReplyInfo
messageObject.autoReply(replyMessage, Collections.singletonList(msgReplyInfo));
//Fill extra elements, required for the reply message
replyMessage.setElement("/GrpHdr/MsgId", "1234");
replyMessage.setElement("/GrpHdr/CreDtTm", Calendar.getInstance());
//Validate the reply message
replyMessage.validate(FIToFIPaymentStatusReport.EpcType.POSITIVE);
Utils.printValidMessageOrErrors(replyMessage);
}
private static void autoReplyPacs002Negative() throws Exception {
FIToFICustomerCreditTransfer messageObject = parseAndValidateMessage();
//You have to initiate the class for the payment status request
FIToFIPaymentStatusReport replyMessage = new FIToFIPaymentStatusReport();
//You have to initiate MsgReplyInfo which contains information for the payment status request
MsgReplyInfo msgReplyInfo = new MsgReplyInfo();
msgReplyInfo.setRtrid("RTRDE0920000891");
msgReplyInfo.setRCode(new ReasonCode(ReasonCode.CD, "AC01"));
//Reply message is filled with information of the original message and MsgReplyInfo
messageObject.autoReply(replyMessage, Collections.singletonList(msgReplyInfo));
//Fill extra elements, required for the reply message
replyMessage.setElement("/GrpHdr/MsgId", "1234");
replyMessage.setElement("/GrpHdr/CreDtTm", Calendar.getInstance());
//Validate the reply message
replyMessage.validate(FIToFIPaymentStatusReport.EpcType.NEGATIVE);
Utils.printValidMessageOrErrors(replyMessage);
}
private static final String validPacs008String = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<Document xmlns=\"urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02\">\n" +
" <FIToFICstmrCdtTrf>\n" +
" <GrpHdr>\n" +
" <MsgId>PSCXMILBGRAA20101115114110891</MsgId>\n" +
" <CreDtTm>2012-12-13T12:12:12</CreDtTm>\n" +
" <NbOfTxs>1</NbOfTxs>\n" +
" <TtlIntrBkSttlmAmt Ccy=\"EUR\">23.00</TtlIntrBkSttlmAmt>\n" +
" <IntrBkSttlmDt>2012-12-13</IntrBkSttlmDt>\n" +
" <SttlmInf>\n" +
" <SttlmMtd>CLRG</SttlmMtd>\n" +
" <SttlmAcct>\n" +
" <Id>\n" +
" <IBAN>DE89370400440532013000</IBAN>\n" +
" </Id>\n" +
" </SttlmAcct>\n" +
" <ClrSys>\n" +
" <Prtry>ST2</Prtry>\n" +
" </ClrSys>\n" +
" </SttlmInf>\n" +
" <PmtTpInf>\n" +
" <SvcLvl>\n" +
" <Cd>SEPA</Cd>\n" +
" </SvcLvl>\n" +
" <LclInstrm>\n" +
" <Cd>INST</Cd>\n" +
" </LclInstrm>\n" +
" <CtgyPurp>\n" +
" <Cd>Purp</Cd>\n" +
" </CtgyPurp>\n" +
" </PmtTpInf>\n" +
" <InstgAgt>\n" +
" <FinInstnId>\n" +
" <BIC>DABAIE2DXXX</BIC>\n" +
" </FinInstnId>\n" +
" </InstgAgt>\n" +
" <InstdAgt>\n" +
" <FinInstnId>\n" +
" <BIC>DABAIE2EXXX</BIC>\n" +
" </FinInstnId>\n" +
" </InstdAgt>\n" +
" </GrpHdr>\n" +
" <CdtTrfTxInf>\n" +
" <PmtId>\n" +
" <InstrId>DEUTDE0920000891</InstrId>\n" +
" <EndToEndId>NOTPROVIDED</EndToEndId>\n" +
" <TxId>DEUTDEFF011OS10222891</TxId>\n" +
" </PmtId>\n" +
" <IntrBkSttlmAmt Ccy=\"EUR\">23.00</IntrBkSttlmAmt>\n" +
" <AccptncDtTm>2012-12-13T12:13:12</AccptncDtTm>\n" +
" <ChrgBr>SLEV</ChrgBr>\n" +
" <UltmtDbtr>\n" +
" <Nm>Ultimate Debtor Name</Nm>\n" +
" <Id>\n" +
" <OrgId>\n" +
" <BICOrBEI>TESTBICAXXX</BICOrBEI>\n" +
" </OrgId>\n" +
" </Id>\n" +
" </UltmtDbtr>\n" +
" <Dbtr>\n" +
" <Nm>Debtor name</Nm>\n" +
" <PstlAdr>\n" +
" <Ctry>DE</Ctry>\n" +
" <AdrLine>Indirizzo 1 Dbtr</AdrLine>\n" +
" <AdrLine>Indirizzo 2 Dbtr</AdrLine>\n" +
" </PstlAdr>\n" +
" <Id>\n" +
" <OrgId>\n" +
" <BICOrBEI>TESTBICBXXX</BICOrBEI>\n" +
" </OrgId>\n" +
" </Id>\n" +
" </Dbtr>\n" +
" <DbtrAcct>\n" +
" <Id>\n" +
" <IBAN>DE73340302860352858328</IBAN>\n" +
" </Id>\n" +
" </DbtrAcct>\n" +
" <DbtrAgt>\n" +
" <FinInstnId>\n" +
" <BIC>DEUTDEFFXXX</BIC>\n" +
" </FinInstnId>\n" +
" </DbtrAgt>\n" +
" <CdtrAgt>\n" +
" <FinInstnId>\n" +
" <BIC>BCYPCY2N</BIC>\n" +
" </FinInstnId>\n" +
" </CdtrAgt>\n" +
" <Cdtr>\n" +
" <Nm>Creditor Name</Nm>\n" +
" <PstlAdr>\n" +
" <Ctry>GR</Ctry>\n" +
" <AdrLine>Creditor Address</AdrLine>\n" +
" </PstlAdr>\n" +
" <Id>\n" +
" <OrgId>\n" +
" <BICOrBEI>TESTBICCXXX</BICOrBEI>\n" +
" </OrgId>\n" +
" </Id>\n" +
" </Cdtr>\n" +
" <CdtrAcct>\n" +
" <Id>\n" +
" <IBAN>GR2703801380000000000089777</IBAN>\n" +
" </Id>\n" +
" </CdtrAcct>\n" +
" <UltmtCdtr>\n" +
" <Nm>Ultimate creditor name</Nm>\n" +
" <Id>\n" +
" <OrgId>\n" +
" <BICOrBEI>TESTBICDXXX</BICOrBEI>\n" +
" </OrgId>\n" +
" </Id>\n" +
" </UltmtCdtr>\n" +
" <Purp>\n" +
" <Cd>str1</Cd>\n" +
" </Purp>\n" +
" <RmtInf>\n" +
" <Ustrd>Unstructed Rmt Inf</Ustrd>\n" +
" <Strd>\n" +
" <CdtrRefInf>\n" +
" <Tp>\n" +
" <CdOrPrtry>\n" +
" <Cd>SCOR</Cd>\n" +
" </CdOrPrtry>\n" +
" <Issr>RmtInf Issuer</Issr>\n" +
" </Tp>\n" +
" <Ref>RmtInf Ref</Ref>\n" +
" </CdtrRefInf>\n" +
" </Strd>\n" +
" </RmtInf>\n" +
" </CdtTrfTxInf>\n" +
" </FIToFICstmrCdtTrf>\n" +
"</Document>";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment