Last active
March 17, 2022 15:44
-
-
Save PaymentComponents/3fdab3b73885450a65b24c889c93c974 to your computer and use it in GitHub Desktop.
Handle EPC SEPA Instant Messages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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