parse information to account owner data in mt940 file
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package mt
|
||||
|
||||
import "strings"
|
||||
|
||||
type mtCreditDebitMark string
|
||||
|
||||
const (
|
||||
@@ -9,6 +11,10 @@ const (
|
||||
MT_MARK_REVERSAL_DEBIT mtCreditDebitMark = "RD"
|
||||
)
|
||||
|
||||
const (
|
||||
MT_INFORMATION_TO_ACCOUNT_OWNER_TAG_REMITTANCE string = "REMI"
|
||||
)
|
||||
|
||||
// mt940Data defines the structure of mt940 data
|
||||
type mt940Data struct {
|
||||
StatementReferenceNumber string
|
||||
@@ -31,7 +37,7 @@ type mtStatement struct {
|
||||
TransactionTypeIdentificationCode string
|
||||
ReferenceForAccountOwner string
|
||||
ReferenceOfAccountServicingInstitution string
|
||||
AdditionalInformation []string
|
||||
InformationToAccountOwner []string
|
||||
}
|
||||
|
||||
// mtBalance defines the structure of mt940 balance
|
||||
@@ -41,3 +47,27 @@ type mtBalance struct {
|
||||
Currency string
|
||||
Amount string
|
||||
}
|
||||
|
||||
// GetInformationToAccountOwnerMap returns a map of additional information
|
||||
func (s *mtStatement) GetInformationToAccountOwnerMap() map[string]string {
|
||||
additionalInfoMap := make(map[string]string, len(s.InformationToAccountOwner))
|
||||
|
||||
for _, info := range s.InformationToAccountOwner {
|
||||
items := strings.Split(info, "/")
|
||||
|
||||
if len(items) < 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
for i := 2; i < len(items); i += 2 {
|
||||
key := strings.TrimSpace(items[i-1])
|
||||
value := strings.TrimSpace(items[i])
|
||||
|
||||
if len(key) > 0 {
|
||||
additionalInfoMap[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return additionalInfoMap
|
||||
}
|
||||
|
||||
@@ -17,20 +17,20 @@ const mtBasicHeaderBlockPrefix = "{1:"
|
||||
const mtTextBlockStartPrefix = "{4:"
|
||||
const mtTextBlockEndPrefix = "-}"
|
||||
const mtTagPrefix = ':'
|
||||
const mtStatementAdditionalInformationMaxLines = 6
|
||||
const mtInformationToAccountOwnerMaxLines = 6
|
||||
|
||||
const (
|
||||
mtTagStatementReferenceNumber = ":20:"
|
||||
mtTagRelatedReference = ":21:"
|
||||
mtTagAccountId = ":25:"
|
||||
mtTagSequentialNumber = ":28C:"
|
||||
mtTagOpeningBalanceF = ":60F:"
|
||||
mtTagOpeningBalanceM = ":60M:"
|
||||
mtTagClosingBalanceF = ":62F:"
|
||||
mtTagClosingBalanceM = ":62M:"
|
||||
mtTagClosingAvailableBalance = ":64:"
|
||||
mtTagStatementLine = ":61:"
|
||||
mtTagStatementAdditionalInformation = ":86:"
|
||||
mtTagStatementReferenceNumber = ":20:"
|
||||
mtTagRelatedReference = ":21:"
|
||||
mtTagAccountId = ":25:"
|
||||
mtTagSequentialNumber = ":28C:"
|
||||
mtTagOpeningBalanceF = ":60F:"
|
||||
mtTagOpeningBalanceM = ":60M:"
|
||||
mtTagClosingBalanceF = ":62F:"
|
||||
mtTagClosingBalanceM = ":62M:"
|
||||
mtTagClosingAvailableBalance = ":64:"
|
||||
mtTagStatementLine = ":61:"
|
||||
mtTagInformationToAccountOwner = ":86:"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -123,16 +123,16 @@ func (r *mt940DataReader) read(ctx core.Context) (*mt940Data, error) {
|
||||
|
||||
currentStatement = statement
|
||||
lastTag = mtTagStatementLine
|
||||
} else if strings.HasPrefix(line, mtTagStatementAdditionalInformation) && currentStatement != nil {
|
||||
currentStatement.AdditionalInformation = make([]string, 1)
|
||||
currentStatement.AdditionalInformation[0] = line[len(mtTagStatementAdditionalInformation):]
|
||||
lastTag = mtTagStatementAdditionalInformation
|
||||
} else if strings.HasPrefix(line, mtTagInformationToAccountOwner) && currentStatement != nil {
|
||||
currentStatement.InformationToAccountOwner = make([]string, 1)
|
||||
currentStatement.InformationToAccountOwner[0] = line[len(mtTagInformationToAccountOwner):]
|
||||
lastTag = mtTagInformationToAccountOwner
|
||||
} else if line[0] != mtTagPrefix && lastTag == mtTagStatementLine && currentStatement != nil {
|
||||
currentStatement.ReferenceForAccountOwner += line
|
||||
lastTag = ""
|
||||
} else if line[0] != mtTagPrefix && lastTag == mtTagStatementAdditionalInformation && currentStatement != nil && len(currentStatement.AdditionalInformation) < mtStatementAdditionalInformationMaxLines {
|
||||
currentStatement.AdditionalInformation = append(currentStatement.AdditionalInformation, line)
|
||||
lastTag = mtTagStatementAdditionalInformation
|
||||
} else if line[0] != mtTagPrefix && lastTag == mtTagInformationToAccountOwner && currentStatement != nil && len(currentStatement.InformationToAccountOwner) < mtInformationToAccountOwnerMaxLines {
|
||||
currentStatement.InformationToAccountOwner = append(currentStatement.InformationToAccountOwner, line)
|
||||
lastTag = mtTagInformationToAccountOwner
|
||||
} else {
|
||||
log.Warnf(ctx, "[mt_data_reader.read] unsupported line \"%s\" and skip this line", line)
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ func TestMT940DataReaderParse(t *testing.T) {
|
||||
assert.Equal(t, "NTRF", actualData.Statements[0].TransactionTypeIdentificationCode)
|
||||
assert.Equal(t, "TEST", actualData.Statements[0].ReferenceForAccountOwner)
|
||||
assert.Equal(t, "ABC123456", actualData.Statements[0].ReferenceOfAccountServicingInstitution)
|
||||
assert.Equal(t, "First Transaction", actualData.Statements[0].AdditionalInformation[0])
|
||||
assert.Equal(t, "Additional Info", actualData.Statements[0].AdditionalInformation[1])
|
||||
assert.Equal(t, "First Transaction", actualData.Statements[0].InformationToAccountOwner[0])
|
||||
assert.Equal(t, "Additional Info", actualData.Statements[0].InformationToAccountOwner[1])
|
||||
|
||||
assert.Equal(t, "250602", actualData.Statements[1].ValueDate)
|
||||
assert.Equal(t, "0620", actualData.Statements[1].EntryDate)
|
||||
@@ -65,8 +65,8 @@ func TestMT940DataReaderParse(t *testing.T) {
|
||||
assert.Equal(t, "NSTF", actualData.Statements[1].TransactionTypeIdentificationCode)
|
||||
assert.Equal(t, "FOOBAR", actualData.Statements[1].ReferenceForAccountOwner)
|
||||
assert.Equal(t, "DEF789012", actualData.Statements[1].ReferenceOfAccountServicingInstitution)
|
||||
assert.Equal(t, "Second Transaction", actualData.Statements[1].AdditionalInformation[0])
|
||||
assert.Equal(t, "More Info", actualData.Statements[1].AdditionalInformation[1])
|
||||
assert.Equal(t, "Second Transaction", actualData.Statements[1].InformationToAccountOwner[0])
|
||||
assert.Equal(t, "More Info", actualData.Statements[1].InformationToAccountOwner[1])
|
||||
|
||||
assert.Equal(t, MT_MARK_CREDIT, actualData.ClosingBalance.DebitCreditMark)
|
||||
assert.Equal(t, "250602", actualData.ClosingBalance.Date)
|
||||
@@ -114,7 +114,7 @@ func TestMT940DataReaderParse_NoBlockHeaderFooter(t *testing.T) {
|
||||
assert.Equal(t, "NTRF", actualData.Statements[0].TransactionTypeIdentificationCode)
|
||||
assert.Equal(t, "TEST", actualData.Statements[0].ReferenceForAccountOwner)
|
||||
assert.Equal(t, "ABC123456", actualData.Statements[0].ReferenceOfAccountServicingInstitution)
|
||||
assert.Equal(t, "First Transaction", actualData.Statements[0].AdditionalInformation[0])
|
||||
assert.Equal(t, "First Transaction", actualData.Statements[0].InformationToAccountOwner[0])
|
||||
}
|
||||
|
||||
func TestMT940DataReaderParse_ReferenceForTheAccountOwnerTwoLine(t *testing.T) {
|
||||
@@ -138,7 +138,7 @@ func TestMT940DataReaderParse_ReferenceForTheAccountOwnerTwoLine(t *testing.T) {
|
||||
assert.Equal(t, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", actualData.Statements[0].ReferenceForAccountOwner)
|
||||
}
|
||||
|
||||
func TestMT940DataReaderParse_AdditionalInformationSixLine(t *testing.T) {
|
||||
func TestMT940DataReaderParse_InformationToAccountOwnerSixLine(t *testing.T) {
|
||||
reader := &mt940DataReader{
|
||||
allLines: []string{
|
||||
":61:250601D123,45NTRFTEST",
|
||||
@@ -162,16 +162,16 @@ func TestMT940DataReaderParse_AdditionalInformationSixLine(t *testing.T) {
|
||||
assert.Equal(t, "123,45", actualData.Statements[0].Amount)
|
||||
assert.Equal(t, "NTRF", actualData.Statements[0].TransactionTypeIdentificationCode)
|
||||
assert.Equal(t, "TEST", actualData.Statements[0].ReferenceForAccountOwner)
|
||||
assert.Equal(t, 6, len(actualData.Statements[0].AdditionalInformation))
|
||||
assert.Equal(t, "Additional Info Line 1", actualData.Statements[0].AdditionalInformation[0])
|
||||
assert.Equal(t, "Additional Info Line 2", actualData.Statements[0].AdditionalInformation[1])
|
||||
assert.Equal(t, "Additional Info Line 3", actualData.Statements[0].AdditionalInformation[2])
|
||||
assert.Equal(t, "Additional Info Line 4", actualData.Statements[0].AdditionalInformation[3])
|
||||
assert.Equal(t, "Additional Info Line 5", actualData.Statements[0].AdditionalInformation[4])
|
||||
assert.Equal(t, "Additional Info Line 6", actualData.Statements[0].AdditionalInformation[5])
|
||||
assert.Equal(t, 6, len(actualData.Statements[0].InformationToAccountOwner))
|
||||
assert.Equal(t, "Additional Info Line 1", actualData.Statements[0].InformationToAccountOwner[0])
|
||||
assert.Equal(t, "Additional Info Line 2", actualData.Statements[0].InformationToAccountOwner[1])
|
||||
assert.Equal(t, "Additional Info Line 3", actualData.Statements[0].InformationToAccountOwner[2])
|
||||
assert.Equal(t, "Additional Info Line 4", actualData.Statements[0].InformationToAccountOwner[3])
|
||||
assert.Equal(t, "Additional Info Line 5", actualData.Statements[0].InformationToAccountOwner[4])
|
||||
assert.Equal(t, "Additional Info Line 6", actualData.Statements[0].InformationToAccountOwner[5])
|
||||
}
|
||||
|
||||
func TestMT940DataReaderParse_AdditionalInformationMoreThanSixLine(t *testing.T) {
|
||||
func TestMT940DataReaderParse_InformationToAccountOwnerMoreThanSixLine(t *testing.T) {
|
||||
reader := &mt940DataReader{
|
||||
allLines: []string{
|
||||
":61:250601D123,45NTRFTEST",
|
||||
@@ -196,13 +196,13 @@ func TestMT940DataReaderParse_AdditionalInformationMoreThanSixLine(t *testing.T)
|
||||
assert.Equal(t, "123,45", actualData.Statements[0].Amount)
|
||||
assert.Equal(t, "NTRF", actualData.Statements[0].TransactionTypeIdentificationCode)
|
||||
assert.Equal(t, "TEST", actualData.Statements[0].ReferenceForAccountOwner)
|
||||
assert.Equal(t, 6, len(actualData.Statements[0].AdditionalInformation))
|
||||
assert.Equal(t, "Additional Info Line 1", actualData.Statements[0].AdditionalInformation[0])
|
||||
assert.Equal(t, "Additional Info Line 2", actualData.Statements[0].AdditionalInformation[1])
|
||||
assert.Equal(t, "Additional Info Line 3", actualData.Statements[0].AdditionalInformation[2])
|
||||
assert.Equal(t, "Additional Info Line 4", actualData.Statements[0].AdditionalInformation[3])
|
||||
assert.Equal(t, "Additional Info Line 5", actualData.Statements[0].AdditionalInformation[4])
|
||||
assert.Equal(t, "Additional Info Line 6", actualData.Statements[0].AdditionalInformation[5])
|
||||
assert.Equal(t, 6, len(actualData.Statements[0].InformationToAccountOwner))
|
||||
assert.Equal(t, "Additional Info Line 1", actualData.Statements[0].InformationToAccountOwner[0])
|
||||
assert.Equal(t, "Additional Info Line 2", actualData.Statements[0].InformationToAccountOwner[1])
|
||||
assert.Equal(t, "Additional Info Line 3", actualData.Statements[0].InformationToAccountOwner[2])
|
||||
assert.Equal(t, "Additional Info Line 4", actualData.Statements[0].InformationToAccountOwner[3])
|
||||
assert.Equal(t, "Additional Info Line 5", actualData.Statements[0].InformationToAccountOwner[4])
|
||||
assert.Equal(t, "Additional Info Line 6", actualData.Statements[0].InformationToAccountOwner[5])
|
||||
}
|
||||
|
||||
func TestMT940DataReaderParse_DuplicateBlockHeader(t *testing.T) {
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package mt
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMtStatementGetInformationToAccountOwnerMap_OneLineMultiTags(t *testing.T) {
|
||||
statement := &mtStatement{
|
||||
InformationToAccountOwner: []string{
|
||||
"/REMI/test value/ABC/123/FOO/Bar",
|
||||
},
|
||||
}
|
||||
|
||||
expectedMap := map[string]string{
|
||||
"REMI": "test value",
|
||||
"ABC": "123",
|
||||
"FOO": "Bar",
|
||||
}
|
||||
|
||||
actualMap := statement.GetInformationToAccountOwnerMap()
|
||||
assert.Equal(t, expectedMap, actualMap)
|
||||
}
|
||||
|
||||
func TestMtStatementGetInformationToAccountOwnerMap_MultipleLines(t *testing.T) {
|
||||
statement := &mtStatement{
|
||||
InformationToAccountOwner: []string{
|
||||
"/REMI/test/ABC/123",
|
||||
"/FOO/Bar/HELLO/World",
|
||||
},
|
||||
}
|
||||
|
||||
expectedMap := map[string]string{
|
||||
"REMI": "test",
|
||||
"ABC": "123",
|
||||
"FOO": "Bar",
|
||||
"HELLO": "World",
|
||||
}
|
||||
|
||||
actualMap := statement.GetInformationToAccountOwnerMap()
|
||||
assert.Equal(t, expectedMap, actualMap)
|
||||
}
|
||||
|
||||
func TestMtStatementGetInformationToAccountOwnerMap_EmptyInformation(t *testing.T) {
|
||||
statement := &mtStatement{
|
||||
InformationToAccountOwner: []string{},
|
||||
}
|
||||
|
||||
expectedMap := map[string]string{}
|
||||
|
||||
actualMap := statement.GetInformationToAccountOwnerMap()
|
||||
assert.Equal(t, expectedMap, actualMap)
|
||||
}
|
||||
|
||||
func TestMtStatementGetInformationToAccountOwnerMap_InvalidFormat(t *testing.T) {
|
||||
statement := &mtStatement{
|
||||
InformationToAccountOwner: []string{
|
||||
"/ABCD",
|
||||
"EFGH/123",
|
||||
"/REMI/123/ABC",
|
||||
},
|
||||
}
|
||||
|
||||
expectedMap := map[string]string{
|
||||
"REMI": "123",
|
||||
}
|
||||
|
||||
actualMap := statement.GetInformationToAccountOwnerMap()
|
||||
assert.Equal(t, expectedMap, actualMap)
|
||||
}
|
||||
|
||||
func TestMtStatementGetInformationToAccountOwnerMap_EmptyKeyValue(t *testing.T) {
|
||||
statement := &mtStatement{
|
||||
InformationToAccountOwner: []string{
|
||||
"/REMI//ABC/ /DEF/456",
|
||||
"/GHI/123/JKL/def",
|
||||
},
|
||||
}
|
||||
|
||||
expectedMap := map[string]string{
|
||||
"REMI": "",
|
||||
"ABC": "",
|
||||
"DEF": "456",
|
||||
"GHI": "123",
|
||||
"JKL": "def",
|
||||
}
|
||||
|
||||
actualMap := statement.GetInformationToAccountOwnerMap()
|
||||
assert.Equal(t, expectedMap, actualMap)
|
||||
}
|
||||
@@ -151,7 +151,15 @@ func (t *mt940TransactionDataRowIterator) parseTransaction(ctx core.Context, use
|
||||
return nil, errs.ErrTransactionTypeInvalid
|
||||
}
|
||||
|
||||
data[datatable.TRANSACTION_DATA_TABLE_DESCRIPTION] = strings.Join(statement.AdditionalInformation, "\n")
|
||||
informationToAccountOwnerMap := statement.GetInformationToAccountOwnerMap()
|
||||
|
||||
if len(informationToAccountOwnerMap) > 0 {
|
||||
if value, exists := informationToAccountOwnerMap[MT_INFORMATION_TO_ACCOUNT_OWNER_TAG_REMITTANCE]; exists {
|
||||
data[datatable.TRANSACTION_DATA_TABLE_DESCRIPTION] = value
|
||||
}
|
||||
} else {
|
||||
data[datatable.TRANSACTION_DATA_TABLE_DESCRIPTION] = strings.Join(statement.InformationToAccountOwner, "\n")
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user