Browse Source

Restructure PAIN package into group_header, payment_information (WIP)

master
Gerdriaan Mulder 6 years ago
parent
commit
2e662f09af
  1. 38
      pain/group_header.go
  2. 146
      pain/pain.go
  3. 20
      pain/pain_regexp.go
  4. 130
      pain/payment_information.go

38
pain/group_header.go

@ -0,0 +1,38 @@
package pain
import (
"fmt"
)
type GrpHdr struct {
MessageId string `xml:"MsgId"`
Timestamp string `xml:"CreDtTm"`
NumTx string `xml:"NbOfTxs"`
Sum string `xml:"CtrlSum"`
InitiatingParty PartyIdSEPA1 `xml:"InitgPty"`
}
func (g *GrpHdr) Valid() error {
var err []string
if !SEPARegexps["MsgId"].MatchString(g.MessageId) {
err = append(err, "msgId did not match expected format")
}
if !SEPARegexps["CreDtTm"].MatchString(g.Timestamp) {
err = append(err, "timestamp did not match expected format")
}
if !SEPARegexps["NbOfTxs"].MatchString(g.NumTx) {
err = append(err, "numtx did not match expected format")
}
if !SEPARegexps["CtrlSum"].MatchString(g.Sum) {
err = append(err, "sum did not match expected format")
}
// Note: we assume g.InitiatingParty is initialized.
if !SEPARegexps["Nm"].MatchString(g.InitiatingParty.Name) {
err = append(err, "initiating party's name did not match expected format")
}
if len(err) > 0 {
return fmt.Errorf("group header not valid: %v", strings.Join(err, ", "))
}
return nil
}

146
pain/pain.go

@ -6,24 +6,6 @@ import (
"strings" "strings"
) )
var (
SEPARegexps = map[string]*regexp.Regexp{
"CreDtTm": ISODateTime,
"CtrlSum": RestrictedDecimalNumber,
"IBAN": IBAN2007Identifier,
"Id": RestrictedPersonIdentifierSEPA,
"MsgId": RestrictedIdentificationSEPA1,
"NbOfTxs": Max15NumericText,
"Nm": Max70Text,
"PmtInfId": RestrictedIdentificationSEPA1,
"PmtMetaLclInstrm": LocalInstrumentSEPACode,
"PmtMetaSvcLvl": ServiceLevelSEPACode,
"PmtMtd": PaymentMethod2Code,
"ReqdColltnDt": ISODateTime,
"SeqTp": SequenceType1Code,
}
)
type PainXML struct { type PainXML struct {
GroupHeader GrpHdr `xml:"GrpHdr"` GroupHeader GrpHdr `xml:"GrpHdr"`
PaymentInformation []PmtInf `xml:"PmtInf"` PaymentInformation []PmtInf `xml:"PmtInf"`
@ -49,106 +31,6 @@ func (p *PainXML) Valid() error {
return nil return nil
} }
type GrpHdr struct {
MessageId string `xml:"MsgId"`
Timestamp string `xml:"CreDtTm"`
NumTx string `xml:"NbOfTxs"`
Sum string `xml:"CtrlSum"`
InitiatingParty PartyIdSEPA1 `xml:"InitgPty"`
}
func (g *GrpHdr) Valid() error {
var err []string
if !SEPARegexps["MsgId"].MatchString(g.MessageId) {
err = append(err, "msgId did not match expected format")
}
if !SEPARegexps["CreDtTm"].MatchString(g.Timestamp) {
err = append(err, "timestamp did not match expected format")
}
if !SEPARegexps["NbOfTxs"].MatchString(g.NumTx) {
err = append(err, "numtx did not match expected format")
}
if !SEPARegexps["CtrlSum"].MatchString(g.Sum) {
err = append(err, "sum did not match expected format")
}
// Note: we assume g.InitiatingParty is initialized.
if !SEPARegexps["Nm"].MatchString(g.InitiatingParty.Name) {
err = append(err, "initiating party's name did not match expected format")
}
if len(err) > 0 {
return fmt.Errorf("group header not valid: %v", strings.Join(err, ", "))
}
return nil
}
type PmtInf struct {
Id string `xml:"PmtInfId"`
Method string `xml:"PmtMtd"`
PaymentMeta PmtTpInf `xml:"PmtTpInf"`
CollectionDate string `xml:"ReqdColltnDt"`
Creditor Cdtr `xml:"Cdtr"`
CreditorAccount CdtrAcct `xml:"CdtrAcct"`
CreditorAgent CdtrAgt `xml:"CdtrAgt"`
SchemeId CdtrSchmeId `xml:"CdtrSchmeId"`
}
func (pmt *PmtInf) Valid() error {
var err []string
if !SEPARegexps["PmtInfId"].MatchString(pmt.Id) {
err = append(err, "payment info id does not match expected format")
}
if !SEPARegexps["PmtMtd"].MatchString(pmt.Method) {
err = append(err, "payment method does not match expected format")
}
if e := pmt.PaymentMeta.Valid(); e != nil {
err = append(err, fmt.Sprintf("payment meta not valid: %v", e))
}
if !SEPARegexps["ReqdColltnDt"].MatchString(pmt.CollectionDate) {
err = append(err, "payment collection date does not match expected format")
}
if e := pmt.Creditor.Valid(); e != nil {
err = append(err, fmt.Sprintf("payment creditor not valid: %v", e))
}
if e := pmt.CreditorAccount.Valid(); e != nil {
err = append(err, fmt.Sprintf("payment creditor account not valid: %v", e))
}
if e := pmt.SchemeId.Valid(); e != nil {
err = append(err, fmt.Sprintf("payment scheme id not valid: %v", e))
}
if len(err) > 0 {
return fmt.Errorf("payment info (Id: %q) not valid: %v", pmt.Id, strings.Join(err, ", "))
}
return nil
}
type PmtTpInf struct {
ServiceLevel Code `xml:"SvcLvl"`
LocalInstrument Code `xml:"LclIntrm"`
SequenceType string `xml:"SeqTp"`
}
type Cdtr struct {
Name string `xml:"Nm"`
PostalAddress PstlAddr `xml:"PstlAddr"`
}
func (c *Cdtr) Valid() error {
var err []string
if !SEPARegexps["Nm"].MatchString(c.Name) {
err = append(err, "creditor name does not match format")
}
if e := c.PostalAddress.Valid(); e != nil {
err = append(err, fmt.Sprintf("creditor postal address not valid: %v", e))
}
if len(err) > 0 {
return fmt.Errorf("creditor (Nm: %q) not valid: %v", c.Name, strings.Join(err, ", "))
}
return nil
}
type CdtrAgt struct { type CdtrAgt struct {
InstitutionId FinInstnId `xml:"FinInstId"` InstitutionId FinInstnId `xml:"FinInstId"`
} }
@ -165,34 +47,6 @@ func (c *CdtrSchmeId) Valid() error {
return c.Id.Valid() return c.Id.Valid()
} }
type PstlAddr struct {
Country string `xml:"Ctry"`
AddressLines []AdrLine `xml:"AdrLine"`
}
func (p *PstlAddr) Valid() error {
var err []string
if !SEPARegexps["Ctry"].MatchString(p.Country) {
err = append(err, "country does not match format")
}
if len(p.AddressLines) > 2 {
err = append(err, "expected at most 2 address lines")
}
for i, line := range p.AddressLines {
if !SEPARegexps["AdrLine"].MatchString(string(line)) {
err = append(err, fmt.Sprintf("address line %d (%q) does not match format", i, line))
}
}
if len(err) > 0 {
return fmt.Errorf("address not valid: %v", strings.Join(err, ", "))
}
return nil
}
type AdrLine string
type CdtrAcct struct { type CdtrAcct struct {
Id IBAN `xml:"Id"` Id IBAN `xml:"Id"`
} }

20
pain/pain_regexp.go

@ -19,4 +19,24 @@ var (
IBAN2007Identifier = regexp.MustCompile(`[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}`) IBAN2007Identifier = regexp.MustCompile(`[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}`)
RestrictedPersonIdentifierSEPA = regexp.MustCompile(`[a-zA-Z]{2,2}[0-9]{2,2}([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){3,3}([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){1,28}`) RestrictedPersonIdentifierSEPA = regexp.MustCompile(`[a-zA-Z]{2,2}[0-9]{2,2}([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){3,3}([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){1,28}`)
BICIdentifier = regexp.MustCompile(`[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}`)
)
var (
SEPARegexps = map[string]*regexp.Regexp{
"BIC": BICIdentifier,
"CreDtTm": ISODateTime,
"CtrlSum": RestrictedDecimalNumber,
"IBAN": IBAN2007Identifier,
"Id": RestrictedPersonIdentifierSEPA,
"MsgId": RestrictedIdentificationSEPA1,
"NbOfTxs": Max15NumericText,
"Nm": Max70Text,
"PmtInfId": RestrictedIdentificationSEPA1,
"PmtMetaLclInstrm": LocalInstrumentSEPACode,
"PmtMetaSvcLvl": ServiceLevelSEPACode,
"PmtMtd": PaymentMethod2Code,
"ReqdColltnDt": ISODateTime,
"SeqTp": SequenceType1Code,
}
) )

130
pain/payment_information.go

@ -0,0 +1,130 @@
package pain
import (
"fmt"
)
type PmtInf struct {
Id string `xml:"PmtInfId"`
Method string `xml:"PmtMtd"`
PaymentMeta PmtTpInf `xml:"PmtTpInf"`
CollectionDate string `xml:"ReqdColltnDt"`
Creditor Cdtr `xml:"Cdtr"`
CreditorAccount CdtrAcct `xml:"CdtrAcct"`
CreditorAgent CdtrAgt `xml:"CdtrAgt"`
SchemeId CdtrSchmeId `xml:"CdtrSchmeId"`
Transactions []DrctDbtTxInf `xml:"DrctDbtTxInf"`
}
func (pmt *PmtInf) Valid() error {
var err []string
if !SEPARegexps["PmtInfId"].MatchString(pmt.Id) {
err = append(err, "payment info id does not match expected format")
}
if !SEPARegexps["PmtMtd"].MatchString(pmt.Method) {
err = append(err, "payment method does not match expected format")
}
if e := pmt.PaymentMeta.Valid(); e != nil {
err = append(err, fmt.Sprintf("payment meta not valid: %v", e))
}
if !SEPARegexps["ReqdColltnDt"].MatchString(pmt.CollectionDate) {
err = append(err, "payment collection date does not match expected format")
}
if e := pmt.Creditor.Valid(); e != nil {
err = append(err, fmt.Sprintf("payment creditor not valid: %v", e))
}
if e := pmt.CreditorAccount.Valid(); e != nil {
err = append(err, fmt.Sprintf("payment creditor account not valid: %v", e))
}
if e := pmt.CreditorAgent.Valid(); e != nil {
err = append(err, fmt.Sprintf("payment creditor agent not valid: %v", e))
}
if e := pmt.SchemeId.Valid(); e != nil {
err = append(err, fmt.Sprintf("payment scheme id not valid: %v", e))
}
if len(err) > 0 {
return fmt.Errorf("payment info (Id: %q) not valid: %v", pmt.Id, strings.Join(err, ", "))
}
return nil
}
type PmtTpInf struct {
ServiceLevel Code `xml:"SvcLvl"`
LocalInstrument Code `xml:"LclIntrm"`
SequenceType string `xml:"SeqTp"`
}
type Cdtr struct {
Name string `xml:"Nm"`
PostalAddress PstlAddr `xml:"PstlAddr"`
}
func (c *Cdtr) Valid() error {
var err []string
if !SEPARegexps["Nm"].MatchString(c.Name) {
err = append(err, "creditor name does not match format")
}
if e := c.PostalAddress.Valid(); e != nil {
err = append(err, fmt.Sprintf("creditor postal address not valid: %v", e))
}
if len(err) > 0 {
return fmt.Errorf("creditor (Nm: %q) not valid: %v", c.Name, strings.Join(err, ", "))
}
return nil
}
type AdrLine string
type PstlAddr struct {
Country string `xml:"Ctry"`
AddressLines []AdrLine `xml:"AdrLine"`
}
func (p *PstlAddr) Valid() error {
var err []string
if !SEPARegexps["Ctry"].MatchString(p.Country) {
err = append(err, "country does not match format")
}
if len(p.AddressLines) > 2 {
err = append(err, "expected at most 2 address lines")
}
for i, line := range p.AddressLines {
if !SEPARegexps["AdrLine"].MatchString(string(line)) {
err = append(err, fmt.Sprintf("address line %d (%q) does not match format", i, line))
}
}
if len(err) > 0 {
return fmt.Errorf("address not valid: %v", strings.Join(err, ", "))
}
return nil
}
type CdtrAgt struct {
InstitutionId FinInstnId `xml:"FinInstId"`
}
func (c *CdtrAgt) Valid() error {
return c.InstituionId.Valid()
}
type FinInstnId struct {
BIC string `xml:"BIC"`
}
func (f *FinInstnId) Valid() error {
if !SEPARegexps["BIC"].MatchString(f.BIC) {
return fmt.Errorf("BIC not in expected format")
}
return nil
}
type CdtrSchmeId struct {
Id PartyIdSEPA3 `xml:"Id"`
}
func (c *CdtrSchmeId) Valid() error {
return c.Id.Valid()
}
Loading…
Cancel
Save