Files
ezbookkeeping/pkg/converters/mt/mt_data_reader_test.go

342 lines
13 KiB
Go

package mt
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs"
)
func TestMT940DataReaderParse(t *testing.T) {
reader := &mt940DataReader{
allLines: []string{
"{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:",
":20:MT940-2025001",
":21:RELATEDREFERENCE",
":25:123456789",
":28C:123/1",
":60F:C250601CNY1234,56",
":61:2506010602DY123,45NTRFTEST//ABC123456",
":86:First Transaction",
"Additional Info",
":61:2506020620CY234,56NSTFFOOBAR//DEF789012",
":86:Second Transaction",
"More Info",
":62F:C250602CNY2345,67",
":64:C250602CNY2345,67",
"-}",
},
}
context := core.NewNullContext()
actualData, err := reader.read(context)
assert.Nil(t, err)
assert.Equal(t, "MT940-2025001", actualData.StatementReferenceNumber)
assert.Equal(t, "RELATEDREFERENCE", actualData.RelatedReference)
assert.Equal(t, "123456789", actualData.AccountId)
assert.Equal(t, "123/1", actualData.SequentialNumber)
assert.Equal(t, MT_MARK_CREDIT, actualData.OpeningBalance.DebitCreditMark)
assert.Equal(t, "250601", actualData.OpeningBalance.Date)
assert.Equal(t, "CNY", actualData.OpeningBalance.Currency)
assert.Equal(t, "1234,56", actualData.OpeningBalance.Amount)
assert.Equal(t, 2, len(actualData.Statements))
assert.Equal(t, "250601", actualData.Statements[0].ValueDate)
assert.Equal(t, "0602", actualData.Statements[0].EntryDate)
assert.Equal(t, MT_MARK_DEBIT, actualData.Statements[0].CreditDebitMark)
assert.Equal(t, "Y", actualData.Statements[0].FundsCode)
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, "ABC123456", actualData.Statements[0].ReferenceOfAccountServicingInstitution)
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)
assert.Equal(t, MT_MARK_CREDIT, actualData.Statements[1].CreditDebitMark)
assert.Equal(t, "Y", actualData.Statements[0].FundsCode)
assert.Equal(t, "234,56", actualData.Statements[1].Amount)
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].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)
assert.Equal(t, "CNY", actualData.ClosingBalance.Currency)
assert.Equal(t, "2345,67", actualData.ClosingBalance.Amount)
assert.Equal(t, MT_MARK_CREDIT, actualData.ClosingAvailableBalance.DebitCreditMark)
assert.Equal(t, "250602", actualData.ClosingAvailableBalance.Date)
assert.Equal(t, "CNY", actualData.ClosingAvailableBalance.Currency)
assert.Equal(t, "2345,67", actualData.ClosingAvailableBalance.Amount)
}
func TestMT940DataReaderParse_NoBlockHeaderFooter(t *testing.T) {
reader := &mt940DataReader{
allLines: []string{
":20:MT940-2025001",
":25:123456789",
":28C:123/1",
":60F:C250601CNY1234,56",
":61:2506010602DY123,45NTRFTEST//ABC123456",
":86:First Transaction",
},
}
context := core.NewNullContext()
actualData, err := reader.read(context)
assert.Nil(t, err)
assert.Equal(t, "MT940-2025001", actualData.StatementReferenceNumber)
assert.Equal(t, "123456789", actualData.AccountId)
assert.Equal(t, "123/1", actualData.SequentialNumber)
assert.Equal(t, MT_MARK_CREDIT, actualData.OpeningBalance.DebitCreditMark)
assert.Equal(t, "250601", actualData.OpeningBalance.Date)
assert.Equal(t, "CNY", actualData.OpeningBalance.Currency)
assert.Equal(t, "1234,56", actualData.OpeningBalance.Amount)
assert.Equal(t, 1, len(actualData.Statements))
assert.Equal(t, "250601", actualData.Statements[0].ValueDate)
assert.Equal(t, "0602", actualData.Statements[0].EntryDate)
assert.Equal(t, MT_MARK_DEBIT, actualData.Statements[0].CreditDebitMark)
assert.Equal(t, "Y", actualData.Statements[0].FundsCode)
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, "ABC123456", actualData.Statements[0].ReferenceOfAccountServicingInstitution)
assert.Equal(t, "First Transaction", actualData.Statements[0].InformationToAccountOwner[0])
}
func TestMT940DataReaderParse_ReferenceForTheAccountOwnerTwoLine(t *testing.T) {
reader := &mt940DataReader{
allLines: []string{
":61:250601D123,45NTRFABCDEFGHIJKLMNOP",
"QRSTUVWXYZ",
},
}
context := core.NewNullContext()
actualData, err := reader.read(context)
assert.Nil(t, err)
assert.Equal(t, 1, len(actualData.Statements))
assert.Equal(t, "250601", actualData.Statements[0].ValueDate)
assert.Equal(t, MT_MARK_DEBIT, actualData.Statements[0].CreditDebitMark)
assert.Equal(t, "123,45", actualData.Statements[0].Amount)
assert.Equal(t, "NTRF", actualData.Statements[0].TransactionTypeIdentificationCode)
assert.Equal(t, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", actualData.Statements[0].ReferenceForAccountOwner)
}
func TestMT940DataReaderParse_InformationToAccountOwnerSixLine(t *testing.T) {
reader := &mt940DataReader{
allLines: []string{
":61:250601D123,45NTRFTEST",
":86:Additional Info Line 1",
"Additional Info Line 2",
"Additional Info Line 3",
"Additional Info Line 4",
"Additional Info Line 5",
"Additional Info Line 6",
},
}
context := core.NewNullContext()
actualData, err := reader.read(context)
assert.Nil(t, err)
assert.Equal(t, 1, len(actualData.Statements))
assert.Equal(t, "250601", actualData.Statements[0].ValueDate)
assert.Equal(t, MT_MARK_DEBIT, actualData.Statements[0].CreditDebitMark)
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].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_InformationToAccountOwnerMoreThanSixLine(t *testing.T) {
reader := &mt940DataReader{
allLines: []string{
":61:250601D123,45NTRFTEST",
":86:Additional Info Line 1",
"Additional Info Line 2",
"Additional Info Line 3",
"Additional Info Line 4",
"Additional Info Line 5",
"Additional Info Line 6",
"Additional Info Line 7",
},
}
context := core.NewNullContext()
actualData, err := reader.read(context)
assert.Nil(t, err)
assert.Equal(t, 1, len(actualData.Statements))
assert.Equal(t, "250601", actualData.Statements[0].ValueDate)
assert.Equal(t, MT_MARK_DEBIT, actualData.Statements[0].CreditDebitMark)
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].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) {
reader := &mt940DataReader{
allLines: []string{
"{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:",
":20:MT940-2025001",
":25:123456789",
":28C:123/1",
":60F:C250601CNY1234,56",
"{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:",
":61:2506010602DY123,45NTRFTEST//ABC123456",
":86:First Transaction",
"-}",
},
}
context := core.NewNullContext()
actualData, err := reader.read(context)
assert.Nil(t, err)
assert.Equal(t, "", actualData.StatementReferenceNumber)
assert.Equal(t, "", actualData.AccountId)
assert.Equal(t, "", actualData.SequentialNumber)
assert.Nil(t, actualData.OpeningBalance)
assert.Equal(t, 1, len(actualData.Statements))
assert.Equal(t, "250601", actualData.Statements[0].ValueDate)
assert.Equal(t, "0602", actualData.Statements[0].EntryDate)
assert.Equal(t, MT_MARK_DEBIT, actualData.Statements[0].CreditDebitMark)
assert.Equal(t, "Y", actualData.Statements[0].FundsCode)
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, "ABC123456", actualData.Statements[0].ReferenceOfAccountServicingInstitution)
}
func TestMT940DataReaderParse_EmptyContent(t *testing.T) {
reader := &mt940DataReader{
allLines: []string{},
}
context := core.NewNullContext()
_, err := reader.read(context)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
}
func TestMT940DataReaderParseBalance_ValidBalance(t *testing.T) {
reader := &mt940DataReader{}
context := core.NewNullContext()
balance, err := reader.parseBalance(context, "C250601CNY1234,56")
assert.Nil(t, err)
assert.Equal(t, MT_MARK_CREDIT, balance.DebitCreditMark)
assert.Equal(t, "250601", balance.Date)
assert.Equal(t, "CNY", balance.Currency)
assert.Equal(t, "1234,56", balance.Amount)
balance, err = reader.parseBalance(context, "D250602USD2345,67")
assert.Nil(t, err)
assert.Equal(t, MT_MARK_DEBIT, balance.DebitCreditMark)
assert.Equal(t, "250602", balance.Date)
assert.Equal(t, "USD", balance.Currency)
assert.Equal(t, "2345,67", balance.Amount)
}
func TestMT940DataReaderParseBalance_InvalidBalance(t *testing.T) {
reader := &mt940DataReader{}
context := core.NewNullContext()
_, err := reader.parseBalance(context, "X250601CNY1234,56")
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
_, err = reader.parseBalance(context, "C")
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
}
func TestMT940DataReaderParseStatement_ValidFields(t *testing.T) {
reader := &mt940DataReader{}
context := core.NewNullContext()
statement, err := reader.parseStatement(context, "2506010602RDY123,45NTRFTEST//ABC123456")
assert.Nil(t, err)
assert.Equal(t, "250601", statement.ValueDate)
assert.Equal(t, "0602", statement.EntryDate)
assert.Equal(t, MT_MARK_REVERSAL_DEBIT, statement.CreditDebitMark)
assert.Equal(t, "Y", statement.FundsCode)
assert.Equal(t, "123,45", statement.Amount)
assert.Equal(t, "NTRF", statement.TransactionTypeIdentificationCode)
assert.Equal(t, "TEST", statement.ReferenceForAccountOwner)
assert.Equal(t, "ABC123456", statement.ReferenceOfAccountServicingInstitution)
statement, err = reader.parseStatement(context, "250601RC234,56NSTFFOOBAR")
assert.Nil(t, err)
assert.Equal(t, "250601", statement.ValueDate)
assert.Equal(t, "", statement.EntryDate)
assert.Equal(t, MT_MARK_REVERSAL_CREDIT, statement.CreditDebitMark)
assert.Equal(t, "234,56", statement.Amount)
assert.Equal(t, "NSTF", statement.TransactionTypeIdentificationCode)
assert.Equal(t, "FOOBAR", statement.ReferenceForAccountOwner)
}
func TestMT940DataReaderParseStatement_InvalidField(t *testing.T) {
reader := &mt940DataReader{}
context := core.NewNullContext()
_, err := reader.parseStatement(context, "250601X123,45NTRFTest")
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
}
func TestMT940DataReaderParseStatement_MissingField(t *testing.T) {
reader := &mt940DataReader{}
context := core.NewNullContext()
// Missing entry date
_, err := reader.parseStatement(context, "2406")
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
// Missing debit/credit mark
_, err = reader.parseStatement(context, "250601060234,56NTRFTEST//ABC123456")
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
// Missing amount
_, err = reader.parseStatement(context, "250601DNTRFTEST//ABC123456")
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
// Missing transaction type identification code
_, err = reader.parseStatement(context, "250601D234,56TEST//ABC123456")
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
// Missing reference for account owner
_, err = reader.parseStatement(context, "250601D234,56NTRF//ABC123456")
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
}