You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
4.9 KiB

package pain
import (
"fmt"
"strings"
"time"
)
type DrctDbtTxInf struct {
Id PaymentId `xml:"PmtId"`
Amount CurrencyWithAmount `xml:"InstdAmt"`
Transaction DrctDbtTx `xml:"DrctDbtTx"`
Agent DbtrAgt `xml:"DbtrAgt"`
Debtor Dbtr `xml:"Dbtr"`
Account DbtrAcct `xml:"DbtrAcct"`
Info RmtInf `xml:"RmtInf"`
}
func NewDirectDebitTransaction(debtor Dbtr, account DbtrAcct, mandateInfo MndtRltdInf, amount float64, additionalInfo string, counter int) DrctDbtTxInf {
e2eid := fmt.Sprintf("%v%04d", time.Now().Format("20060102"), counter)
return DrctDbtTxInf{
Id: PaymentId{
EndToEndId: e2eid,
},
Amount: CurrencyWithAmount{
Currency: "EUR",
Value: fmt.Sprintf("%.2f", amount),
},
Transaction: DrctDbtTx{
MandateRelatedInfo: mandateInfo,
},
Agent: DbtrAgt{
InstitutionId: FinInstnId{
BIC: "NOTPROVIDED",
},
},
Debtor: debtor,
Account: account,
Info: RmtInf{
Value: additionalInfo,
},
}
}
func (d *DrctDbtTxInf) Valid() error {
var err []string
if e := d.Id.Valid(); e != nil {
err = append(err, fmt.Sprintf("%v", e))
}
if e := d.Amount.Valid(); e != nil {
err = append(err, fmt.Sprintf("%v", e))
}
if e := d.Transaction.Valid(); e != nil {
err = append(err, fmt.Sprintf("%v", e))
}
if e := d.Agent.Valid(); e != nil {
err = append(err, fmt.Sprintf("%v", e))
}
if e := d.Debtor.Valid(); e != nil {
err = append(err, fmt.Sprintf("%v", e))
}
if e := d.Account.Valid(); e != nil {
err = append(err, fmt.Sprintf("%v", e))
}
if len(err) > 0 {
return fmt.Errorf("direct debit transaction information not valid: %v", strings.Join(err, ", "))
}
return nil
}
type CurrencyWithAmount struct {
Currency string `xml:"Ccy,attr"`
Value string `xml:",innerxml"`
}
func (c *CurrencyWithAmount) Valid() error {
var err []string
if c.Currency != "EUR" {
err = append(err, "expected Ccy EUR")
}
if !SEPARegexps["InstdAmnt"].MatchString(c.Value) {
err = append(err, "value does not match format")
}
if len(err) > 0 {
return fmt.Errorf("currency with amount not valid: %v", strings.Join(err, ", "))
}
return nil
}
type PaymentId struct {
InstrumentId string `xml:"InstrId,omitempty"`
EndToEndId string `xml:"EndToEndId"`
}
func (p *PaymentId) Valid() error {
var err []string
if !SEPARegexps["InstrId"].MatchString(p.InstrumentId) {
err = append(err, "instrument id does not match format")
}
if !SEPARegexps["EndToEndId"].MatchString(p.EndToEndId) {
err = append(err, "end-to-end id does not match format")
}
if len(err) > 0 {
return fmt.Errorf("payment id not valid: %v", strings.Join(err, ", "))
}
return nil
}
type MndtRltdInf struct {
Id string `xml:"MndtId"`
SignatureDate string `xml:"DtOfSgntr"`
IsAmended bool `xml:"AmdmntInd"`
//AmdmntInfDtls is optional
//ElctrncSgntr is optional
}
// NewMandateInfo truncates id to 35 characters
func NewMandateInfo(id, signatureDate string) MndtRltdInf {
if len(id) > 35 {
id = id[0:35]
}
return MndtRltdInf{
Id: id,
SignatureDate: signatureDate,
IsAmended: false,
}
}
func (m *MndtRltdInf) Valid() error {
var err []string
if !SEPARegexps["MndtId"].MatchString(m.Id) {
err = append(err, "mandate id does not match format")
}
if !SEPARegexps["DtOfSgntr"].MatchString(m.SignatureDate) {
err = append(err, "date of signature does not match format")
}
if len(err) > 0 {
return fmt.Errorf("mandate related information is not valid: %v", strings.Join(err, ", "))
}
return nil
}
type DrctDbtTx struct {
MandateRelatedInfo MndtRltdInf `xml:"MndtRltdInf"`
//CdtrSchemeId is optional
}
func (d *DrctDbtTx) Valid() error {
return d.MandateRelatedInfo.Valid()
}
type DbtrAgt struct {
InstitutionId FinInstnId `xml:"FinInstnId"`
}
func (d *DbtrAgt) Valid() error {
return d.InstitutionId.Valid()
}
type Dbtr struct {
Name string `xml:"Nm"`
Address PstlAdr `xml:"PstlAdr"`
}
func NewDebtor(name, line1, line2, country string) Dbtr {
return Dbtr{
Name: name,
Address: PstlAdr{
Country: country,
AddressLines: []AdrLine{
AdrLine(line1),
AdrLine(line2),
},
},
}
}
func (d *Dbtr) Valid() error {
var err []string
if !SEPARegexps["Nm"].MatchString(d.Name) {
err = append(err, "name does not match format")
}
if e := d.Address.Valid(); e != nil {
err = append(err, fmt.Sprintf("%v", e))
}
if len(err) > 0 {
return fmt.Errorf("dbtr not valid: %v", strings.Join(err, ", "))
}
return nil
}
type DbtrAcct struct {
Id IBAN `xml:"Id"`
}
func NewDbtrAcct(iban string) DbtrAcct {
return DbtrAcct{
Id: IBAN{
IBAN: iban,
},
}
}
func (d *DbtrAcct) Valid() error {
return d.Id.Valid()
}
type RmtInf struct {
Value string `xml:"Ustrd"`
}
func (r *RmtInf) Valid() error {
if !SEPARegexps["Ustrd"].MatchString(r.Value) {
return fmt.Errorf("remittance information does not match format")
}
return nil
}