Creating SEPA Files

In this Excel Model you can create an SEPA XML file using the details you enter on the SEPA Debit tab. I used Chilkat XML when working with XML, I have also used MS XML but find Chilkat better. Chilkat XML is free and you can download the program from their website.

Sepa Setup
SEPA Setup

To start using the model you will need to complete the setup details tab. The cells with a pink background are formula driven and while the model isn’t protected these should not be overwritten.

Adding Customers
SEPA Customers

On the customer tab enter the customers details , the IBAN Check will validate that the IBAN is technically valid. The customer code is used as your unique identifier for identifier with your bank, a good practice is to use the code from your accounting system. The date of signature defines when the customer signed your direct debit mandate. This will be passed to the bank in the XML file, this cannot be a date in the future.

Sepa XML File Generation
Entering the direct debit details

The customer code cell is a drop-down linked to the customer tab. select a customer from the drop-down and the other details will populate. Only customers with a value will be generated on the excel file.

Before a file will be generated the system will ensure that all the mandatory fields are completed. This is shown on the screen as an error count.

In the next version of this file I will add an archive function to copy the data on the SEPA Debit tab to the archive tab. I am working on a video to demonstrate this model. I also have an SEPA Access Database which I will post once the code is updated to the current Chilkat Release.

You can download the current model from this link and make any changes to suit your own environment.

If you have any issues drop me an email on support@anythingaccess.com.

Creating SEPA File – vba Function
Function MakeXML()
On Error GoTo Errorhandler
Dim tmpRunNo, tmpBank
tmpRunNo = Range("Payment_Number")
tmpBank = Range("BankName")
Dim success As Long
Dim xml As New ChilkatXml
Dim DDInst As ChilkatXml
Dim GroupHeader As ChilkatXml
Dim PaymentInformation As ChilkatXml
Dim DDTransactionInformation As ChilkatXml
'Group Header Fields
Dim MessageID As ChilkatXml
Dim MessageDateTime As ChilkatXml
Dim TotalNumberofPayments As ChilkatXml
Dim TotalValue As ChilkatXml
Dim InitiatingParty As ChilkatXml
Dim InitiatingPartyID As ChilkatXml
Dim InitiatingPartyOrgID As ChilkatXml
Dim InitiatingPartyOthr As ChilkatXml
Dim InitiatingPartyOthrId As ChilkatXml
Dim tmpLoop, tmpBIC, tmpIban, tmpBankName, tmpSignDate
'Payment Fields
Dim PaymentID As ChilkatXml
Dim PaymentMethod As ChilkatXml
Dim BatchBook As ChilkatXml
Dim NoofTrans  As ChilkatXml
Dim TransValue As ChilkatXml
Dim PaymentTypeInformation As ChilkatXml
Dim ServiceLevel As ChilkatXml
Dim ServiceLevelCode As ChilkatXml
Dim LocalInstrument As ChilkatXml
Dim LocalInstrumentCode As ChilkatXml
Dim SequenceTP As ChilkatXml
Dim RequestedCollectionDate As ChilkatXml
Dim Creditor As ChilkatXml
Dim CreditorName As ChilkatXml
Dim CreditorAccount As ChilkatXml
Dim CreditorID As ChilkatXml
Dim CreditorIBAN As ChilkatXml
Dim CreditorAgentBIC As ChilkatXml
Dim FinInstnId As ChilkatXml
Dim CreditorBIC As ChilkatXml
Dim PmtId As ChilkatXml
Dim PaymentEndToEndId As ChilkatXml
Dim InstructionAmount As ChilkatXml
Dim DDMandatetx As ChilkatXml
Dim MndtRltdInf As ChilkatXml
Dim MandateId As ChilkatXml
Dim MandateSignDate As ChilkatXml
Dim CdtrSchmeId As ChilkatXml
Dim CdtrSchmeIdID As ChilkatXml
Dim PrvtId As ChilkatXml
Dim Othr As ChilkatXml
Dim CreditorSEPAID As ChilkatXml
Dim CreditorSchmeNm As ChilkatXml
Dim CreditorPrtry As ChilkatXml
Dim CustomerAgent As ChilkatXml
Dim CustomerFinInstnId As ChilkatXml
Dim CustomerBIC As ChilkatXml
Dim Customer As ChilkatXml
Dim CustomerName As ChilkatXml
Dim CustomerAccount As ChilkatXml
Dim CustomerAccId As ChilkatXml
Dim CustomerIBAN As ChilkatXml
Dim PL_CdtrSchmeId As ChilkatXml
Dim PL_CdtrSchmeIdID As ChilkatXml
Dim PL_PrvtId As ChilkatXml
Dim PL_Othr As ChilkatXml
Dim PL_CreditorSEPAID As ChilkatXml
Dim PL_CreditorSchmeNm As ChilkatXml
Dim PL_CreditorPrtry As ChilkatXml
Dim tmpMandateID As String
xml.Tag = "Document"
xml.addAttribute "xmlns", "urn:iso:std:iso:20022:tech:xsd:pain.008.001.02"
Set DDInst = xml.NewChild("CstmrDrctDbtInitn", "")
'Payment Group Information
Set GroupHeader = DDInst.NewChild("GrpHdr", "")
Set MessageID = GroupHeader.NewChild("MsgId", Format(Now(), "YYYYMMDDhhss") & "-" & tmpRunNo)
Set MessageDateTime = GroupHeader.NewChild("CreDtTm", Format(Date, "YYYY-MM-DD") & "T" & Format(Now(), "HH:mm:SS"))
Set TotalNumberofPayments = GroupHeader.NewChild("NbOfTxs", Range("Number_of_Payments"))
Set TotalValue = GroupHeader.NewChild(" CtrlSum", Format(Range("Total_Payment_Value"), "#.00"))
Set InitiatingParty = GroupHeader.NewChild("InitgPty", "") ' Sepa User ID
Set InitiatingPartyID = InitiatingParty.NewChild("Id", "")
'this may be redundant - when originally written AIB had a different format to the others
If tmpBank = "AIB" Then
Set InitiatingPartyOrgID = InitiatingPartyID.NewChild("OrgId", "")
Set InitiatingPartyOthr = InitiatingPartyOrgID.NewChild("Othr", "")
Set InitiatingPartyOthrId = InitiatingPartyOthr.NewChild("Id", Range("Sepa_User_ID"))
ElseIf tmpBank = "BOI" Then
Set InitiatingPartyOrgID = InitiatingPartyID.NewChild("PrvtId", "")
Set InitiatingPartyOthr = InitiatingPartyOrgID.NewChild("Othr", "")
Set InitiatingPartyOthrId = InitiatingPartyOthr.NewChild("Id", Range("Sepa_User_ID"))
Else
Set InitiatingPartyOrgID = InitiatingPartyID.NewChild("OrgId", "")
Set InitiatingPartyOthr = InitiatingPartyOrgID.NewChild("Othr", "")
Set InitiatingPartyOthrId = InitiatingPartyOthr.NewChild("Id", Range("Sepa_User_ID"))
End If
Set PaymentInformation = DDInst.NewChild("PmtInf", "")
Set PaymentID = PaymentInformation.NewChild("PmtInfId", Right("00000" & tmpRunNo, 5))
Set PaymentMethod = PaymentInformation.NewChild("PmtMtd", "DD")
Set BatchBook = PaymentInformation.NewChild("BtchBookg", "true")
Set NoofTrans = PaymentInformation.NewChild("NbOfTxs", Range("Number_of_Payments"))
Set TransValue = PaymentInformation.NewChild("CtrlSum", Format(Range("Total_Payment_Value"), "#.00"))
Set PaymentTypeInformation = PaymentInformation.NewChild("PmtTpInf", "")
Set ServiceLevel = PaymentTypeInformation.NewChild("SvcLvl", "")
Set ServiceLevelCode = ServiceLevel.NewChild("Cd", "SEPA")
Set LocalInstrument = PaymentTypeInformation.NewChild("LclInstrm", "")
Set LocalInstrumentCode = LocalInstrument.NewChild("Cd", "CORE")
Set SequenceTP = PaymentTypeInformation.NewChild("SeqTp", "RCUR") 'FRST – for First presentation RCUR – for Recurrent presentation OOFF – for Once off presentation FNAL – for Final presenta
Set RequestedCollectionDate = PaymentInformation.NewChild("ReqdColltnDt", Format(Range("Collection_Date"), "YYYY-MM-DD"))
Set Creditor = PaymentInformation.NewChild("Cdtr", "")
Set CreditorName = Creditor.NewChild("Nm", Range("Business_Name"))
Set CreditorAccount = PaymentInformation.NewChild("CdtrAcct", "")
Set CreditorID = CreditorAccount.NewChild("Id", "")
Set CreditorIBAN = CreditorID.NewChild("IBAN", Range("IBAN"))
Set CreditorAgentBIC = PaymentInformation.NewChild("CdtrAgt", "")
Set FinInstnId = CreditorAgentBIC.NewChild("FinInstnId", "")
'Set CreditorBIC = FinInstnId.NewChild("BIC", Range("My_SEPA_BIC"))
'loop on payment
tmpLoop = 1
Sheets("SEPA Debit").Select
Range("Start").Select
Do While ActiveCell.Offset(tmpLoop, 0).Value <> ""
If ActiveCell.Offset(tmpLoop, 3).Value <> 0 Then ' if we have a payment value then proceed
Set DDTransactionInformation = PaymentInformation.NewChild("DrctDbtTxInf", "")
Set PmtId = DDTransactionInformation.NewChild("PmtId", "")
Set PaymentEndToEndId = PmtId.NewChild("EndToEndId", Format(Now(), "YYYYMMDDhhss") & "T" & tmpLoop) ' must be unique
Set InstructionAmount = DDTransactionInformation.NewChild("InstdAmt", Format(Round(ActiveCell.Offset(tmpLoop, 3).Value), "#.00"))
InstructionAmount.addAttribute "Ccy", "EUR"
Set DDMandatetx = DDTransactionInformation.NewChild("DrctDbtTx", "")
Set MndtRltdInf = DDMandatetx.NewChild("MndtRltdInf", "")
Set MandateId = MndtRltdInf.NewChild("MndtId", ActiveCell.Offset(tmpLoop, 0).Value)
tmpSignDate = Format(ActiveCell.Offset(tmpLoop, 5), "YYYY-MM-DD")
Set MandateSignDate = MndtRltdInf.NewChild("DtOfSgntr", tmpSignDate)     
Set PL_CdtrSchmeId = DDMandatetx.NewChild("CdtrSchmeId", "")
Set PL_CdtrSchmeIdID = PL_CdtrSchmeId.NewChild("Id", "")
Set PL_PrvtId = PL_CdtrSchmeIdID.NewChild("PrvtId", "")
Set PL_Othr = PL_PrvtId.NewChild("Othr", "")
Set PL_CreditorSEPAID = PL_Othr.NewChild("Id", Range("Sepa_USer_ID"))
Set PL_CreditorSchmeNm = PL_Othr.NewChild("SchmeNm", "")
Set PL_CreditorPrtry = PL_CreditorSchmeNm.NewChild("Prtry", "SEPA")    
Set CustomerAgent = DDTransactionInformation.NewChild("DbtrAgt", "")
Set CustomerFinInstnId = CustomerAgent.NewChild("FinInstnId", "")
Set Customer = DDTransactionInformation.NewChild("Dbtr", "")
Set CustomerName = Customer.NewChild("Nm", Replace(ActiveCell.Offset(tmpLoop, 1).Value, "&", "+"))
Set CustomerAccount = DDTransactionInformation.NewChild("DbtrAcct", "")
Set CustomerAccId = CustomerAccount.NewChild("Id", "")
tmpIban = ActiveCell.Offset(tmpLoop, 2).Value
Set CustomerIBAN = CustomerAccId.NewChild("IBAN", tmpIban)
'end loop on payment
End If
tmpLoop = tmpLoop + 1
Loop
success = xml.SaveXml(Range("ExportFileName") & "\RunNo_" & tmpRunNo & ".xml")
If (success <> 1) Then
MsgBox xml.LastErrorText
Else
MsgBox "File Created " & Range("ExportFileName") & "\RunNo_" & tmpRunNo & ".xml"
End If
Exit Function
Errorhandler:
MsgBox "An Error Occurred creating the File " & Err.Number & " " & Err.Description
End Function

Sources

I used the vba code for IBAN Validation from Aswin van Woudenberg

Sample IBAN Codes sourced here for testing

AIB Sepa Documentation

Chilkat XML for the XML file creation

IBAN Validation Code

' http://en.wikipedia.org/wiki/International_Bank_Account_Number
Private Const IbanCountryLengths As String = "AL28AD24AT20AZ28BH22BE16BA20BR29BG22CR21HR21CY28CZ24DK18DO28EE20FO18" & _
"FI18FR27GE22DE22GI23GR27GL18GT28HU28IS26IE22IL23IT27KZ20KW30LV21LB28" & _
"LI21LT20LU20MK19MT31MR27MU30MC27MD24ME22NL18NO15PK24PS29PL28PT25RO24" & _
"SM27SA24RS22SK24SI19ES24SE24CH21TN24TR26AE23GB22VG24QA29"
Private Function ValidIbanCountryLength(CountryCode As String, IbanLength As Integer) As Boolean
Dim i As Integer
For i = 0 To Len(IbanCountryLengths) / 4 - 1
If Mid(IbanCountryLengths, i * 4 + 1, 2) = CountryCode And _
CInt(Mid(IbanCountryLengths, i * 4 + 3, 2)) = IbanLength Then
ValidIbanCountryLength = True
Exit Function
End If
Next i
ValidIbanCountryLength = False
End Function
Private Function Mod97(Num As String) As Integer
Dim lngTemp As Long
Dim strTemp As String
Do While Val(Num) >= 97
If Len(Num) > 5 Then
strTemp = Left(Num, 5)
Num = Right(Num, Len(Num) - 5)
Else
strTemp = Num
Num = ""
End If
lngTemp = CLng(strTemp)
lngTemp = lngTemp Mod 97
strTemp = CStr(lngTemp)
Num = strTemp & Num
Loop
Mod97 = CInt(Num)
End Function
Public Function ValidIban(IBAN As String) As Boolean
Dim strIban As String
Dim i As Integer
strIban = UCase(IBAN)
' Remove spaces
strIban = Replace(strIban, " ", "")
' Check if IBAN contains only uppercase characters and numbers
For i = 1 To Len(strIban)
If Not ((Asc(Mid(strIban, i, 1)) <= Asc("9") And Asc(Mid(strIban, i, 1)) >= Asc("0")) Or _
(Asc(Mid(strIban, i, 1)) <= Asc("Z") And Asc(Mid(strIban, i, 1)) >= Asc("A"))) Then
ValidIban = False
Exit Function
End If
Next i
' Check if length of IBAN equals expected length for country
If Not ValidIbanCountryLength(Left(strIban, 2), Len(strIban)) Then
ValidIban = False
Exit Function
End If
' Rearrange
strIban = Right(strIban, Len(strIban) - 4) & Left(strIban, 4)
' Replace characters
For i = 0 To 25
strIban = Replace(strIban, Chr(i + Asc("A")), i + 10)
Next i
' Check remainder
ValidIban = Mod97(strIban) = 1
End Function


Leave a Reply

Your email address will not be published. Required fields are marked *