import payee field as tags when importing a QIF file (#356)

This commit is contained in:
MaysWind
2025-11-25 00:55:36 +08:00
parent de27c8e6c5
commit 9ff1334584
64 changed files with 1353 additions and 871 deletions
+10 -1
View File
@@ -1405,6 +1405,15 @@ func (a *TransactionsApi) TransactionParseImportFileHandler(c *core.WebContext)
fileType := fileTypes[0] fileType := fileTypes[0]
textualOptions := form.Value["options"]
textualOption := ""
if len(textualOptions) > 0 {
textualOption = textualOptions[0]
}
additionalOptions := converter.ParseImporterOptions(textualOption)
var dataImporter converter.TransactionDataImporter var dataImporter converter.TransactionDataImporter
if converters.IsCustomDelimiterSeparatedValuesFileType(fileType) { if converters.IsCustomDelimiterSeparatedValuesFileType(fileType) {
@@ -1581,7 +1590,7 @@ func (a *TransactionsApi) TransactionParseImportFileHandler(c *core.WebContext)
tagMap := a.transactionTags.GetVisibleTagNameMapByList(tags) tagMap := a.transactionTags.GetVisibleTagNameMapByList(tags)
parsedTransactions, _, _, _, _, _, err := dataImporter.ParseImportedData(c, user, fileData, utcOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) parsedTransactions, _, _, _, _, _, err := dataImporter.ParseImportedData(c, user, fileData, utcOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
if err != nil { if err != nil {
log.Errorf(c, "[transactions.TransactionParseImportFileHandler] failed to parse imported data for user \"uid:%d\", because %s", user.Uid, err.Error()) log.Errorf(c, "[transactions.TransactionParseImportFileHandler] failed to parse imported data for user \"uid:%d\", because %s", user.Uid, err.Error())
+2 -1
View File
@@ -5,6 +5,7 @@ import (
"time" "time"
"github.com/mayswind/ezbookkeeping/pkg/converters" "github.com/mayswind/ezbookkeeping/pkg/converters"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/log" "github.com/mayswind/ezbookkeeping/pkg/log"
@@ -818,7 +819,7 @@ func (l *UserDataCli) ImportTransaction(c *core.CliContext, username string, fil
return err return err
} }
parsedTransactions, newAccounts, newSubExpenseCategories, newSubIncomeCategories, newSubTransferCategories, newTags, err := dataImporter.ParseImportedData(c, user, data, utils.GetTimezoneOffsetMinutes(time.Local), accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) parsedTransactions, newAccounts, newSubExpenseCategories, newSubIncomeCategories, newSubTransferCategories, newTags, err := dataImporter.ParseImportedData(c, user, data, utils.GetTimezoneOffsetMinutes(time.Local), converter.DefaultImporterOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
if err != nil { if err != nil {
log.CliErrorf(c, "[user_data.ImportTransaction] failed to parse imported data for \"%s\", because %s", username, err.Error()) log.CliErrorf(c, "[user_data.ImportTransaction] failed to parse imported data for \"%s\", because %s", username, err.Error())
@@ -53,7 +53,7 @@ type alipayTransactionDataCsvFileImporter struct {
} }
// ParseImportedData returns the imported data by parsing the alipay transaction csv data // ParseImportedData returns the imported data by parsing the alipay transaction csv data
func (c *alipayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *alipayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
enc := simplifiedchinese.GB18030 enc := simplifiedchinese.GB18030
reader := transform.NewReader(bytes.NewReader(data), enc.NewDecoder()) reader := transform.NewReader(bytes.NewReader(data), enc.NewDecoder())
@@ -83,5 +83,5 @@ func (c *alipayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Contex
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, alipayTransactionSupportedColumns, transactionRowParser) transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, alipayTransactionSupportedColumns, transactionRowParser)
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(alipayTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(alipayTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -8,6 +8,7 @@ import (
"golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/encoding/simplifiedchinese"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -15,7 +16,7 @@ import (
) )
func TestAlipayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -35,7 +36,7 @@ func TestAlipayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 4, len(allNewTransactions)) assert.Equal(t, 4, len(allNewTransactions))
@@ -94,7 +95,7 @@ func TestAlipayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
} }
func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -112,7 +113,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid) assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
@@ -132,7 +133,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid) assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
@@ -144,7 +145,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin
} }
func TestAlipayCsvFileImporterParseImportedData_ParseInvestmentRefundTransaction(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_ParseInvestmentRefundTransaction(t *testing.T) {
converter := AlipayAppTransactionDataCsvFileImporter importer := AlipayAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -163,7 +164,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvestmentRefundTransaction
"2024-09-01 01:00:00,Test Account2,xxx-买入,不计收支,0.01,Test Account,退款成功,\n" + "2024-09-01 01:00:00,Test Account2,xxx-买入,不计收支,0.01,Test Account,退款成功,\n" +
"2024-09-01 02:00:00,Test Account2,xxx-买入退款,不计收支,0.01,Test Account,退款成功,\n") "2024-09-01 02:00:00,Test Account2,xxx-买入退款,不计收支,0.01,Test Account,退款成功,\n")
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, len(allNewTransactions)) assert.Equal(t, 2, len(allNewTransactions))
@@ -184,7 +185,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvestmentRefundTransaction
} }
func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -201,7 +202,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
data2, err := simplifiedchinese.GB18030.NewEncoder().String("支付宝交易记录明细查询\n" + data2, err := simplifiedchinese.GB18030.NewEncoder().String("支付宝交易记录明细查询\n" +
@@ -213,12 +214,12 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestAlipayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -235,12 +236,12 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -258,7 +259,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -274,7 +275,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -290,7 +291,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data3), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -307,7 +308,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data4), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -324,7 +325,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data5), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -341,7 +342,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data6), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data6), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -358,7 +359,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data7), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data7), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -367,7 +368,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
} }
func TestAlipayCsvFileImporterParseImportedData_ParseCategory(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_ParseCategory(t *testing.T) {
converter := AlipayAppTransactionDataCsvFileImporter importer := AlipayAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -388,7 +389,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseCategory(t *testing.T) {
"2024-09-01 23:59:59,Test Category3,充值-普通充值,不计收支,0.05,交易成功,\n") "2024-09-01 23:59:59,Test Category3,充值-普通充值,不计收支,0.05,交易成功,\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 3, len(allNewTransactions)) assert.Equal(t, 3, len(allNewTransactions))
@@ -407,7 +408,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseCategory(t *testing.T) {
} }
func TestAlipayCsvFileImporterParseImportedData_ParseRelatedAccount(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_ParseRelatedAccount(t *testing.T) {
converter := AlipayAppTransactionDataCsvFileImporter importer := AlipayAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -434,7 +435,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRelatedAccount(t *testing.T
"2024-09-01 08:00:00,Test Account4,信用卡还款,不计收支,0.01,Test Account,还款成功,repayment,\n") "2024-09-01 08:00:00,Test Account4,信用卡还款,不计收支,0.01,Test Account,还款成功,repayment,\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 9, len(allNewTransactions)) assert.Equal(t, 9, len(allNewTransactions))
@@ -529,7 +530,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRelatedAccount(t *testing.T
} }
func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -546,7 +547,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -561,7 +562,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -569,7 +570,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
} }
func TestAlipayCsvFileImporterParseImportedData_SkipClosedIncomeOrTransferTransaction(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_SkipClosedIncomeOrTransferTransaction(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -586,12 +587,12 @@ func TestAlipayCsvFileImporterParseImportedData_SkipClosedIncomeOrTransferTransa
"2024-09-01 23:59:59 ,充值-普通充值 ,0.05 ,不计收支 ,交易关闭 ,\n" + "2024-09-01 23:59:59 ,充值-普通充值 ,0.05 ,不计收支 ,交易关闭 ,\n" +
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestAlipayCsvFileImporterParseImportedData_SkipUnknownProductTransferTransaction(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_SkipUnknownProductTransferTransaction(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -607,12 +608,12 @@ func TestAlipayCsvFileImporterParseImportedData_SkipUnknownProductTransferTransa
"2024-09-01 23:59:59 ,xxxx ,0.05 ,不计收支 ,交易成功 ,\n" + "2024-09-01 23:59:59 ,xxxx ,0.05 ,不计收支 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestAlipayCsvFileImporterParseImportedData_SkipUnknownStatusTransaction(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_SkipUnknownStatusTransaction(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -628,12 +629,12 @@ func TestAlipayCsvFileImporterParseImportedData_SkipUnknownStatusTransaction(t *
"2024-09-01 01:23:45 ,xxxx ,0.12 ,收入 ,xxxx ,\n" + "2024-09-01 01:23:45 ,xxxx ,0.12 ,收入 ,xxxx ,\n" +
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestAlipayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -647,15 +648,15 @@ func TestAlipayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T)
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
assert.Nil(t, err) assert.Nil(t, err)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message) assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(""), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message) assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
} }
func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -671,7 +672,7 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
"金额(元),收/支 ,交易状态 ,\n" + "金额(元),收/支 ,交易状态 ,\n" +
"0.12 ,收入 ,交易成功 ,\n" + "0.12 ,收入 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Amount Column // Missing Amount Column
@@ -682,7 +683,7 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
"交易创建时间 ,收/支 ,交易状态 ,\n" + "交易创建时间 ,收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,收入 ,交易成功 ,\n" + "2024-09-01 12:34:56 ,收入 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Status Column // Missing Status Column
@@ -693,7 +694,7 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
"交易创建时间 ,金额(元),收/支 ,\n" + "交易创建时间 ,金额(元),收/支 ,\n" +
"2024-09-01 12:34:56 ,0.12 ,收入 ,\n" + "2024-09-01 12:34:56 ,0.12 ,收入 ,\n" +
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data3), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Type Column // Missing Type Column
@@ -704,12 +705,12 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
"交易创建时间 ,金额(元),交易状态 ,\n" + "交易创建时间 ,金额(元),交易状态 ,\n" +
"2024-09-01 12:34:56 ,0.12 ,交易成功 ,\n" + "2024-09-01 12:34:56 ,0.12 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data4), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
} }
func TestAlipayCsvFileImporterParseImportedData_NoTransactionData(t *testing.T) { func TestAlipayCsvFileImporterParseImportedData_NoTransactionData(t *testing.T) {
converter := AlipayWebTransactionDataCsvFileImporter importer := AlipayWebTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -723,6 +724,6 @@ func TestAlipayCsvFileImporterParseImportedData_NoTransactionData(t *testing.T)
"---------------------------------交易记录明细列表------------------------------------\n" + "---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" + "交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" +
"------------------------------------------------------------------------------------\n") "------------------------------------------------------------------------------------\n")
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
@@ -24,7 +24,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the Beancount transaction data // ParseImportedData returns the imported data by parsing the Beancount transaction data
func (c *beancountTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *beancountTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
beancountDataReader, err := createNewBeancountDataReader(ctx, data) beancountDataReader, err := createNewBeancountDataReader(ctx, data)
if err != nil { if err != nil {
@@ -45,5 +45,5 @@ func (c *beancountTransactionDataImporter) ParseImportedData(ctx core.Context, u
dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(beancountTransactionTypeNameMapping, "", "", BEANCOUNT_TRANSACTION_TAG_SEPARATOR) dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(beancountTransactionTypeNameMapping, "", "", BEANCOUNT_TRANSACTION_TAG_SEPARATOR)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -12,7 +13,7 @@ import (
) )
func TestBeancountTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) { func TestBeancountTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) {
converter := BeancountTransactionDataImporter importer := BeancountTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -20,7 +21,7 @@ func TestBeancountTransactionDataFileParseImportedData_MinimumValidData(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 *\n"+ "2024-09-01 *\n"+
" Equity:Opening-Balances -123.45 CNY\n"+ " Equity:Opening-Balances -123.45 CNY\n"+
" Assets:TestAccount 123.45 CNY\n"+ " Assets:TestAccount 123.45 CNY\n"+
@@ -32,7 +33,7 @@ func TestBeancountTransactionDataFileParseImportedData_MinimumValidData(t *testi
" Expenses:TestCategory2 1.00 CNY\n"+ " Expenses:TestCategory2 1.00 CNY\n"+
"2024-09-04 *\n"+ "2024-09-04 *\n"+
" Assets:TestAccount -0.05 CNY\n"+ " Assets:TestAccount -0.05 CNY\n"+
" Assets:TestAccount2 0.05 CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount2 0.05 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -91,7 +92,7 @@ func TestBeancountTransactionDataFileParseImportedData_MinimumValidData(t *testi
} }
func TestBeancountTransactionDataFileParseImportedData_MinimumValidData2(t *testing.T) { func TestBeancountTransactionDataFileParseImportedData_MinimumValidData2(t *testing.T) {
converter := BeancountTransactionDataImporter importer := BeancountTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -99,7 +100,7 @@ func TestBeancountTransactionDataFileParseImportedData_MinimumValidData2(t *test
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 *\n"+ "2024-09-01 *\n"+
" Assets:TestAccount 123.45 CNY\n"+ " Assets:TestAccount 123.45 CNY\n"+
" Equity:Opening-Balances -123.45 CNY\n"+ " Equity:Opening-Balances -123.45 CNY\n"+
@@ -111,7 +112,7 @@ func TestBeancountTransactionDataFileParseImportedData_MinimumValidData2(t *test
" Assets:TestAccount -1.00 CNY\n"+ " Assets:TestAccount -1.00 CNY\n"+
"2024-09-04 *\n"+ "2024-09-04 *\n"+
" Assets:TestAccount2 0.05 CNY\n"+ " Assets:TestAccount2 0.05 CNY\n"+
" Assets:TestAccount -0.05 CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount -0.05 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -170,7 +171,7 @@ func TestBeancountTransactionDataFileParseImportedData_MinimumValidData2(t *test
} }
func TestBeancountTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T) { func TestBeancountTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T) {
converter := BeancountTransactionDataImporter importer := BeancountTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -178,15 +179,15 @@ func TestBeancountTransactionDataFileParseImportedData_ParseInvalidTime(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024/09/01 *\n"+ "2024/09/01 *\n"+
" Equity:Opening-Balances -123.45 CNY\n"+ " Equity:Opening-Balances -123.45 CNY\n"+
" Assets:TestAccount 123.45 CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount 123.45 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestBeancountTransactionDataFileParseImportedData_ParseValidCurrency(t *testing.T) { func TestBeancountTransactionDataFileParseImportedData_ParseValidCurrency(t *testing.T) {
converter := BeancountTransactionDataImporter importer := BeancountTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -194,10 +195,10 @@ func TestBeancountTransactionDataFileParseImportedData_ParseValidCurrency(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 * \"Payee Name\" \"Hello\nWorld\"\n"+ "2024-09-01 * \"Payee Name\" \"Hello\nWorld\"\n"+
" Assets:TestAccount -0.12 USD\n"+ " Assets:TestAccount -0.12 USD\n"+
" Assets:TestAccount2 0.84 CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount2 0.84 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -222,7 +223,7 @@ func TestBeancountTransactionDataFileParseImportedData_ParseValidCurrency(t *tes
} }
func TestBeancountTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T) { func TestBeancountTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := BeancountTransactionDataImporter importer := BeancountTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -230,21 +231,21 @@ func TestBeancountTransactionDataFileParseImportedData_ParseInvalidAmount(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 *\n"+ "2024-09-01 *\n"+
" Equity:Opening-Balances -abc CNY\n"+ " Equity:Opening-Balances -abc CNY\n"+
" Assets:TestAccount abc CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount abc CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 *\n"+ "2024-09-01 *\n"+
" Equity:Opening-Balances -1/0 CNY\n"+ " Equity:Opening-Balances -1/0 CNY\n"+
" Assets:TestAccount 1/0 CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount 1/0 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestBeancountTransactionDataFileParseImportedData_ParseDescription(t *testing.T) { func TestBeancountTransactionDataFileParseImportedData_ParseDescription(t *testing.T) {
converter := BeancountTransactionDataImporter importer := BeancountTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -252,13 +253,13 @@ func TestBeancountTransactionDataFileParseImportedData_ParseDescription(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 * \"foo bar\t#test\n\"\n"+ "2024-09-01 * \"foo bar\t#test\n\"\n"+
" Equity:Opening-Balances -123.45 CNY\n"+ " Equity:Opening-Balances -123.45 CNY\n"+
" Assets:TestAccount 123.45 CNY\n"+ " Assets:TestAccount 123.45 CNY\n"+
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+ "2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
" Income:TestCategory -0.12 CNY\n"+ " Income:TestCategory -0.12 CNY\n"+
" Assets:TestAccount 0.12 CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount 0.12 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -269,7 +270,7 @@ func TestBeancountTransactionDataFileParseImportedData_ParseDescription(t *testi
} }
func TestBeancountTransactionDataFileParseImportedData_InvalidTransaction(t *testing.T) { func TestBeancountTransactionDataFileParseImportedData_InvalidTransaction(t *testing.T) {
converter := BeancountTransactionDataImporter importer := BeancountTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -277,33 +278,33 @@ func TestBeancountTransactionDataFileParseImportedData_InvalidTransaction(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+ "2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
" Assets:TestAccount 0.11 CNY\n"+ " Assets:TestAccount 0.11 CNY\n"+
" Assets:TestAccount2 0.11 CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount2 0.11 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message) assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+ "2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
" Expenses:TestCategory -0.11 CNY\n"+ " Expenses:TestCategory -0.11 CNY\n"+
" Expenses:TestCategory2 0.11 CNY\n"), 0, nil, nil, nil, nil, nil) " Expenses:TestCategory2 0.11 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message) assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+ "2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
" Income:TestCategory -0.11 CNY\n"+ " Income:TestCategory -0.11 CNY\n"+
" Income:TestCategory2 0.11 CNY\n"), 0, nil, nil, nil, nil, nil) " Income:TestCategory2 0.11 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message) assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+ "2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
" Equity:TestCategory -0.11 CNY\n"+ " Equity:TestCategory -0.11 CNY\n"+
" Equity:TestCategory2 0.11 CNY\n"), 0, nil, nil, nil, nil, nil) " Equity:TestCategory2 0.11 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message) assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message)
} }
func TestBeancountTransactionDataFileParseImportedData_NotSupportedToParseSplitTransaction(t *testing.T) { func TestBeancountTransactionDataFileParseImportedData_NotSupportedToParseSplitTransaction(t *testing.T) {
converter := BeancountTransactionDataImporter importer := BeancountTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -311,16 +312,16 @@ func TestBeancountTransactionDataFileParseImportedData_NotSupportedToParseSplitT
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+ "2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
" Assets:TestAccount -0.23 CNY\n"+ " Assets:TestAccount -0.23 CNY\n"+
" Assets:TestAccount2 0.11 CNY\n"+ " Assets:TestAccount2 0.11 CNY\n"+
" Assets:TestAccount3 0.12 CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount3 0.12 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message) assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
} }
func TestBeancountTransactionDataFileParseImportedData_MissingTransactionRequiredData(t *testing.T) { func TestBeancountTransactionDataFileParseImportedData_MissingTransactionRequiredData(t *testing.T) {
converter := BeancountTransactionDataImporter importer := BeancountTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -329,30 +330,30 @@ func TestBeancountTransactionDataFileParseImportedData_MissingTransactionRequire
} }
// Missing Transaction Time // Missing Transaction Time
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"* \"narration\"\n"+ "* \"narration\"\n"+
" Equity:Opening-Balances -123.45 CNY\n"+ " Equity:Opening-Balances -123.45 CNY\n"+
" Assets:TestAccount 123.45 CNY\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount 123.45 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
// Missing Account Name // Missing Account Name
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 * \"narration\"\n"+ "2024-09-01 * \"narration\"\n"+
" Equity:Opening-Balances -123.45 CNY\n"+ " Equity:Opening-Balances -123.45 CNY\n"+
" 123.45 CNY\n"), 0, nil, nil, nil, nil, nil) " 123.45 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message) assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
// Missing Amount // Missing Amount
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 * \"narration\"\n"+ "2024-09-01 * \"narration\"\n"+
" Equity:Opening-Balances\n"+ " Equity:Opening-Balances\n"+
" Assets:TestAccount\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message) assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
// Missing Commodity // Missing Commodity
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 * \"narration\"\n"+ "2024-09-01 * \"narration\"\n"+
" Equity:Opening-Balances -123.45\n"+ " Equity:Opening-Balances -123.45\n"+
" Assets:TestAccount 123.45\n"), 0, nil, nil, nil, nil, nil) " Assets:TestAccount 123.45\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message) assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
} }
@@ -23,7 +23,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the camt.053 file transaction data // ParseImportedData returns the imported data by parsing the camt.053 file transaction data
func (c *camt053TransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *camt053TransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
camt053DataReader, err := createNewCamt053FileReader(data) camt053DataReader, err := createNewCamt053FileReader(data)
if err != nil { if err != nil {
@@ -44,5 +44,5 @@ func (c *camt053TransactionDataImporter) ParseImportedData(ctx core.Context, use
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(camtTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(camtTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -12,7 +13,7 @@ import (
) )
func TestCamt053TransactionDataFileParseImportedData_MinimumValidData(t *testing.T) { func TestCamt053TransactionDataFileParseImportedData_MinimumValidData(t *testing.T) {
converter := Camt053TransactionDataImporter importer := Camt053TransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -20,7 +21,7 @@ func TestCamt053TransactionDataFileParseImportedData_MinimumValidData(t *testing
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -64,7 +65,7 @@ func TestCamt053TransactionDataFileParseImportedData_MinimumValidData(t *testing
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -115,7 +116,7 @@ func TestCamt053TransactionDataFileParseImportedData_MinimumValidData(t *testing
} }
func TestCamt053TransactionDataFileParseImportedData_ParseValidTransactionTime(t *testing.T) { func TestCamt053TransactionDataFileParseImportedData_ParseValidTransactionTime(t *testing.T) {
converter := Camt053TransactionDataImporter importer := Camt053TransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -123,7 +124,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseValidTransactionTime(t
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -157,7 +158,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseValidTransactionTime(t
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 3, len(allNewTransactions)) assert.Equal(t, 3, len(allNewTransactions))
@@ -168,7 +169,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseValidTransactionTime(t
} }
func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *testing.T) { func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *testing.T) {
converter := Camt053TransactionDataImporter importer := Camt053TransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -176,7 +177,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -196,10 +197,10 @@ func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -219,10 +220,10 @@ func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -242,10 +243,10 @@ func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -265,12 +266,12 @@ func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmountAndCurrency(t *testing.T) { func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmountAndCurrency(t *testing.T) {
converter := Camt053TransactionDataImporter importer := Camt053TransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -278,7 +279,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -314,7 +315,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, len(allNewTransactions)) assert.Equal(t, 2, len(allNewTransactions))
@@ -323,7 +324,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
assert.Equal(t, "USD", allNewTransactions[1].OriginalSourceAccountCurrency) assert.Equal(t, "USD", allNewTransactions[1].OriginalSourceAccountCurrency)
assert.Equal(t, int64(10023), allNewTransactions[1].Amount) assert.Equal(t, int64(10023), allNewTransactions[1].Amount)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -365,7 +366,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, len(allNewTransactions)) assert.Equal(t, 2, len(allNewTransactions))
@@ -374,7 +375,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
assert.Equal(t, "USD", allNewTransactions[1].OriginalSourceAccountCurrency) assert.Equal(t, "USD", allNewTransactions[1].OriginalSourceAccountCurrency)
assert.Equal(t, int64(9999), allNewTransactions[1].Amount) assert.Equal(t, int64(9999), allNewTransactions[1].Amount)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -403,14 +404,14 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "USD", allNewTransactions[0].OriginalSourceAccountCurrency) assert.Equal(t, "USD", allNewTransactions[0].OriginalSourceAccountCurrency)
assert.Equal(t, int64(12345), allNewTransactions[0].Amount) assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -430,7 +431,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -439,7 +440,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
} }
func TestCamt053TransactionDataFileParseImportedData_ParseTransactionInvalidAmountAndCurrency(t *testing.T) { func TestCamt053TransactionDataFileParseImportedData_ParseTransactionInvalidAmountAndCurrency(t *testing.T) {
converter := Camt053TransactionDataImporter importer := Camt053TransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -447,7 +448,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionInvalidAmou
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -467,10 +468,10 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionInvalidAmou
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -498,10 +499,10 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionInvalidAmou
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -529,12 +530,12 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionInvalidAmou
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing.T) { func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing.T) {
converter := Camt053TransactionDataImporter importer := Camt053TransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -542,7 +543,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -572,13 +573,13 @@ func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "Test Transaction", allNewTransactions[0].Comment) assert.Equal(t, "Test Transaction", allNewTransactions[0].Comment)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -607,13 +608,13 @@ func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "Test Line 1\nTest Line 2", allNewTransactions[0].Comment) assert.Equal(t, "Test Line 1\nTest Line 2", allNewTransactions[0].Comment)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -634,7 +635,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -642,7 +643,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing
} }
func TestCamt053TransactionDataFileParseImportedData_MissingAccountNode(t *testing.T) { func TestCamt053TransactionDataFileParseImportedData_MissingAccountNode(t *testing.T) {
converter := Camt053TransactionDataImporter importer := Camt053TransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -650,7 +651,7 @@ func TestCamt053TransactionDataFileParseImportedData_MissingAccountNode(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -664,12 +665,12 @@ func TestCamt053TransactionDataFileParseImportedData_MissingAccountNode(t *testi
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingAccountData.Message) assert.EqualError(t, err, errs.ErrMissingAccountData.Message)
} }
func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredNode(t *testing.T) { func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredNode(t *testing.T) {
converter := Camt053TransactionDataImporter importer := Camt053TransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -677,7 +678,7 @@ func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredN
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -694,10 +695,10 @@ func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredN
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message) assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -716,10 +717,10 @@ func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredN
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -738,10 +739,10 @@ func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredN
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"> <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt> <BkToCstmrStmt>
@@ -760,6 +761,6 @@ func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredN
</Ntry> </Ntry>
</Stmt> </Stmt>
</BkToCstmrStmt> </BkToCstmrStmt>
</Document>`), 0, nil, nil, nil, nil, nil) </Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
@@ -29,7 +29,7 @@ type DataTableTransactionDataImporter struct {
} }
// ParseImportedData returns the imported transaction data // ParseImportedData returns the imported transaction data
func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, dataTable datatable.TransactionDataTable, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, dataTable datatable.TransactionDataTable, defaultTimezoneOffset int16, additionalOptions TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
if dataTable.TransactionRowCount() < 1 { if dataTable.TransactionRowCount() < 1 {
log.Errorf(ctx, "[data_table_transaction_data_importer.ParseImportedData] cannot parse import data for user \"uid:%d\", because data table row count is less 1", user.Uid) log.Errorf(ctx, "[data_table_transaction_data_importer.ParseImportedData] cannot parse import data for user \"uid:%d\", because data table row count is less 1", user.Uid)
return nil, nil, nil, nil, nil, nil, errs.ErrNotFoundTransactionDataInFile return nil, nil, nil, nil, nil, nil, errs.ErrNotFoundTransactionDataInFile
@@ -303,6 +303,7 @@ func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, u
var tagIds []string var tagIds []string
var tagNames []string var tagNames []string
tagNamesMap := make(map[string]bool)
if dataTable.HasColumn(datatable.TRANSACTION_DATA_TABLE_TAGS) { if dataTable.HasColumn(datatable.TRANSACTION_DATA_TABLE_TAGS) {
var tagNameItems []string var tagNameItems []string
@@ -316,7 +317,7 @@ func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, u
for i := 0; i < len(tagNameItems); i++ { for i := 0; i < len(tagNameItems); i++ {
tagName := tagNameItems[i] tagName := tagNameItems[i]
if tagName == "" { if tagName == "" || tagNamesMap[tagName] {
continue continue
} }
@@ -333,6 +334,28 @@ func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, u
} }
tagNames = append(tagNames, tagName) tagNames = append(tagNames, tagName)
tagNamesMap[tagName] = true
}
}
if dataTable.HasColumn(datatable.TRANSACTION_DATA_TABLE_PAYEE) && additionalOptions.IsPayeeAsTag() {
payee := dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_PAYEE)
if payee != "" && !tagNamesMap[payee] {
tag, exists := tagMap[payee]
if !exists {
tag = c.createNewTransactionTagModel(user.Uid, payee)
allNewTags = append(allNewTags, tag)
tagMap[payee] = tag
}
if tag != nil {
tagIds = append(tagIds, utils.Int64ToString(tag.TagId))
}
tagNames = append(tagNames, payee)
tagNamesMap[payee] = true
} }
} }
@@ -342,6 +365,10 @@ func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, u
description = dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_DESCRIPTION) description = dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_DESCRIPTION)
} }
if description == "" && additionalOptions.IsPayeeAsDescription() && dataTable.HasColumn(datatable.TRANSACTION_DATA_TABLE_PAYEE) {
description = dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_PAYEE)
}
transaction := &models.ImportTransaction{ transaction := &models.ImportTransaction{
Transaction: &models.Transaction{ Transaction: &models.Transaction{
Uid: user.Uid, Uid: user.Uid,
@@ -14,7 +14,7 @@ type TransactionDataExporter interface {
// TransactionDataImporter defines the structure of transaction data importer // TransactionDataImporter defines the structure of transaction data importer
type TransactionDataImporter interface { type TransactionDataImporter interface {
// ParseImportedData returns the imported data // ParseImportedData returns the imported data
ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error)
} }
// TransactionDataConverter defines the structure of transaction data converter // TransactionDataConverter defines the structure of transaction data converter
@@ -0,0 +1,118 @@
package converter
import "strings"
// TransactionDataImporterOptions defines the options for transaction data importer
type TransactionDataImporterOptions struct {
payeeAsTag bool
payeeAsDescription bool
memberAsTag bool
projectAsTag bool
merchantAsTag bool
}
// DefaultImporterOptions provides the default options for transaction data importer
var DefaultImporterOptions = TransactionDataImporterOptions{
payeeAsTag: false,
payeeAsDescription: false,
memberAsTag: false,
projectAsTag: false,
merchantAsTag: false,
}
// IsPayeeAsTag returns whether to import payee as tag
func (o TransactionDataImporterOptions) IsPayeeAsTag() bool {
return o.payeeAsTag
}
// IsPayeeAsDescription returns whether to import payee as description
func (o TransactionDataImporterOptions) IsPayeeAsDescription() bool {
return o.payeeAsDescription
}
// IsMemberAsTag returns whether to import member as tag
func (o TransactionDataImporterOptions) IsMemberAsTag() bool {
return o.memberAsTag
}
// IsProjectAsTag returns whether to import project as tag
func (o TransactionDataImporterOptions) IsProjectAsTag() bool {
return o.projectAsTag
}
// IsMerchantAsTag returns whether to import merchant as tag
func (o TransactionDataImporterOptions) IsMerchantAsTag() bool {
return o.merchantAsTag
}
// WithPayeeAsTag sets the option to import payee as tag
func (o TransactionDataImporterOptions) WithPayeeAsTag() TransactionDataImporterOptions {
cloned := o.Clone()
cloned.payeeAsTag = true
return cloned
}
// WithPayeeAsDescription sets the option to import payee as description
func (o TransactionDataImporterOptions) WithPayeeAsDescription() TransactionDataImporterOptions {
cloned := o.Clone()
cloned.payeeAsDescription = true
return cloned
}
// WithMemberAsTag sets the option to import member as tag
func (o TransactionDataImporterOptions) WithMemberAsTag() TransactionDataImporterOptions {
cloned := o.Clone()
cloned.memberAsTag = true
return cloned
}
// WithProjectAsTag sets the option to import project as tag
func (o TransactionDataImporterOptions) WithProjectAsTag() TransactionDataImporterOptions {
cloned := o.Clone()
cloned.projectAsTag = true
return cloned
}
// WithMerchantAsTag sets the option to import merchant as tag
func (o TransactionDataImporterOptions) WithMerchantAsTag() TransactionDataImporterOptions {
cloned := o.Clone()
cloned.merchantAsTag = true
return cloned
}
// Clone creates a copy of the options instance
func (o TransactionDataImporterOptions) Clone() TransactionDataImporterOptions {
return TransactionDataImporterOptions{
payeeAsTag: o.payeeAsTag,
payeeAsDescription: o.payeeAsDescription,
memberAsTag: o.memberAsTag,
projectAsTag: o.projectAsTag,
merchantAsTag: o.merchantAsTag,
}
}
// ParseImporterOptions parses the textual options to the instance
func ParseImporterOptions(s string) TransactionDataImporterOptions {
options := TransactionDataImporterOptions{}
if s == "" {
return options
}
for _, option := range strings.Split(s, ",") {
switch option {
case "payeeAsTag":
options.payeeAsTag = true
case "payeeAsDescription":
options.payeeAsDescription = true
case "memberAsTag":
options.memberAsTag = true
case "projectAsTag":
options.projectAsTag = true
case "merchantAsTag":
options.merchantAsTag = true
}
}
return options
}
@@ -0,0 +1,110 @@
package converter
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseImporterOptions(t *testing.T) {
actualValue := ParseImporterOptions("payeeAsTag,memberAsTag")
expectedValue := TransactionDataImporterOptions{
payeeAsTag: true,
memberAsTag: true,
projectAsTag: false,
merchantAsTag: false,
}
assert.Equal(t, expectedValue, actualValue)
assert.Equal(t, true, actualValue.IsPayeeAsTag())
assert.Equal(t, true, actualValue.IsMemberAsTag())
assert.Equal(t, false, actualValue.IsProjectAsTag())
assert.Equal(t, false, actualValue.IsMerchantAsTag())
actualValue = ParseImporterOptions("")
expectedValue = TransactionDataImporterOptions{
payeeAsTag: false,
memberAsTag: false,
projectAsTag: false,
merchantAsTag: false,
}
assert.Equal(t, expectedValue, actualValue)
assert.Equal(t, false, actualValue.IsPayeeAsTag())
assert.Equal(t, false, actualValue.IsMemberAsTag())
assert.Equal(t, false, actualValue.IsProjectAsTag())
assert.Equal(t, false, actualValue.IsMerchantAsTag())
}
func TestParseImporterOptions_WithAllOptions(t *testing.T) {
actualValue := ParseImporterOptions("payeeAsTag,payeeAsDescription,memberAsTag,projectAsTag,merchantAsTag")
expectedValue := TransactionDataImporterOptions{
payeeAsTag: true,
payeeAsDescription: true,
memberAsTag: true,
projectAsTag: true,
merchantAsTag: true,
}
assert.Equal(t, expectedValue, actualValue)
assert.Equal(t, true, actualValue.IsPayeeAsTag())
assert.Equal(t, true, actualValue.IsPayeeAsDescription())
assert.Equal(t, true, actualValue.IsMemberAsTag())
assert.Equal(t, true, actualValue.IsProjectAsTag())
assert.Equal(t, true, actualValue.IsMerchantAsTag())
}
func TestParseImporterOptions_WithInvalidOptions(t *testing.T) {
actualValue := ParseImporterOptions("invalidOption,payeeAsTag,memberAsTag")
expectedValue := TransactionDataImporterOptions{
payeeAsTag: true,
memberAsTag: true,
projectAsTag: false,
merchantAsTag: false,
}
assert.Equal(t, expectedValue, actualValue)
assert.Equal(t, true, actualValue.IsPayeeAsTag())
assert.Equal(t, true, actualValue.IsMemberAsTag())
assert.Equal(t, false, actualValue.IsProjectAsTag())
assert.Equal(t, false, actualValue.IsMerchantAsTag())
actualValue = ParseImporterOptions("invalidOption")
expectedValue = TransactionDataImporterOptions{
payeeAsTag: false,
memberAsTag: false,
projectAsTag: false,
merchantAsTag: false,
}
assert.Equal(t, expectedValue, actualValue)
assert.Equal(t, false, actualValue.IsPayeeAsTag())
assert.Equal(t, false, actualValue.IsMemberAsTag())
assert.Equal(t, false, actualValue.IsProjectAsTag())
assert.Equal(t, false, actualValue.IsMerchantAsTag())
}
func TestParseImporterOptions_Clone(t *testing.T) {
original := TransactionDataImporterOptions{
payeeAsTag: true,
payeeAsDescription: false,
memberAsTag: false,
projectAsTag: true,
merchantAsTag: false,
}
cloned := original.Clone()
assert.Equal(t, original, cloned)
// Modify cloned options and verify original options are not affected
cloned.payeeAsTag = false
cloned.payeeAsDescription = true
cloned.memberAsTag = true
assert.Equal(t, true, original.payeeAsTag)
assert.Equal(t, false, original.payeeAsDescription)
assert.Equal(t, false, original.memberAsTag)
assert.Equal(t, true, original.projectAsTag)
assert.Equal(t, false, original.merchantAsTag)
assert.Equal(t, false, cloned.payeeAsTag)
assert.Equal(t, true, cloned.payeeAsDescription)
assert.Equal(t, true, cloned.memberAsTag)
assert.Equal(t, true, cloned.projectAsTag)
assert.Equal(t, false, cloned.merchantAsTag)
}
@@ -72,6 +72,10 @@ const (
TRANSACTION_DATA_TABLE_GEOGRAPHIC_LOCATION TransactionDataTableColumn = 12 TRANSACTION_DATA_TABLE_GEOGRAPHIC_LOCATION TransactionDataTableColumn = 12
TRANSACTION_DATA_TABLE_TAGS TransactionDataTableColumn = 13 TRANSACTION_DATA_TABLE_TAGS TransactionDataTableColumn = 13
TRANSACTION_DATA_TABLE_DESCRIPTION TransactionDataTableColumn = 14 TRANSACTION_DATA_TABLE_DESCRIPTION TransactionDataTableColumn = 14
TRANSACTION_DATA_TABLE_PAYEE TransactionDataTableColumn = 101
TRANSACTION_DATA_TABLE_MEMBER TransactionDataTableColumn = 102
TRANSACTION_DATA_TABLE_PROJECT TransactionDataTableColumn = 103
TRANSACTION_DATA_TABLE_MERCHANT TransactionDataTableColumn = 104
) )
// TRANSACTION_DATA_TABLE_TIMEZONE_NOT_AVAILABLE represents the constant for timezone not available // TRANSACTION_DATA_TABLE_TIMEZONE_NOT_AVAILABLE represents the constant for timezone not available
@@ -35,7 +35,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the transaction json data // ParseImportedData returns the imported data by parsing the transaction json data
func (c *defaultTransactionDataJsonImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *defaultTransactionDataJsonImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
var importRequest models.ImportTransactionRequest var importRequest models.ImportTransactionRequest
if err := json.Unmarshal(data, &importRequest); err != nil { if err := json.Unmarshal(data, &importRequest); err != nil {
@@ -55,7 +55,7 @@ func (c *defaultTransactionDataJsonImporter) ParseImportedData(ctx core.Context,
ezbookkeepingTagSeparator, ezbookkeepingTagSeparator,
) )
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
func (c *defaultTransactionDataJsonImporter) createNewDefaultTransactionDataTable(importRequest models.ImportTransactionRequest) (datatable.TransactionDataTable, error) { func (c *defaultTransactionDataJsonImporter) createNewDefaultTransactionDataTable(importRequest models.ImportTransactionRequest) (datatable.TransactionDataTable, error) {
@@ -84,7 +84,7 @@ func (c *defaultTransactionDataPlainTextConverter) ToExportedContent(ctx core.Co
} }
// ParseImportedData returns the imported data by parsing the transaction plain text data // ParseImportedData returns the imported data by parsing the transaction plain text data
func (c *defaultTransactionDataPlainTextConverter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *defaultTransactionDataPlainTextConverter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
dataTable, err := createNewDefaultPlainTextDataTable( dataTable, err := createNewDefaultPlainTextDataTable(
string(data), string(data),
c.columnSeparator, c.columnSeparator,
@@ -104,5 +104,5 @@ func (c *defaultTransactionDataPlainTextConverter) ParseImportedData(ctx core.Co
ezbookkeepingTagSeparator, ezbookkeepingTagSeparator,
) )
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -12,7 +13,7 @@ import (
) )
func TestDefaultTransactionDataCSVFileConverterToExportedContent(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterToExportedContent(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter exporter := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
transactions := make([]*models.Transaction, 3) transactions := make([]*models.Transaction, 3)
@@ -119,14 +120,14 @@ func TestDefaultTransactionDataCSVFileConverterToExportedContent(t *testing.T) {
"2024-09-01 12:34:56,+08:00,Income,Test Category,Test Sub Category,Test Account,CNY,123.45,,,,123.450000 45.670000,Test Tag;Test Tag2,Hello World\n" + "2024-09-01 12:34:56,+08:00,Income,Test Category,Test Sub Category,Test Account,CNY,123.45,,,,123.450000 45.670000,Test Tag;Test Tag2,Hello World\n" +
"2024-09-01 12:34:56,+00:00,Expense,Test Category2,Test Sub Category2,Test Account,CNY,-0.10,,,,,Test Tag,Foo#Bar\n" + "2024-09-01 12:34:56,+00:00,Expense,Test Category2,Test Sub Category2,Test Account,CNY,-0.10,,,,,Test Tag,Foo#Bar\n" +
"2024-09-01 12:34:56,-05:00,Transfer,Test Category3,Test Sub Category3,Test Account,CNY,123.45,Test Account2,USD,17.35,,Test Tag2,T\te s t test\n" "2024-09-01 12:34:56,-05:00,Transfer,Test Category3,Test Sub Category3,Test Account,CNY,123.45,Test Account2,USD,17.35,,Test Tag2,T\te s t test\n"
actualContent, err := converter.ToExportedContent(context, 123, transactions, accountMap, categoryMap, tagMap, allTagIndexes) actualContent, err := exporter.ToExportedContent(context, 123, transactions, accountMap, categoryMap, tagMap, allTagIndexes)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, expectedContent, string(actualContent)) assert.Equal(t, expectedContent, string(actualContent))
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_MinimumValidData(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_MinimumValidData(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -134,11 +135,11 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_MinimumValidDat
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"2024-09-01 00:00:00,Balance Modification,,Test Account,123.45,,\n"+ "2024-09-01 00:00:00,Balance Modification,,Test Account,123.45,,\n"+
"2024-09-01 01:23:45,Income,Test Category,Test Account,0.12,,\n"+ "2024-09-01 01:23:45,Income,Test Category,Test Account,0.12,,\n"+
"2024-09-01 12:34:56,Expense,Test Category2,Test Account,1.00,,\n"+ "2024-09-01 12:34:56,Expense,Test Category2,Test Account,1.00,,\n"+
"2024-09-01 23:59:59,Transfer,Test Category3,Test Account,0.05,Test Account2,0.05"), 0, nil, nil, nil, nil, nil) "2024-09-01 23:59:59,Transfer,Test Category3,Test Account,0.05,Test Account2,0.05"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -197,7 +198,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_MinimumValidDat
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTime(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTime(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -205,17 +206,17 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTim
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"2024-09-01T12:34:56,Expense,Test Category,Test Account,123.45,,"), 0, nil, nil, nil, nil, nil) "2024-09-01T12:34:56,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"09/01/2024 12:34:56,Expense,Test Category,Test Account,123.45,,"), 0, nil, nil, nil, nil, nil) "09/01/2024 12:34:56,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidType(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidType(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -223,13 +224,13 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTyp
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"2024-09-01 12:34:56,Type,Test Category,Test Account,123.45,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Type,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidTimezone(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidTimezone(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -237,27 +238,27 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidTimez
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"2024-09-01 12:34:56,-10:00,Expense,Test Category,Test Account,123.45,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,-10:00,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"2024-09-01 12:34:56,+00:00,Expense,Test Category,Test Account,123.45,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,+00:00,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"2024-09-01 12:34:56,+12:45,Expense,Test Category,Test Account,123.45,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,+12:45,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTimezone(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTimezone(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -265,13 +266,13 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTim
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"2024-09-01 12:34:56,Asia/Shanghai,Expense,Test Category,Test Account,123.45,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Asia/Shanghai,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidAccountCurrency(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidAccountCurrency(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -279,9 +280,9 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidAccou
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+ allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
"2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+ "2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+
"2024-09-01 12:34:56,Transfer,Test Category2,Test Account,USD,1.23,Test Account2,EUR,1.10"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Transfer,Test Category2,Test Account,USD,1.23,Test Account2,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -298,7 +299,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidAccou
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidAccountCurrency(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidAccountCurrency(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -306,19 +307,19 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidAcc
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
"2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+ "2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+
"2024-09-01 12:34:56,Transfer,Test Category3,Test Account,CNY,1.23,Test Account2,EUR,1.10"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Transfer,Test Category3,Test Account,CNY,1.23,Test Account2,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
"2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+ "2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+
"2024-09-01 12:34:56,Transfer,Test Category3,Test Account2,CNY,1.23,Test Account,EUR,1.10"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Transfer,Test Category3,Test Account2,CNY,1.23,Test Account,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseNotSupportedCurrency(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseNotSupportedCurrency(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -326,17 +327,17 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseNotSupport
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
"2024-09-01 01:23:45,Balance Modification,,Test Account,XXX,123.45,,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 01:23:45,Balance Modification,,Test Account,XXX,123.45,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
"2024-09-01 01:23:45,Transfer,Test Category,Test Account,USD,123.45,Test Account2,XXX,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 01:23:45,Transfer,Test Category,Test Account,USD,123.45,Test Account2,XXX,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidAmount(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -344,17 +345,17 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidAmo
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123 45,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Expense,Test Category,Test Account,123 45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
"2024-09-01 12:34:56,Transfer,Test Category,Test Account,123.45,Test Account2,123 45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Transfer,Test Category,Test Account,123.45,Test Account2,123 45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseNoAmount2(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseNoAmount2(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -362,15 +363,15 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseNoAmount2(
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2\n"+
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(12345), allNewTransactions[0].Amount) assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
assert.Equal(t, int64(0), allNewTransactions[0].RelatedAccountAmount) assert.Equal(t, int64(0), allNewTransactions[0].RelatedAccountAmount)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2\n"+ allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2\n"+
"2024-09-01 12:34:56,Transfer,Test Category,Test Account,123.45,Test Account2"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Transfer,Test Category,Test Account,123.45,Test Account2"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(12345), allNewTransactions[0].Amount) assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
@@ -378,7 +379,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseNoAmount2(
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidGeographicLocation(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidGeographicLocation(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -386,8 +387,8 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidGeogr
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,123.45 45.56"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,123.45 45.56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -396,7 +397,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidGeogr
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidGeographicLocation(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidGeographicLocation(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -404,24 +405,24 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidGeo
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,1"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,1"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, float64(0), allNewTransactions[0].GeoLongitude) assert.Equal(t, float64(0), allNewTransactions[0].GeoLongitude)
assert.Equal(t, float64(0), allNewTransactions[0].GeoLatitude) assert.Equal(t, float64(0), allNewTransactions[0].GeoLatitude)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,a b"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,a b"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message) assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,1 "), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,1 "), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message) assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message)
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseTag(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseTag(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -429,8 +430,8 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseTag(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, allNewTags, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Tags\n"+ _, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Tags\n"+
"2024-09-01 00:00:00,Balance Modification,,Test Account,123.45,,,foo;;bar.;#test;hello\tworld;;"), 0, nil, nil, nil, nil, nil) "2024-09-01 00:00:00,Balance Modification,,Test Account,123.45,,,foo;;bar.;#test;hello\tworld;;"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -450,7 +451,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseTag(t *tes
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseDescription(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseDescription(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -458,8 +459,8 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseDescriptio
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Description\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Description\n"+
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,foo bar\t#test"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,foo bar\t#test"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -467,7 +468,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseDescriptio
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_MissingFileHeader(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_MissingFileHeader(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -475,12 +476,12 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_MissingFileHead
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(""), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestDefaultTransactionDataCSVFileConverterParseImportedData_MissingRequiredColumn(t *testing.T) { func TestDefaultTransactionDataCSVFileConverterParseImportedData_MissingRequiredColumn(t *testing.T) {
converter := DefaultTransactionDataCSVFileConverter importer := DefaultTransactionDataCSVFileConverter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -489,32 +490,32 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_MissingRequired
} }
// Missing Time Column // Missing Time Column
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("Timezone,Type,Category,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Timezone,Type,Category,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
"+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,123.45,,,,,,"), 0, nil, nil, nil, nil, nil) "+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,123.45,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Type Column // Missing Type Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Category,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Category,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
"2024-09-01 00:00:00,+08:00,Test Category,Test Sub Category,Test Account,CNY,123.45,,,,,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 00:00:00,+08:00,Test Category,Test Sub Category,Test Account,CNY,123.45,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Sub Category Column // Missing Sub Category Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Type,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
"2024-09-01 00:00:00,+08:00,Balance Modification,Test Account,CNY,123.45,,,,,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 00:00:00,+08:00,Balance Modification,Test Account,CNY,123.45,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Account Name Column // Missing Account Name Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
"2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,CNY,123.45,,,,,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,CNY,123.45,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Amount Column // Missing Amount Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account,Account Currency,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account,Account Currency,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
"2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,,,,,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Account2 Name Column // Missing Account2 Name Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account,Account Currency,Amount,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account,Account Currency,Amount,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
"2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,123.45,,,,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,123.45,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
} }
@@ -146,7 +146,7 @@ func (c *customTransactionDataDsvFileImporter) ParseDsvFileLines(ctx core.Contex
} }
// ParseImportedData returns the imported data by parsing the custom transaction dsv data // ParseImportedData returns the imported data by parsing the custom transaction dsv data
func (c *customTransactionDataDsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *customTransactionDataDsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
allLines, err := c.ParseDsvFileLines(ctx, data) allLines, err := c.ParseDsvFileLines(ctx, data)
if err != nil { if err != nil {
@@ -157,7 +157,7 @@ func (c *customTransactionDataDsvFileImporter) ParseImportedData(ctx core.Contex
transactionDataTable := CreateNewCustomPlainTextDataTable(dataTable, c.columnIndexMapping, c.transactionTypeNameMapping, c.timeFormat, c.timezoneFormat, c.amountDecimalSeparator, c.amountDigitGroupingSymbol) transactionDataTable := CreateNewCustomPlainTextDataTable(dataTable, c.columnIndexMapping, c.transactionTypeNameMapping, c.timeFormat, c.timezoneFormat, c.amountDecimalSeparator, c.amountDigitGroupingSymbol)
dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(customTransactionTypeNameMapping, c.geoLocationSeparator, c.geoLocationOrder, c.transactionTagSeparator) dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(customTransactionTypeNameMapping, c.geoLocationSeparator, c.geoLocationOrder, c.transactionTagSeparator)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
// IsDelimiterSeparatedValuesFileType returns whether the file type is the delimiter-separated values file type // IsDelimiterSeparatedValuesFileType returns whether the file type is the delimiter-separated values file type
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable" "github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
@@ -22,12 +23,12 @@ func TestIsDelimiterSeparatedValuesFileType(t *testing.T) {
} }
func TestCustomTransactionDataDsvFileParser_ParseDsvFileLines(t *testing.T) { func TestCustomTransactionDataDsvFileParser_ParseDsvFileLines(t *testing.T) {
converter, err := CreateNewCustomTransactionDataDsvFileParser("custom_csv", "utf-8") importer, err := CreateNewCustomTransactionDataDsvFileParser("custom_csv", "utf-8")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
allLines, err := converter.ParseDsvFileLines(context, []byte( allLines, err := importer.ParseDsvFileLines(context, []byte(
"2024-09-01 00:00:00,B,123.45\n"+ "2024-09-01 00:00:00,B,123.45\n"+
"2024-09-01 01:23:45,I,0.12\n")) "2024-09-01 01:23:45,I,0.12\n"))
assert.Nil(t, err) assert.Nil(t, err)
@@ -44,10 +45,10 @@ func TestCustomTransactionDataDsvFileParser_ParseDsvFileLines(t *testing.T) {
assert.Equal(t, "I", allLines[1][1]) assert.Equal(t, "I", allLines[1][1])
assert.Equal(t, "0.12", allLines[1][2]) assert.Equal(t, "0.12", allLines[1][2])
converter, err = CreateNewCustomTransactionDataDsvFileParser("custom_tsv", "utf-8") importer, err = CreateNewCustomTransactionDataDsvFileParser("custom_tsv", "utf-8")
assert.Nil(t, err) assert.Nil(t, err)
allLines, err = converter.ParseDsvFileLines(context, []byte( allLines, err = importer.ParseDsvFileLines(context, []byte(
"2024-09-01 12:34:56\tE\t1.00\n"+ "2024-09-01 12:34:56\tE\t1.00\n"+
"2024-09-01 23:59:59\tT\t0.05")) "2024-09-01 23:59:59\tT\t0.05"))
assert.Nil(t, err) assert.Nil(t, err)
@@ -77,7 +78,7 @@ func TestCustomTransactionDataDsvFileImporter_MinimumValidData(t *testing.T) {
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", ".", "", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", ".", "", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -87,11 +88,11 @@ func TestCustomTransactionDataDsvFileImporter_MinimumValidData(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 00:00:00,B,123.45\n"+ "2024-09-01 00:00:00,B,123.45\n"+
"2024-09-01 01:23:45,I,0.12\n"+ "2024-09-01 01:23:45,I,0.12\n"+
"2024-09-01 12:34:56,E,1.00\n"+ "2024-09-01 12:34:56,E,1.00\n"+
"2024-09-01 23:59:59,T,0.05"), 0, nil, nil, nil, nil, nil) "2024-09-01 23:59:59,T,0.05"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -168,7 +169,7 @@ func TestCustomTransactionDataDsvFileImporter_WithAllSupportedColumns(t *testing
"Expense": models.TRANSACTION_TYPE_EXPENSE, "Expense": models.TRANSACTION_TYPE_EXPENSE,
"Transfer": models.TRANSACTION_TYPE_TRANSFER, "Transfer": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, true, "YYYY-MM-DD HH:mm:ss", "", ".", "", " ", "lonlat", ";") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, true, "YYYY-MM-DD HH:mm:ss", "", ".", "", " ", "lonlat", ";")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -178,12 +179,12 @@ func TestCustomTransactionDataDsvFileImporter_WithAllSupportedColumns(t *testing
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(
"\"Time\",\"Timezone\",\"Type\",\"Category\",\"Sub Category\",\"Account\",\"Account Currency\",\"Amount\",\"Account2\",\"Account2 Currency\",\"Account2 Amount\",\"Geographic Location\",\"Tags\",\"Description\"\n"+ "\"Time\",\"Timezone\",\"Type\",\"Category\",\"Sub Category\",\"Account\",\"Account Currency\",\"Amount\",\"Account2\",\"Account2 Currency\",\"Account2 Amount\",\"Geographic Location\",\"Tags\",\"Description\"\n"+
"\"2024-09-01 00:00:00\",\"+08:00\",\"Balance Modification\",\"\",\"\",\"Test Account\",\"CNY\",\"123.45\",\"\",\"\",\"\",\"\",\"\",\"\"\n"+ "\"2024-09-01 00:00:00\",\"+08:00\",\"Balance Modification\",\"\",\"\",\"Test Account\",\"CNY\",\"123.45\",\"\",\"\",\"\",\"\",\"\",\"\"\n"+
"\"2024-09-01 01:23:45\",\"+08:00\",\"Income\",\"Test Category\",\"Test Sub Category\",\"Test Account\",\"CNY\",\"0.12\",\"\",\"\",\"\",\"123.450000 45.670000\",\"Test Tag;Test Tag2\",\"Hello World\"\n"+ "\"2024-09-01 01:23:45\",\"+08:00\",\"Income\",\"Test Category\",\"Test Sub Category\",\"Test Account\",\"CNY\",\"0.12\",\"\",\"\",\"\",\"123.450000 45.670000\",\"Test Tag;Test Tag2\",\"Hello World\"\n"+
"\"2024-09-01 12:34:56\",\"+00:00\",\"Expense\",\"Test Category2\",\"Test Sub Category2\",\"Test Account\",\"CNY\",\"1.00\",\"\",\"\",\"\",\"\",\"Test Tag\",\"Foo#Bar\"\n"+ "\"2024-09-01 12:34:56\",\"+00:00\",\"Expense\",\"Test Category2\",\"Test Sub Category2\",\"Test Account\",\"CNY\",\"1.00\",\"\",\"\",\"\",\"\",\"Test Tag\",\"Foo#Bar\"\n"+
"\"2024-09-01 23:59:59\",\"-05:00\",\"Transfer\",\"Test Category3\",\"Test Sub Category3\",\"Test Account\",\"CNY\",\"0.05\",\"Test Account2\",\"USD\",\"0.35\",\"\",\"Test Tag2\",\"foo\tbar\""), 0, nil, nil, nil, nil, nil) "\"2024-09-01 23:59:59\",\"-05:00\",\"Transfer\",\"Test Category3\",\"Test Sub Category3\",\"Test Account\",\"CNY\",\"0.05\",\"Test Account2\",\"USD\",\"0.35\",\"\",\"Test Tag2\",\"foo\tbar\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -261,7 +262,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTime(t *testing.T) {
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -271,12 +272,12 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTime(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01T12:34:56,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01T12:34:56,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"09/01/2024 12:34:56,E,123.45"), 0, nil, nil, nil, nil, nil) "09/01/2024 12:34:56,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
@@ -292,7 +293,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseTransactionWithoutType(t *tes
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -302,8 +303,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseTransactionWithoutType(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,A,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,A,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
@@ -316,7 +317,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidType(t *testing.T) {
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"B": 0, "B": 0,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -326,8 +327,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidType(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,B,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,B,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
} }
@@ -340,7 +341,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseTimeWithTimezone(t *testing.T
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ssZ", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ssZ", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -350,20 +351,20 @@ func TestCustomTransactionDataDsvFileImporter_ParseTimeWithTimezone(t *testing.T
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56-10:00,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56-10:00,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56+00:00,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56+00:00,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56+12:45,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56+12:45,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
@@ -378,7 +379,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseTimeWithTimezone2(t *testing.
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ssZZ", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ssZZ", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -388,20 +389,20 @@ func TestCustomTransactionDataDsvFileImporter_ParseTimeWithTimezone2(t *testing.
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56-1000,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56-1000,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56+0000,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56+0000,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56+1245,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56+1245,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
@@ -417,7 +418,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidTimezone(t *testing.T) {
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -427,20 +428,20 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidTimezone(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,-10:00,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,-10:00,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,+00:00,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,+00:00,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,+12:45,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,+12:45,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
@@ -456,7 +457,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidTimezone2(t *testing.T)
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "ZZ", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "ZZ", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -466,20 +467,20 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidTimezone2(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,-1000,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,-1000,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,+0000,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,+0000,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,+1245,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,+1245,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
@@ -495,7 +496,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTimezoneFormat(t *test
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "z", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "z", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -505,8 +506,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTimezoneFormat(t *test
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,CST,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,CST,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrImportFileTransactionTimezoneFormatInvalid.Message) assert.EqualError(t, err, errs.ErrImportFileTransactionTimezoneFormatInvalid.Message)
} }
@@ -520,7 +521,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTimezone(t *testing.T)
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -530,12 +531,12 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTimezone(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,Asia/Shanghai,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Asia/Shanghai,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,-0700,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,-0700,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
} }
@@ -549,7 +550,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTimezone2(t *testing.T
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "ZZ", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "ZZ", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -559,12 +560,12 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTimezone2(t *testing.T
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,Asia/Shanghai,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,Asia/Shanghai,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,0700,E,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,0700,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
} }
@@ -577,7 +578,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseAmountWithCustomFormat(t *tes
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_tsv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ",", ".", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_tsv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ",", ".", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -587,8 +588,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseAmountWithCustomFormat(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56\tE\t1.234,56"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56\tE\t1.234,56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(123456), allNewTransactions[0].Amount) assert.Equal(t, int64(123456), allNewTransactions[0].Amount)
@@ -603,7 +604,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAmountWithCustomFormat
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_tsv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", ",", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_tsv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", ",", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -613,8 +614,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAmountWithCustomFormat
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56\tE\t1.234,56"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56\tE\t1.234,56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
@@ -627,7 +628,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAmountWithCustomFormat
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_tsv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ",", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_tsv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ",", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -637,8 +638,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAmountWithCustomFormat
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56\tE\t1.234,56"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56\tE\t1.234,56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
@@ -655,7 +656,7 @@ func TestCustomTransactionDataDsvFileImporter_ParsePrimaryCategory(t *testing.T)
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -665,11 +666,11 @@ func TestCustomTransactionDataDsvFileImporter_ParsePrimaryCategory(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 00:00:00,B,,123.45\n"+ "2024-09-01 00:00:00,B,,123.45\n"+
"2024-09-01 01:23:45,I,Test Category,0.12\n"+ "2024-09-01 01:23:45,I,Test Category,0.12\n"+
"2024-09-01 12:34:56,E,Test Category2,1.00\n"+ "2024-09-01 12:34:56,E,Test Category2,1.00\n"+
"2024-09-01 23:59:59,T,Test Category3,0.05"), 0, nil, nil, nil, nil, nil) "2024-09-01 23:59:59,T,Test Category3,0.05"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -724,7 +725,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidAccountCurrency(t *testi
"B": models.TRANSACTION_TYPE_MODIFY_BALANCE, "B": models.TRANSACTION_TYPE_MODIFY_BALANCE,
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -734,9 +735,9 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidAccountCurrency(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+ "2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+
"2024-09-01 12:34:56,T,Test Account,USD,1.23,Test Account2,EUR,1.10"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,T,Test Account,USD,1.23,Test Account2,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -767,7 +768,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAccountCurrency(t *tes
"B": models.TRANSACTION_TYPE_MODIFY_BALANCE, "B": models.TRANSACTION_TYPE_MODIFY_BALANCE,
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -777,14 +778,14 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAccountCurrency(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+ "2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+
"2024-09-01 12:34:56,T,Test Account,CNY,1.23,Test Account2,EUR,1.10"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,T,Test Account,CNY,1.23,Test Account2,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+ "2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+
"2024-09-01 12:34:56,T,Test Account2,CNY,1.23,Test Account,EUR,1.10"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,T,Test Account2,CNY,1.23,Test Account,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
@@ -803,7 +804,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseNotSupportedCurrency(t *testi
"B": models.TRANSACTION_TYPE_MODIFY_BALANCE, "B": models.TRANSACTION_TYPE_MODIFY_BALANCE,
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -813,12 +814,12 @@ func TestCustomTransactionDataDsvFileImporter_ParseNotSupportedCurrency(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 01:23:45,B,Test Account,XXX,123.45,,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 01:23:45,B,Test Account,XXX,123.45,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 01:23:45,T,Test Account,USD,123.45,Test Account2,XXX,123.45"), 0, nil, nil, nil, nil, nil) "2024-09-01 01:23:45,T,Test Account,USD,123.45,Test Account2,XXX,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
@@ -835,7 +836,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidAmount(t *testing.T) {
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -845,11 +846,11 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidAmount(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 00:00:00,B,123.45000000,\n"+ "2024-09-01 00:00:00,B,123.45000000,\n"+
"2024-09-01 01:23:45,I,0.12000000,\n"+ "2024-09-01 01:23:45,I,0.12000000,\n"+
"2024-09-01 12:34:56,E,1.00000000,\n"+ "2024-09-01 12:34:56,E,1.00000000,\n"+
"2024-09-01 23:59:59,T,0.05000000,0.35000000"), 0, nil, nil, nil, nil, nil) "2024-09-01 23:59:59,T,0.05000000,0.35000000"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -886,7 +887,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAmount(t *testing.T) {
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -896,12 +897,12 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAmount(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,E,Test Account,123 45,,"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,E,Test Account,123 45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,T,Test Account,123.45,Test Account2,123 45"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,T,Test Account,123.45,Test Account2,123 45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
@@ -917,7 +918,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseNoAmount2(t *testing.T) {
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -927,15 +928,15 @@ func TestCustomTransactionDataDsvFileImporter_ParseNoAmount2(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,E,Test Account,123.45,"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,E,Test Account,123.45,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(12345), allNewTransactions[0].Amount) assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
assert.Equal(t, int64(0), allNewTransactions[0].RelatedAccountAmount) assert.Equal(t, int64(0), allNewTransactions[0].RelatedAccountAmount)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,T,Test Account,123.45,Test Account2"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,T,Test Account,123.45,Test Account2"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(12345), allNewTransactions[0].Amount) assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
@@ -952,7 +953,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidGeographicLocation(t *te
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", ";", "lonlat", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", ";", "lonlat", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -962,8 +963,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidGeographicLocation(t *te
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,E,123.45,123.45;45.56"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,E,123.45,123.45;45.56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -981,7 +982,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidGeographicLocation(t *
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", " ", "lonlat", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", " ", "lonlat", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -991,15 +992,15 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidGeographicLocation(t *
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,E,123.45,,,1"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,E,123.45,,,1"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, float64(0), allNewTransactions[0].GeoLongitude) assert.Equal(t, float64(0), allNewTransactions[0].GeoLongitude)
assert.Equal(t, float64(0), allNewTransactions[0].GeoLatitude) assert.Equal(t, float64(0), allNewTransactions[0].GeoLatitude)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,E,123.45,a b"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,E,123.45,a b"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message) assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message)
} }
@@ -1013,7 +1014,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseTag(t *testing.T) {
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", ";") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", ";")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -1023,8 +1024,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseTag(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, allNewTags, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 00:00:00,E,123.45,foo;;bar.;#test;hello\tworld;;"), 0, nil, nil, nil, nil, nil) "2024-09-01 00:00:00,E,123.45,foo;;bar.;#test;hello\tworld;;"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -1053,7 +1054,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseTagWithoutSeparator(t *testin
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"E": models.TRANSACTION_TYPE_EXPENSE, "E": models.TRANSACTION_TYPE_EXPENSE,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -1063,8 +1064,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseTagWithoutSeparator(t *testin
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, allNewTags, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 00:00:00,E,123.45,foo;;bar.;#test;hello\tworld;;"), 0, nil, nil, nil, nil, nil) "2024-09-01 00:00:00,E,123.45,foo;;bar.;#test;hello\tworld;;"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -1084,7 +1085,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseDescription(t *testing.T) {
transactionTypeMapping := map[string]models.TransactionType{ transactionTypeMapping := map[string]models.TransactionType{
"T": models.TRANSACTION_TYPE_TRANSFER, "T": models.TRANSACTION_TYPE_TRANSFER,
} }
converter, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "") importer, err := CreateNewCustomTransactionDataDsvFileImporter("custom_csv", "utf-8", columnIndexMapping, transactionTypeMapping, false, "YYYY-MM-DD HH:mm:ss", "", ".", "", "", "", "")
assert.Nil(t, err) assert.Nil(t, err)
context := core.NewNullContext() context := core.NewNullContext()
@@ -1094,8 +1095,8 @@ func TestCustomTransactionDataDsvFileImporter_ParseDescription(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"2024-09-01 12:34:56,T,123.45,foo bar\t#test"), 0, nil, nil, nil, nil, nil) "2024-09-01 12:34:56,T,123.45,foo bar\t#test"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -55,7 +55,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the feidee mymoney app transaction csv data // ParseImportedData returns the imported data by parsing the feidee mymoney app transaction csv data
func (c *feideeMymoneyAppTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *feideeMymoneyAppTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
fallback := unicode.UTF8.NewDecoder() fallback := unicode.UTF8.NewDecoder()
reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback)) reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback))
@@ -91,7 +91,7 @@ func (c *feideeMymoneyAppTransactionDataCsvFileImporter) ParseImportedData(ctx c
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(feideeMymoneyTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(feideeMymoneyTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
func (c *feideeMymoneyAppTransactionDataCsvFileImporter) createNewFeideeMymoneyAppTransactionDataTable(ctx core.Context, commonDataTable datatable.CommonDataTable) (datatable.TransactionDataTable, error) { func (c *feideeMymoneyAppTransactionDataCsvFileImporter) createNewFeideeMymoneyAppTransactionDataTable(ctx core.Context, commonDataTable datatable.CommonDataTable) (datatable.TransactionDataTable, error) {
@@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -13,7 +14,7 @@ import (
) )
func TestFeideeMymoneyCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -21,7 +22,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MinimumValidData(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"+ "\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"+
"\"余额变更\",\"2024-09-01 01:00:00\",\"\",\"Test Account2\",\"-0.12\",\"\",\"\"\n"+ "\"余额变更\",\"2024-09-01 01:00:00\",\"\",\"Test Account2\",\"-0.12\",\"\",\"\"\n"+
@@ -30,7 +31,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MinimumValidData(t *testi
"\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account2\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转入\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account2\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\"\n"+ "\"转入\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\"\n"+
"\"转出\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account2\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\""), 0, nil, nil, nil, nil, nil) "\"转出\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account2\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -110,7 +111,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MinimumValidData(t *testi
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseOutstandingBalanceModification(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseOutstandingBalanceModification(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -118,10 +119,10 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseOutstandingBalanceMo
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"负债变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"+ "\"负债变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"+
"\"负债变更\",\"2024-09-01 01:00:00\",\"\",\"Test Account2\",\"-0.12\",\"\",\"\"\n"), 0, nil, nil, nil, nil, nil) "\"负债变更\",\"2024-09-01 01:00:00\",\"\",\"Test Account2\",\"-0.12\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -160,7 +161,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseOutstandingBalanceMo
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -168,19 +169,19 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidTime(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"收入\",\"2024-09-01T12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), 0, nil, nil, nil, nil, nil) "\"收入\",\"2024-09-01T12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"收入\",\"09/01/2024 12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), 0, nil, nil, nil, nil, nil) "\"收入\",\"09/01/2024 12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -188,14 +189,14 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidType(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"Type\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), 0, nil, nil, nil, nil, nil) "\"Type\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseValidAccountCurrency(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseValidAccountCurrency(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -203,11 +204,11 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseValidAccountCurrency
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+ "\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"USD\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"USD\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, nil, nil, nil, nil, nil) "\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -224,7 +225,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseValidAccountCurrency
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidAccountCurrency(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidAccountCurrency(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -232,23 +233,23 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidAccountCurren
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+ "\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"CNY\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"CNY\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, nil, nil, nil, nil, nil) "\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+ "\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"CNY\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"CNY\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, nil, nil, nil, nil, nil) "\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseNotSupportedCurrency(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseNotSupportedCurrency(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -256,26 +257,26 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseNotSupportedCurrency
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"XXX\",\"123.45\",\"\",\"\""), 0, nil, nil, nil, nil, nil) "\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"XXX\",\"123.45\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"USD\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"USD\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"XXX\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, nil, nil, nil, nil, nil) "\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"XXX\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"XXX\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"XXX\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"USD\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, nil, nil, nil, nil, nil) "\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"USD\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidAmount(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -283,31 +284,31 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidAmount(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), 0, nil, nil, nil, nil, nil) "\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"负债变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), 0, nil, nil, nil, nil, nil) "\"负债变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123 45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123 45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, nil, nil, nil, nil, nil) "\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"123 45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, nil, nil, nil, nil, nil) "\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"123 45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseDescription(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -315,10 +316,10 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseDescription(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"支出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"Test\n"+ "\"支出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"Test\n"+
"A new line break\",\"\""), 0, nil, nil, nil, nil, nil) "A new line break\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -326,7 +327,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseDescription(t *testi
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_InvalidRelatedId(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_InvalidRelatedId(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -334,41 +335,41 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_InvalidRelatedId(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"\""), 0, nil, nil, nil, nil, nil) "\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrRelatedIdCannotBeBlank.Message) assert.EqualError(t, err, errs.ErrRelatedIdCannotBeBlank.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"转入\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"\""), 0, nil, nil, nil, nil, nil) "\"转入\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrRelatedIdCannotBeBlank.Message) assert.EqualError(t, err, errs.ErrRelatedIdCannotBeBlank.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ "\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
"\"转入\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\""), 0, nil, nil, nil, nil, nil) "\"转入\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrFoundRecordNotHasRelatedRecord.Message) assert.EqualError(t, err, errs.ErrFoundRecordNotHasRelatedRecord.Message)
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
Uid: 1, Uid: 1,
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, nil, nil, nil, nil, nil) "\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message) assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(""), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message) assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
} }
func TestFeideeMymoneyCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing.T) { func TestFeideeMymoneyCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing.T) {
converter := FeideeMymoneyAppTransactionDataCsvFileImporter importer := FeideeMymoneyAppTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -377,38 +378,38 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MissingRequiredColumn(t *
} }
// Missing Time Column // Missing Time Column
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, nil, nil, nil, nil, nil) "\"余额变更\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Type Column // Missing Type Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"2024-09-01 00:00:00\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, nil, nil, nil, nil, nil) "\"2024-09-01 00:00:00\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Sub Category Column // Missing Sub Category Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 00:00:00\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, nil, nil, nil, nil, nil) "\"余额变更\",\"2024-09-01 00:00:00\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Account Name Column // Missing Account Name Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"金额\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"123.45\",\"\",\"\"\n"), 0, nil, nil, nil, nil, nil) "\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Amount Column // Missing Amount Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"备注\",\"关联Id\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"备注\",\"关联Id\"\n"+
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"\",\"\"\n"), 0, nil, nil, nil, nil, nil) "\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Related ID Column // Missing Related ID Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\"\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\"\n"+
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\"\n"), 0, nil, nil, nil, nil, nil) "\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
} }
@@ -31,7 +31,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the feidee mymoney (elecloud) transaction xlsx data // ParseImportedData returns the imported data by parsing the feidee mymoney (elecloud) transaction xlsx data
func (c *feideeMymoneyElecloudTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *feideeMymoneyElecloudTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
dataTable, err := excel.CreateNewExcelOOXMLFileBasicDataTable(data, true) dataTable, err := excel.CreateNewExcelOOXMLFileBasicDataTable(data, true)
if err != nil { if err != nil {
@@ -42,5 +42,5 @@ func (c *feideeMymoneyElecloudTransactionDataXlsxFileImporter) ParseImportedData
transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, feideeMymoneyElecloudDataColumnNameMapping, transactionRowParser) transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, feideeMymoneyElecloudDataColumnNameMapping, transactionRowParser)
dataTableImporter := converter.CreateNewSimpleImporter(feideeMymoneyElecloudTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporter(feideeMymoneyElecloudTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -7,13 +7,14 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
"github.com/mayswind/ezbookkeeping/pkg/utils" "github.com/mayswind/ezbookkeeping/pkg/utils"
) )
func TestFeideeMymoneyElecloudTransactionDataXlsxImporterParseImportedData_MinimumValidData(t *testing.T) { func TestFeideeMymoneyElecloudTransactionDataXlsxImporterParseImportedData_MinimumValidData(t *testing.T) {
converter := FeideeMymoneyElecloudTransactionDataXlsxFileImporter importer := FeideeMymoneyElecloudTransactionDataXlsxFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -24,7 +25,7 @@ func TestFeideeMymoneyElecloudTransactionDataXlsxImporterParseImportedData_Minim
testdata, err := os.ReadFile("../../../testdata/feidee_mymoney_elecloud_test_file.xlsx") testdata, err := os.ReadFile("../../../testdata/feidee_mymoney_elecloud_test_file.xlsx")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, testdata, 0, nil, nil, nil, nil, nil) allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, testdata, 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 7, len(allNewTransactions)) assert.Equal(t, 7, len(allNewTransactions))
@@ -30,7 +30,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the feidee mymoney (web) transaction xls data // ParseImportedData returns the imported data by parsing the feidee mymoney (web) transaction xls data
func (c *feideeMymoneyWebTransactionDataXlsFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *feideeMymoneyWebTransactionDataXlsFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
dataTable, err := excel.CreateNewExcelMSCFBFileBasicDataTable(data, true) dataTable, err := excel.CreateNewExcelMSCFBFileBasicDataTable(data, true)
if err != nil { if err != nil {
@@ -41,5 +41,5 @@ func (c *feideeMymoneyWebTransactionDataXlsFileImporter) ParseImportedData(ctx c
transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, feideeMymoneyWebDataColumnNameMapping, transactionRowParser) transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, feideeMymoneyWebDataColumnNameMapping, transactionRowParser)
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(feideeMymoneyTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(feideeMymoneyTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -7,13 +7,14 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
"github.com/mayswind/ezbookkeeping/pkg/utils" "github.com/mayswind/ezbookkeeping/pkg/utils"
) )
func TestFeideeMymoneyTransactionDataXlsImporterParseImportedData_MinimumValidData(t *testing.T) { func TestFeideeMymoneyTransactionDataXlsImporterParseImportedData_MinimumValidData(t *testing.T) {
converter := FeideeMymoneyWebTransactionDataXlsFileImporter importer := FeideeMymoneyWebTransactionDataXlsFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -24,7 +25,7 @@ func TestFeideeMymoneyTransactionDataXlsImporterParseImportedData_MinimumValidDa
testdata, err := os.ReadFile("../../../testdata/feidee_mymoney_test_file.xls") testdata, err := os.ReadFile("../../../testdata/feidee_mymoney_test_file.xls")
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, testdata, 0, nil, nil, nil, nil, nil) allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, testdata, 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 7, len(allNewTransactions)) assert.Equal(t, 7, len(allNewTransactions))
@@ -40,7 +40,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the firefly III transaction csv data // ParseImportedData returns the imported data by parsing the firefly III transaction csv data
func (c *fireflyIIITransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *fireflyIIITransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
reader := bytes.NewReader(data) reader := bytes.NewReader(data)
dataTable, err := csv.CreateNewCsvBasicDataTable(ctx, reader, true) dataTable, err := csv.CreateNewCsvBasicDataTable(ctx, reader, true)
@@ -52,5 +52,5 @@ func (c *fireflyIIITransactionDataCsvFileImporter) ParseImportedData(ctx core.Co
transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, fireflyIIITransactionDataColumnNameMapping, transactionRowParser) transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, fireflyIIITransactionDataColumnNameMapping, transactionRowParser)
dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(fireflyIIITransactionTypeNameMapping, "", "", ",") dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(fireflyIIITransactionTypeNameMapping, "", "", ",")
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -5,14 +5,15 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
"github.com/mayswind/ezbookkeeping/pkg/utils" "github.com/mayswind/ezbookkeeping/pkg/utils"
) )
func TestFireFlyIIICsvFileConverterParseImportedData_MinimumValidData(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_MinimumValidData(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -20,11 +21,11 @@ func TestFireFlyIIICsvFileConverterParseImportedData_MinimumValidData(t *testing
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+ "\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
"Deposit,0.12,2024-09-01T01:23:45+08:00,\"A revenue account\",\"Test Account\",\"Test Category\"\n"+ "Deposit,0.12,2024-09-01T01:23:45+08:00,\"A revenue account\",\"Test Account\",\"Test Category\"\n"+
"Withdrawal,-1.00,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category2\"\n"+ "Withdrawal,-1.00,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category2\"\n"+
"Transfer,0.05,2024-09-01T23:59:59+08:00,\"Test Account\",\"Test Account2\",\"Test Category3\""), 0, nil, nil, nil, nil, nil) "Transfer,0.05,2024-09-01T23:59:59+08:00,\"Test Account\",\"Test Account2\",\"Test Category3\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -82,8 +83,8 @@ func TestFireFlyIIICsvFileConverterParseImportedData_MinimumValidData(t *testing
assert.Equal(t, "Test Category3", allNewSubTransferCategories[0].Name) assert.Equal(t, "Test Category3", allNewSubTransferCategories[0].Name)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseInvalidTime(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseInvalidTime(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -91,17 +92,17 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseInvalidTime(t *testing
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"Withdrawal,-1.00,2024-09-01T12:34:56,\"Test Account\",\"A expense account\",\"Test Category\""), 0, nil, nil, nil, nil, nil) "Withdrawal,-1.00,2024-09-01T12:34:56,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"Withdrawal,-1.00,2024-09-01 12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, nil, nil, nil, nil, nil) "Withdrawal,-1.00,2024-09-01 12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseInvalidType(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseInvalidType(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -109,13 +110,13 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseInvalidType(t *testing
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"Type,123.45,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, nil, nil, nil, nil, nil) "Type,123.45,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseAccountNameAsCategoryName(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseAccountNameAsCategoryName(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -123,23 +124,23 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseAccountNameAsCategoryN
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"Withdrawal,-1.00,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"\""), 0, nil, nil, nil, nil, nil) "Withdrawal,-1.00,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "A expense account", allNewTransactions[0].OriginalCategoryName) assert.Equal(t, "A expense account", allNewTransactions[0].OriginalCategoryName)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"Deposit,10.00,2024-09-01T12:34:56+08:00,\"A revenue account\",\"Test Account\",\"\""), 0, nil, nil, nil, nil, nil) "Deposit,10.00,2024-09-01T12:34:56+08:00,\"A revenue account\",\"Test Account\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "A revenue account", allNewTransactions[0].OriginalCategoryName) assert.Equal(t, "A revenue account", allNewTransactions[0].OriginalCategoryName)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidTimezone(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseValidTimezone(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -147,27 +148,27 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidTimezone(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"Withdrawal,-1.00,2024-09-01T12:34:56-10:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, nil, nil, nil, nil, nil) "Withdrawal,-1.00,2024-09-01T12:34:56-10:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"Withdrawal,-1.00,2024-09-01T12:34:56+00:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, nil, nil, nil, nil, nil) "Withdrawal,-1.00,2024-09-01T12:34:56+00:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"Withdrawal,-1.00,2024-09-01T12:34:56+12:45,\"Test Account\",\"A expense account\",\"Test Category\""), 0, nil, nil, nil, nil, nil) "Withdrawal,-1.00,2024-09-01T12:34:56+12:45,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidAccountCurrency(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseValidAccountCurrency(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -175,9 +176,9 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidAccountCurrency(t
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+ allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+ "\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
"Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category2\""), 0, nil, nil, nil, nil, nil) "Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category2\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -193,8 +194,8 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidAccountCurrency(t
assert.Equal(t, "EUR", allNewAccounts[1].Currency) assert.Equal(t, "EUR", allNewAccounts[1].Currency)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidForeignAmountAndCurrency(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseValidForeignAmountAndCurrency(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -202,8 +203,8 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidForeignAmountAndC
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
"Transfer,10.00,15.00,2024-09-01T12:34:56+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category\""), 0, nil, nil, nil, nil, nil) "Transfer,10.00,15.00,2024-09-01T12:34:56+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -213,8 +214,8 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidForeignAmountAndC
assert.Equal(t, "USD", allNewTransactions[0].OriginalSourceAccountCurrency) assert.Equal(t, "USD", allNewTransactions[0].OriginalSourceAccountCurrency)
assert.Equal(t, "EUR", allNewTransactions[0].OriginalDestinationAccountCurrency) assert.Equal(t, "EUR", allNewTransactions[0].OriginalDestinationAccountCurrency)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
"Transfer,10.00,2024-09-01T12:34:56+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category\""), 0, nil, nil, nil, nil, nil) "Transfer,10.00,2024-09-01T12:34:56+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -223,8 +224,8 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidForeignAmountAndC
assert.Equal(t, "USD", allNewTransactions[0].OriginalSourceAccountCurrency) assert.Equal(t, "USD", allNewTransactions[0].OriginalSourceAccountCurrency)
assert.Equal(t, "EUR", allNewTransactions[0].OriginalDestinationAccountCurrency) assert.Equal(t, "EUR", allNewTransactions[0].OriginalDestinationAccountCurrency)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
"Transfer,10.00,2024-09-01T12:34:56+08:00,USD,,\"Test Account\",\"Test Account2\",\"Test Category\""), 0, nil, nil, nil, nil, nil) "Transfer,10.00,2024-09-01T12:34:56+08:00,USD,,\"Test Account\",\"Test Account2\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -232,8 +233,8 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseValidForeignAmountAndC
assert.Equal(t, "USD", allNewTransactions[0].OriginalDestinationAccountCurrency) assert.Equal(t, "USD", allNewTransactions[0].OriginalDestinationAccountCurrency)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseInvalidAccountCurrency(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseInvalidAccountCurrency(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -241,19 +242,19 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseInvalidAccountCurrency
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+ "\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
"Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,CNY,EUR,\"Test Account\",\"Test Account2\",\"Test Category3\""), 0, nil, nil, nil, nil, nil) "Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,CNY,EUR,\"Test Account\",\"Test Account2\",\"Test Category3\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+ "\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
"Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,CNY,EUR,\"Test Account2\",\"Test Account\",\"Test Category3\""), 0, nil, nil, nil, nil, nil) "Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,CNY,EUR,\"Test Account2\",\"Test Account\",\"Test Category3\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseNotSupportedCurrency(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseNotSupportedCurrency(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -261,17 +262,17 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseNotSupportedCurrency(t
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,XXX,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, nil, nil, nil, nil, nil) "\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,XXX,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
"Transfer,123.45,123.45,2024-09-01T23:59:59+08:00,USD,XXX,\"Test Account\",\"Test Account2\",\"Test Category2\""), 0, nil, nil, nil, nil, nil) "Transfer,123.45,123.45,2024-09-01T23:59:59+08:00,USD,XXX,\"Test Account\",\"Test Account2\",\"Test Category2\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseInvalidAmount(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -279,17 +280,17 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseInvalidAmount(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
"Withdrawal,-123 45,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), 0, nil, nil, nil, nil, nil) "Withdrawal,-123 45,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,source_name,destination_name,category\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,source_name,destination_name,category\n"+
"Transfer,123.45,123 45,2024-09-01T23:59:59+08:00,\"Test Account\",\"Test Account2\",\"Test Category2\""), 0, nil, nil, nil, nil, nil) "Transfer,123.45,123 45,2024-09-01T23:59:59+08:00,\"Test Account\",\"Test Account2\",\"Test Category2\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseDescription(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseDescription(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -297,16 +298,16 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseDescription(t *testing
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,description,date,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,description,date,source_name,destination_name,category\n"+
"Withdrawal,-123.45,\"foo bar\t#test\",2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), 0, nil, nil, nil, nil, nil) "Withdrawal,-123.45,\"foo bar\t#test\",2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "foo bar\t#test", allNewTransactions[0].Comment) assert.Equal(t, "foo bar\t#test", allNewTransactions[0].Comment)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_ParseTags(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_ParseTags(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -314,8 +315,8 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseTags(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, allNewTags, err := converter.ParseImportedData(context, user, []byte("type,amount,tags,date,source_name,destination_name,category\n"+ allNewTransactions, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte("type,amount,tags,date,source_name,destination_name,category\n"+
"Withdrawal,-123.45,\"tag1,tag2,tag3\",2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), 0, nil, nil, nil, nil, nil) "Withdrawal,-123.45,\"tag1,tag2,tag3\",2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -328,8 +329,8 @@ func TestFireFlyIIICsvFileConverterParseImportedData_ParseTags(t *testing.T) {
assert.Equal(t, "tag3", allNewTags[2].Name) assert.Equal(t, "tag3", allNewTags[2].Name)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_MissingFileHeader(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_MissingFileHeader(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -337,12 +338,12 @@ func TestFireFlyIIICsvFileConverterParseImportedData_MissingFileHeader(t *testin
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(""), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestFireFlyIIICsvFileConverterParseImportedData_MissingRequiredColumn(t *testing.T) { func TestFireFlyIIICsvFileimporterParseImportedData_MissingRequiredColumn(t *testing.T) {
converter := FireflyIIITransactionDataCsvFileImporter importer := FireflyIIITransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -351,32 +352,32 @@ func TestFireFlyIIICsvFileConverterParseImportedData_MissingRequiredColumn(t *te
} }
// Missing Time Column // Missing Time Column
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("type,amount,source_name,destination_name,category\n"+ _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,source_name,destination_name,category\n"+
"\"Opening balance\",123.45,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, nil, nil, nil, nil, nil) "\"Opening balance\",123.45,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Type Column // Missing Type Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("amount,date,source_name,destination_name,category\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("amount,date,source_name,destination_name,category\n"+
"123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, nil, nil, nil, nil, nil) "123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Sub Category Column // Missing Sub Category Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name\n"+
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\"\n"), 0, nil, nil, nil, nil, nil) "\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Account Name Column // Missing Account Name Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,date,destination_name,category\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,destination_name,category\n"+
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Test Account\",\n"), 0, nil, nil, nil, nil, nil) "\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Amount Column // Missing Amount Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,date,source_name,destination_name,category\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,date,source_name,destination_name,category\n"+
"\"Opening balance\",2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, nil, nil, nil, nil, nil) "\"Opening balance\",2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Account2 Name Column // Missing Account2 Name Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("type,amount,date,source_name,category\n"+ _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,category\n"+
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\n"), 0, nil, nil, nil, nil, nil) "\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
} }
@@ -24,7 +24,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the gnucash transaction data // ParseImportedData returns the imported data by parsing the gnucash transaction data
func (c *gnucashTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *gnucashTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
gnucashDataReader, err := createNewGnuCashDatabaseReader(data) gnucashDataReader, err := createNewGnuCashDatabaseReader(data)
if err != nil { if err != nil {
@@ -45,5 +45,5 @@ func (c *gnucashTransactionDataImporter) ParseImportedData(ctx core.Context, use
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(gnucashTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(gnucashTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -185,7 +186,7 @@ const gnucashCommonValidDataCaseFooter = "</gnc:book>\n" +
"</gnc-v2>\n" "</gnc-v2>\n"
func TestGnuCashTransactionDatabaseFileParseImportedData_MinimumValidData(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_MinimumValidData(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -193,14 +194,14 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MinimumValidData(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte(gnucashMinimumValidDataCase), 0, nil, nil, nil, nil, nil) allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(gnucashMinimumValidDataCase), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags) checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags)
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_GzippedMinimumValidData(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_GzippedMinimumValidData(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -217,14 +218,14 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_GzippedMinimumValidData
assert.Nil(t, err) assert.Nil(t, err)
gzippedData := buffer.Bytes() gzippedData := buffer.Bytes()
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, gzippedData, 0, nil, nil, nil, nil, nil) allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, gzippedData, 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags) checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags)
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_MinimumValidDataWithReversedSplitOrder(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_MinimumValidDataWithReversedSplitOrder(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -232,7 +233,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MinimumValidDataWithRev
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"+ allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"+
"<gnc-v2\n"+ "<gnc-v2\n"+
" xmlns:gnc=\"http://www.gnucash.org/XML/gnc\"\n"+ " xmlns:gnc=\"http://www.gnucash.org/XML/gnc\"\n"+
" xmlns:act=\"http://www.gnucash.org/XML/act\"\n"+ " xmlns:act=\"http://www.gnucash.org/XML/act\"\n"+
@@ -356,14 +357,14 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MinimumValidDataWithRev
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
"</gnc:book>\n"+ "</gnc:book>\n"+
"</gnc-v2>\n"), 0, nil, nil, nil, nil, nil) "</gnc-v2>\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags) checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags)
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidTime(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidTime(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -371,7 +372,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidTime(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -388,10 +389,10 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidTime(t *tes
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -408,12 +409,12 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidTime(t *tes
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidTimezone(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidTimezone(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -421,7 +422,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidTimezone(t *t
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -438,12 +439,12 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidTimezone(t *t
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -460,14 +461,14 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidTimezone(t *t
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAccountCurrency(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAccountCurrency(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -475,7 +476,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAccountCurren
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"+ allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"+
"<gnc-v2\n"+ "<gnc-v2\n"+
" xmlns:gnc=\"http://www.gnucash.org/XML/gnc\"\n"+ " xmlns:gnc=\"http://www.gnucash.org/XML/gnc\"\n"+
" xmlns:act=\"http://www.gnucash.org/XML/act\"\n"+ " xmlns:act=\"http://www.gnucash.org/XML/act\"\n"+
@@ -557,7 +558,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAccountCurren
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
"</gnc:book>\n"+ "</gnc:book>\n"+
"</gnc-v2>\n"), 0, nil, nil, nil, nil, nil) "</gnc-v2>\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -574,7 +575,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAccountCurren
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAmount(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAmount(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -582,7 +583,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAmount(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -599,13 +600,13 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAmount(t *tes
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, int64(1234500), allNewTransactions[0].Amount) assert.Equal(t, int64(1234500), allNewTransactions[0].Amount)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -622,7 +623,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAmount(t *tes
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -630,7 +631,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAmount(t *tes
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidAmount(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -638,7 +639,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidAmount(t *t
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -655,10 +656,10 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidAmount(t *t
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -675,10 +676,10 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidAmount(t *t
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -695,12 +696,12 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidAmount(t *t
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_ParseDescription(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_ParseDescription(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -708,7 +709,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseDescription(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -726,7 +727,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseDescription(t *tes
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -734,7 +735,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseDescription(t *tes
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_SkipZeroAmountTransaction(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_SkipZeroAmountTransaction(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -742,7 +743,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_SkipZeroAmountTransacti
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -755,12 +756,12 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_SkipZeroAmountTransacti
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_NotSupportedToParseSplitTransaction(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_NotSupportedToParseSplitTransaction(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -768,7 +769,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_NotSupportedToParseSpli
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:account version=\"2.0.0\">\n"+ "<gnc:account version=\"2.0.0\">\n"+
" <act:name>Test Category2</act:name>\n"+ " <act:name>Test Category2</act:name>\n"+
@@ -805,12 +806,12 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_NotSupportedToParseSpli
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message) assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_MissingAccountRequiredNode(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_MissingAccountRequiredNode(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -819,7 +820,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingAccountRequiredN
} }
// Missing Account Currency Node // Missing Account Currency Node
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"+ "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"+
"<gnc-v2\n"+ "<gnc-v2\n"+
" xmlns:gnc=\"http://www.gnucash.org/XML/gnc\"\n"+ " xmlns:gnc=\"http://www.gnucash.org/XML/gnc\"\n"+
@@ -872,12 +873,12 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingAccountRequiredN
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequiredNode(t *testing.T) { func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequiredNode(t *testing.T) {
converter := GnuCashTransactionDataImporter importer := GnuCashTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -886,7 +887,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequi
} }
// Missing Transaction Time Node // Missing Transaction Time Node
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:splits>\n"+ " <trn:splits>\n"+
@@ -900,22 +901,22 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequi
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message) assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
// Missing Transaction Splits Node // Missing Transaction Splits Node
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
" <ts:date>2024-09-01 00:00:00 +0000</ts:date>\n"+ " <ts:date>2024-09-01 00:00:00 +0000</ts:date>\n"+
" </trn:date-posted>\n"+ " </trn:date-posted>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidGnuCashFile.Message) assert.EqualError(t, err, errs.ErrInvalidGnuCashFile.Message)
// Missing Transaction Split Quantity Node // Missing Transaction Split Quantity Node
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -930,11 +931,11 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequi
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
// Missing Transaction Split Account Node // Missing Transaction Split Account Node
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
gnucashCommonValidDataCaseHeader+ gnucashCommonValidDataCaseHeader+
"<gnc:transaction version=\"2.0.0\">\n"+ "<gnc:transaction version=\"2.0.0\">\n"+
" <trn:date-posted>\n"+ " <trn:date-posted>\n"+
@@ -950,7 +951,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequi
" </trn:split>\n"+ " </trn:split>\n"+
" </trn:splits>\n"+ " </trn:splits>\n"+
"</gnc:transaction>\n"+ "</gnc:transaction>\n"+
gnucashCommonValidDataCaseFooter), 0, nil, nil, nil, nil, nil) gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingAccountData.Message) assert.EqualError(t, err, errs.ErrMissingAccountData.Message)
} }
@@ -23,7 +23,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the intuit interchange format (iif) data // ParseImportedData returns the imported data by parsing the intuit interchange format (iif) data
func (c *iifTransactionDataFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *iifTransactionDataFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
iifDataReader := createNewIifDataReader(data) iifDataReader := createNewIifDataReader(data)
accountDatasets, transactionDatasets, err := iifDataReader.read(ctx) accountDatasets, transactionDatasets, err := iifDataReader.read(ctx)
@@ -39,5 +39,5 @@ func (c *iifTransactionDataFileImporter) ParseImportedData(ctx core.Context, use
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(iifTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(iifTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -12,7 +13,7 @@ import (
) )
func TestIIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -20,7 +21,7 @@ func TestIIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(
"!ACCNT\tNAME\tACCNTTYPE\n"+ "!ACCNT\tNAME\tACCNTTYPE\n"+
"ACCNT\tTest Account\tBANK\n"+ "ACCNT\tTest Account\tBANK\n"+
"ACCNT\tTest Account2\tBANK\n"+ "ACCNT\tTest Account2\tBANK\n"+
@@ -49,7 +50,7 @@ func TestIIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
"ENDTRNS\t\t\t\t\n"+ "ENDTRNS\t\t\t\t\n"+
"TRNS\tCREDIT CARD\t09/07/2024\tTest Category2\t34.56\n"+ "TRNS\tCREDIT CARD\t09/07/2024\tTest Category2\t34.56\n"+
"SPL\tCREDIT CARD\t09/07/2024\tTest Account2\t-34.56\n"+ "SPL\tCREDIT CARD\t09/07/2024\tTest Account2\t-34.56\n"+
"ENDTRNS\t\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -132,7 +133,7 @@ func TestIIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
} }
func TestIIFTransactionDataFileParseImportedData_MinimumValidDataWithoutAccountData(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_MinimumValidDataWithoutAccountData(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -140,13 +141,13 @@ func TestIIFTransactionDataFileParseImportedData_MinimumValidDataWithoutAccountD
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Category\t-123.45\n"+ "SPL\t09/01/2024\tTest Category\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -162,7 +163,7 @@ func TestIIFTransactionDataFileParseImportedData_MinimumValidDataWithoutAccountD
} }
func TestIIFTransactionDataFileParseImportedData_MultipleDataset(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_MultipleDataset(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -170,7 +171,7 @@ func TestIIFTransactionDataFileParseImportedData_MultipleDataset(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!ACCNT\tNAME\tACCNTTYPE\n"+ "!ACCNT\tNAME\tACCNTTYPE\n"+
"ACCNT\tTest Account3\tBANK\n"+ "ACCNT\tTest Account3\tBANK\n"+
"ACCNT\tTest Account4\tBANK\n"+ "ACCNT\tTest Account4\tBANK\n"+
@@ -202,7 +203,7 @@ func TestIIFTransactionDataFileParseImportedData_MultipleDataset(t *testing.T) {
"ENDTRNS\t\t\t\t\n"+ "ENDTRNS\t\t\t\t\n"+
"!ACCNT\tTEST\tNAME\tACCNTTYPE\n"+ "!ACCNT\tTEST\tNAME\tACCNTTYPE\n"+
"ACCNT\t\tTest Category\tINC\n"+ "ACCNT\t\tTest Category\tINC\n"+
"ACCNT\t\tTest Category2\tEXP\n"), 0, nil, nil, nil, nil, nil) "ACCNT\t\tTest Category2\tEXP\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -247,7 +248,7 @@ func TestIIFTransactionDataFileParseImportedData_MultipleDataset(t *testing.T) {
} }
func TestIIFTransactionDataFileParseImportedData_ParseCategoryAndSubCategory(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseCategoryAndSubCategory(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -255,7 +256,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseCategoryAndSubCategory(t *
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, allNewSubExpenseCategories, allNewSubIncomeCategories, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, allNewSubExpenseCategories, allNewSubIncomeCategories, _, _, err := importer.ParseImportedData(context, user, []byte(
"!ACCNT\tNAME\tACCNTTYPE\n"+ "!ACCNT\tNAME\tACCNTTYPE\n"+
"ACCNT\tTest Parent Category:Test Category\tINC\n"+ "ACCNT\tTest Parent Category:Test Category\tINC\n"+
"ACCNT\tTest Parent Category2:Test Category2\tEXP\n"+ "ACCNT\tTest Parent Category2:Test Category2\tEXP\n"+
@@ -267,7 +268,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseCategoryAndSubCategory(t *
"ENDTRNS\t\t\t\n"+ "ENDTRNS\t\t\t\n"+
"TRNS\t09/02/2024\tTest Account2\t-123.45\n"+ "TRNS\t09/02/2024\tTest Account2\t-123.45\n"+
"SPL\t09/02/2024\tTest Parent Category2:Test Category2\t123.45\n"+ "SPL\t09/02/2024\tTest Parent Category2:Test Category2\t123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -299,7 +300,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseCategoryAndSubCategory(t *
} }
func TestIIFTransactionDataFileParseImportedData_ParseYearMonthDayFormatTime(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseYearMonthDayFormatTime(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -307,7 +308,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseYearMonthDayFormatTime(t *
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
@@ -322,7 +323,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseYearMonthDayFormatTime(t *
"ENDTRNS\t\t\t\n"+ "ENDTRNS\t\t\t\n"+
"TRNS\t2024/9/4\tTest Account\t123.45\n"+ "TRNS\t2024/9/4\tTest Account\t123.45\n"+
"SPL\t2024/9/4\tTest Account2\t-123.45\n"+ "SPL\t2024/9/4\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -334,7 +335,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseYearMonthDayFormatTime(t *
} }
func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayYearFormatTime(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayYearFormatTime(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -342,7 +343,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayYearFormatTim
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
@@ -354,7 +355,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayYearFormatTim
"ENDTRNS\t\t\t\n"+ "ENDTRNS\t\t\t\n"+
"TRNS\t9/3/2024\tTest Account\t123.45\n"+ "TRNS\t9/3/2024\tTest Account\t123.45\n"+
"SPL\t9/3/2024\tTest Account2\t-123.45\n"+ "SPL\t9/3/2024\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -365,7 +366,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayYearFormatTim
} }
func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayTwoDigitsYearFormatTime(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayTwoDigitsYearFormatTime(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -373,7 +374,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayTwoDigitsYear
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
@@ -385,7 +386,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayTwoDigitsYear
"ENDTRNS\t\t\t\n"+ "ENDTRNS\t\t\t\n"+
"TRNS\t24/9/3\tTest Account\t123.45\n"+ "TRNS\t24/9/3\tTest Account\t123.45\n"+
"SPL\t24/9/3\tTest Account2\t-123.45\n"+ "SPL\t24/9/3\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -396,7 +397,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayTwoDigitsYear
} }
func TestIIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -404,36 +405,36 @@ func TestIIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09-01-2024\tTest Account\t123.45\n"+ "TRNS\t09-01-2024\tTest Account\t123.45\n"+
"SPL\t09-01-2024\tTest Account2\t-123.45\n"+ "SPL\t09-01-2024\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t2024-09-01\tTest Account\t123.45\n"+ "TRNS\t2024-09-01\tTest Account\t123.45\n"+
"SPL\t2024-09-01\tTest Account2\t-123.45\n"+ "SPL\t2024-09-01\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t9/24\tTest Account\t123.45\n"+ "TRNS\t9/24\tTest Account\t123.45\n"+
"SPL\t9/24\tTest Account2\t-123.45\n"+ "SPL\t9/24\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestIIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparator(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparator(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -441,13 +442,13 @@ func TestIIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparat
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t9/01/2024\tTest Account\t123,456.78\n"+ "TRNS\t9/01/2024\tTest Account\t123,456.78\n"+
"SPL\t9/01/2024\tTest Account2\t-123,456.78\n"+ "SPL\t9/01/2024\tTest Account2\t-123,456.78\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -456,7 +457,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparat
} }
func TestIIFTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -464,27 +465,27 @@ func TestIIFTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123 45\n"+ "TRNS\t09/01/2024\tTest Account\t123 45\n"+
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+ "SPL\t09/01/2024\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Account2\t-123 45\n"+ "SPL\t09/01/2024\tTest Account2\t-123 45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestIIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -492,25 +493,25 @@ func TestIIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+ "!TRNS\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+
"!SPL\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+ "!SPL\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+
"!ENDTRNS\t\t\t\t\t\n"+ "!ENDTRNS\t\t\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t\"Test\"\t123.45\t\"foo bar\t#test\"\n"+ "TRNS\t09/01/2024\tTest Account\t\"Test\"\t123.45\t\"foo bar\t#test\"\n"+
"SPL\t09/01/2024\tTest Account2\t\t-123.45\t\n"+ "SPL\t09/01/2024\tTest Account2\t\t-123.45\t\n"+
"ENDTRNS\t\t\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "foo bar\t#test", allNewTransactions[0].Comment) assert.Equal(t, "foo bar\t#test", allNewTransactions[0].Comment)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+ "!TRNS\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+
"!SPL\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+ "!SPL\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+
"!ENDTRNS\t\t\t\t\t\n"+ "!ENDTRNS\t\t\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\tTest\t123.45\t\n"+ "TRNS\t09/01/2024\tTest Account\tTest\t123.45\t\n"+
"SPL\t09/01/2024\tTest Account2\t\t-123.45\t\n"+ "SPL\t09/01/2024\tTest Account2\t\t-123.45\t\n"+
"ENDTRNS\t\t\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -518,7 +519,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
} }
func TestIIFTransactionDataFileParseImportedData_ParseSplitTransaction(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseSplitTransaction(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -526,7 +527,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseSplitTransaction(t *testin
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!ACCNT\tNAME\tACCNTTYPE\n"+ "!ACCNT\tNAME\tACCNTTYPE\n"+
"ACCNT\tTest Category\tINC\n"+ "ACCNT\tTest Category\tINC\n"+
"ACCNT\tTest Category2\tEXP\n"+ "ACCNT\tTest Category2\tEXP\n"+
@@ -552,7 +553,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseSplitTransaction(t *testin
"TRNS\t09/05/2024\tTest Category2\t100.00\n"+ "TRNS\t09/05/2024\tTest Category2\t100.00\n"+
"SPL\t09/05/2024\tTest Account3\t-40.00\n"+ "SPL\t09/05/2024\tTest Account3\t-40.00\n"+
"SPL\t09/05/2024\tTest Account4\t-60.00\n"+ "SPL\t09/05/2024\tTest Account4\t-60.00\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -651,7 +652,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseSplitTransaction(t *testin
} }
func TestIIFTransactionDataFileParseImportedData_ParseSplitTransactionDescription(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_ParseSplitTransactionDescription(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -659,21 +660,21 @@ func TestIIFTransactionDataFileParseImportedData_ParseSplitTransactionDescriptio
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+ "!TRNS\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+
"!SPL\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+ "!SPL\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+
"!ENDTRNS\t\t\t\t\t\n"+ "!ENDTRNS\t\t\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t\"Test\"\t123.45\t\"foo bar\t#test\"\n"+ "TRNS\t09/01/2024\tTest Account\t\"Test\"\t123.45\t\"foo bar\t#test\"\n"+
"SPL\t09/01/2024\tTest Account2\t\t-100.00\t\"foo\ttest#bar\"\n"+ "SPL\t09/01/2024\tTest Account2\t\t-100.00\t\"foo\ttest#bar\"\n"+
"SPL\t09/01/2024\tTest Account3\t\t-23.45\t\n"+ "SPL\t09/01/2024\tTest Account3\t\t-23.45\t\n"+
"ENDTRNS\t\t\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, len(allNewTransactions)) assert.Equal(t, 2, len(allNewTransactions))
assert.Equal(t, "foo\ttest#bar", allNewTransactions[0].Comment) assert.Equal(t, "foo\ttest#bar", allNewTransactions[0].Comment)
assert.Equal(t, "foo bar\t#test", allNewTransactions[1].Comment) assert.Equal(t, "foo bar\t#test", allNewTransactions[1].Comment)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+ "!TRNS\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+
"!SPL\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+ "!SPL\tDATE\tACCNT\tNAME\tAMOUNT\tMEMO\n"+
"!ENDTRNS\t\t\t\t\t\n"+ "!ENDTRNS\t\t\t\t\t\n"+
@@ -681,7 +682,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseSplitTransactionDescriptio
"SPL\t09/01/2024\tTest Account2\t\t-100.00\t\"test\"\n"+ "SPL\t09/01/2024\tTest Account2\t\t-100.00\t\"test\"\n"+
"SPL\t09/01/2024\tTest Account3\tfoo\t-12.34\t\n"+ "SPL\t09/01/2024\tTest Account3\tfoo\t-12.34\t\n"+
"SPL\t09/01/2024\tTest Account4\t\t-11.11\t\n"+ "SPL\t09/01/2024\tTest Account4\t\t-11.11\t\n"+
"ENDTRNS\t\t\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 3, len(allNewTransactions)) assert.Equal(t, 3, len(allNewTransactions))
@@ -691,7 +692,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseSplitTransactionDescriptio
} }
func TestIIFTransactionDataFileParseImportedData_NotSupportedSplitTransaction(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_NotSupportedSplitTransaction(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -700,52 +701,52 @@ func TestIIFTransactionDataFileParseImportedData_NotSupportedSplitTransaction(t
} }
// Opening balance transaction // Opening balance transaction
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tTRNSTYPE\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tTRNSTYPE\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tTRNSTYPE\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tTRNSTYPE\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\t\n"+ "!ENDTRNS\t\t\t\t\n"+
"TRNS\tBEGINBALCHECK\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\tBEGINBALCHECK\t09/01/2024\tTest Account\t123.45\n"+
"SPL\tBEGINBALCHECK\t09/01/2024\tTest Account2\t-100.00\n"+ "SPL\tBEGINBALCHECK\t09/01/2024\tTest Account2\t-100.00\n"+
"SPL\tBEGINBALCHECK\t09/01/2024\tTest Account3\t-23.45\n"+ "SPL\tBEGINBALCHECK\t09/01/2024\tTest Account3\t-23.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message) assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
// Transaction with invalid amount // Transaction with invalid amount
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123 45\n"+ "TRNS\t09/01/2024\tTest Account\t123 45\n"+
"SPL\t09/01/2024\tTest Account2\t-100.00\n"+ "SPL\t09/01/2024\tTest Account2\t-100.00\n"+
"SPL\t09/01/2024\tTest Account3\t-23.45\n"+ "SPL\t09/01/2024\tTest Account3\t-23.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
// Transaction split data with invalid amount // Transaction split data with invalid amount
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Account2\t-100 00\n"+ "SPL\t09/01/2024\tTest Account2\t-100 00\n"+
"SPL\t09/01/2024\tTest Account3\t-23.45\n"+ "SPL\t09/01/2024\tTest Account3\t-23.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
// Transaction amount not equal to sum of split data amount // Transaction amount not equal to sum of split data amount
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123.00\n"+ "TRNS\t09/01/2024\tTest Account\t123.00\n"+
"SPL\t09/01/2024\tTest Account2\t-100.00\n"+ "SPL\t09/01/2024\tTest Account2\t-100.00\n"+
"SPL\t09/01/2024\tTest Account3\t-23.45\n"+ "SPL\t09/01/2024\tTest Account3\t-23.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message) assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
} }
func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -754,75 +755,75 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
} }
//Missing Transaction Line //Missing Transaction Line
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+ "SPL\t09/01/2024\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Missing Transaction And Split Line // Missing Transaction And Split Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Missing Split Line // Missing Split Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Missing Transaction End Line // Missing Transaction End Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Account2\t-123.45\n"), 0, nil, nil, nil, nil, nil) "SPL\t09/01/2024\tTest Account2\t-123.45\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Missing Transaction End Line (following is another header) // Missing Transaction End Line (following is another header)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+ "SPL\t09/01/2024\tTest Account2\t-123.45\n"+
"!ACCNT\tNAME\tACCNTTYPE\n"+ "!ACCNT\tNAME\tACCNTTYPE\n"+
"ACCNT\tTest Account\tBANK\n"), 0, nil, nil, nil, nil, nil) "ACCNT\tTest Account\tBANK\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Invalid Line // Invalid Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+ "SPL\t09/01/2024\tTest Account2\t-123.45\n"+
"TEST\t\t\t\n"+ "TEST\t\t\t\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Repeat Transaction Line // Repeat Transaction Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+ "SPL\t09/01/2024\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Repeat Transaction End Line // Repeat Transaction End Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\t\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\t\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\t\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\t\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
@@ -830,12 +831,12 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+ "SPL\t09/01/2024\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"+ "ENDTRNS\t\t\t\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
} }
func TestIIFTransactionDataFileParseImportedData_InvalidHeaderLines(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_InvalidHeaderLines(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -844,49 +845,49 @@ func TestIIFTransactionDataFileParseImportedData_InvalidHeaderLines(t *testing.T
} }
// Missing All Sample Lines // Missing All Sample Lines
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+ "SPL\t09/01/2024\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Missing Transaction Sample Line // Missing Transaction Sample Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "!ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Missing Split Sample Line // Missing Split Sample Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "!ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Missing Transaction End Sample Line // Missing Transaction End Sample Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"), 0, nil, nil, nil, nil, nil) "!SPL\tDATE\tACCNT\tAMOUNT\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Missing Transaction End Sample Line (following is data line) // Missing Transaction End Sample Line (following is data line)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!SPL\tDATE\tACCNT\tAMOUNT\n"+ "!SPL\tDATE\tACCNT\tAMOUNT\n"+
"TRNS\t09/01/2024\tTest Account\t123.45\n"+ "TRNS\t09/01/2024\tTest Account\t123.45\n"+
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+ "SPL\t09/01/2024\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
// Invalid Sample Line // Invalid Sample Line
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+ "!TRNS\tDATE\tACCNT\tAMOUNT\n"+
"!TEST\tDATE\tACCNT\tAMOUNT\n"+ "!TEST\tDATE\tACCNT\tAMOUNT\n"+
"!ENDTRNS\t\t\t\n"), 0, nil, nil, nil, nil, nil) "!ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message) assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
} }
func TestIIFTransactionDataFileParseImportedData_MissingRequiredColumn(t *testing.T) { func TestIIFTransactionDataFileParseImportedData_MissingRequiredColumn(t *testing.T) {
converter := IifTransactionDataFileImporter importer := IifTransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -895,32 +896,32 @@ func TestIIFTransactionDataFileParseImportedData_MissingRequiredColumn(t *testin
} }
// Missing Date Column // Missing Date Column
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!TRNS\tACCNT\tAMOUNT\t\n"+ "!TRNS\tACCNT\tAMOUNT\t\n"+
"!SPL\tACCNT\tAMOUNT\t\n"+ "!SPL\tACCNT\tAMOUNT\t\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\tTest Account\t123.45\n"+ "TRNS\tTest Account\t123.45\n"+
"SPL\tTest Account2\t-123.45\n"+ "SPL\tTest Account2\t-123.45\n"+
"ENDTRNS\t\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Account Column // Missing Account Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tAMOUNT\t\n"+ "!TRNS\tDATE\tAMOUNT\t\n"+
"!SPL\tDATE\tAMOUNT\t\n"+ "!SPL\tDATE\tAMOUNT\t\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\t123.45\n"+ "TRNS\t09/01/2024\t123.45\n"+
"SPL\t09/01/2024\t-123.45\n"+ "SPL\t09/01/2024\t-123.45\n"+
"ENDTRNS\t\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Amount Column // Missing Amount Column
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!TRNS\tDATE\tACCNT\t\n"+ "!TRNS\tDATE\tACCNT\t\n"+
"!SPL\tDATE\tACCNT\t\n"+ "!SPL\tDATE\tACCNT\t\n"+
"!ENDTRNS\t\t\t\n"+ "!ENDTRNS\t\t\t\n"+
"TRNS\t09/01/2024\tTest Account\n"+ "TRNS\t09/01/2024\tTest Account\n"+
"SPL\t09/01/2024\tTest Account2\n"+ "SPL\t09/01/2024\tTest Account2\n"+
"ENDTRNS\t\t\t\t\n"), 0, nil, nil, nil, nil, nil) "ENDTRNS\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
} }
@@ -27,7 +27,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the jd.com finance transaction csv data // ParseImportedData returns the imported data by parsing the jd.com finance transaction csv data
func (c *jdComFinanceTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *jdComFinanceTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
fallback := unicode.UTF8.NewDecoder() fallback := unicode.UTF8.NewDecoder()
reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback)) reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback))
@@ -60,5 +60,5 @@ func (c *jdComFinanceTransactionDataCsvFileImporter) ParseImportedData(ctx core.
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, jdComFinanceTransactionSupportedColumns, transactionRowParser) transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, jdComFinanceTransactionSupportedColumns, transactionRowParser)
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(jdComFinanceTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(jdComFinanceTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -13,7 +14,7 @@ import (
) )
func TestJDComFinanceCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -30,7 +31,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MinimumValidData(t *testin
"2025-09-01 12:34:56,xxx,xxx,123.45,银行卡,交易成功,支出,其他网购\n" + "2025-09-01 12:34:56,xxx,xxx,123.45,银行卡,交易成功,支出,其他网购\n" +
"2025-09-01 23:59:59,xxx,京东钱包余额充值,0.05,银行卡,交易成功,不计收支,余额\n" + "2025-09-01 23:59:59,xxx,京东钱包余额充值,0.05,银行卡,交易成功,不计收支,余额\n" +
"2025-09-02 23:59:59,xxx,京东余额提现,0.03,银行卡,交易成功,不计收支,余额\n" "2025-09-02 23:59:59,xxx,京东余额提现,0.03,银行卡,交易成功,不计收支,余额\n"
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 4, len(allNewTransactions)) assert.Equal(t, 4, len(allNewTransactions))
@@ -93,7 +94,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MinimumValidData(t *testin
} }
func TestJDComFinanceCsvFileImporterParseImportedData_ParseRefundTransaction(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_ParseRefundTransaction(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -110,7 +111,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseRefundTransaction(t *
"2025-09-01 02:34:56,xxx,xxx,0.12(已全额退款),银行卡,交易成功,不计收支\n" + "2025-09-01 02:34:56,xxx,xxx,0.12(已全额退款),银行卡,交易成功,不计收支\n" +
"2025-09-02 01:23:45,xxx,xxx,3.45,银行卡,退款成功,不计收支\n" + "2025-09-02 01:23:45,xxx,xxx,3.45,银行卡,退款成功,不计收支\n" +
"2025-09-02 02:34:56,xxx,xxx,123.45(已退款3.45),银行卡,交易成功,支出\n" "2025-09-02 02:34:56,xxx,xxx,123.45(已退款3.45),银行卡,交易成功,支出\n"
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid) assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
@@ -139,7 +140,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseRefundTransaction(t *
} }
func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -153,7 +154,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidTime(t *testin
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"2025-09-01T01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n" "2025-09-01T01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
data2 := "导出信息:\n" + data2 := "导出信息:\n" +
@@ -162,12 +163,12 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidTime(t *testin
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"09/01/2025 01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n" "09/01/2025 01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -181,12 +182,12 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidType(t *testin
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,转账\n" "2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,转账\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidAmount(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -200,12 +201,12 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidAmount(t *test
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,xxx,¥0.12,银行卡,交易成功,支出\n" "2025-09-01 01:23:45,xxx,xxx,¥0.12,银行卡,交易成功,支出\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -220,7 +221,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支,交易分类\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支,交易分类\n" +
"2025-09-01 01:23:45,xxx,京东钱包余额充值,0.05,银行卡,交易成功,不计收支,余额\n" "2025-09-01 01:23:45,xxx,京东钱包余额充值,0.05,银行卡,交易成功,不计收支,余额\n"
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -235,7 +236,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支,交易分类\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支,交易分类\n" +
"2025-09-01 01:23:45,xxx,京东余额提现,0.05,银行卡,交易成功,不计收支,余额\n" "2025-09-01 01:23:45,xxx,京东余额提现,0.05,银行卡,交易成功,不计收支,余额\n"
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -252,7 +253,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
"2025-09-01 01:23:45,xxx,京东小金库-转入,0.05,余额,交易成功,不计收支,小金库\n" "2025-09-01 01:23:45,xxx,京东小金库-转入,0.05,余额,交易成功,不计收支,小金库\n"
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data3), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -269,7 +270,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
"2025-09-01 01:23:45,xxx,京东小金库-转出,0.05,余额,交易成功,不计收支,小金库\n" "2025-09-01 01:23:45,xxx,京东小金库-转出,0.05,余额,交易成功,不计收支,小金库\n"
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data4), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -286,7 +287,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
"2025-09-01 01:23:45,xxx,价保退款,0.05,银行卡,交易成功,不计收支,其他\n" "2025-09-01 01:23:45,xxx,价保退款,0.05,银行卡,交易成功,不计收支,其他\n"
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data5), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -302,7 +303,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
"2025-09-01 01:23:45,xxx,白条主动还款,0.05,银行卡,交易成功,不计收支,白条\n" "2025-09-01 01:23:45,xxx,白条主动还款,0.05,银行卡,交易成功,不计收支,白条\n"
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data6), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data6), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -312,7 +313,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
} }
func TestJDComFinanceCsvFileImporterParseImportedData_ParseDescription(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -326,7 +327,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseDescription(t *testin
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,,0.12,银行卡,交易成功,支出\n" "2025-09-01 01:23:45,xxx,,0.12,银行卡,交易成功,支出\n"
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -338,7 +339,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseDescription(t *testin
"\n" + "\n" +
"交易时间,商户名称,交易说明,交易说明,金额,收/付款方式,交易状态,收/支,备注\n" + "交易时间,商户名称,交易说明,交易说明,金额,收/付款方式,交易状态,收/支,备注\n" +
"2025-09-01 01:23:45,xxx,xxx,Test,0.12,银行卡,交易成功,支出,\"foo\"\"bar,\ntest\"\n" "2025-09-01 01:23:45,xxx,xxx,Test,0.12,银行卡,交易成功,支出,\"foo\"\"bar,\ntest\"\n"
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "foo\"bar,\ntest", allNewTransactions[0].Comment) assert.Equal(t, "foo\"bar,\ntest", allNewTransactions[0].Comment)
@@ -348,13 +349,13 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseDescription(t *testin
"\n" + "\n" +
"交易时间,商户名称,交易说明,交易说明,金额,收/付款方式,交易状态,收/支,备注\n" + "交易时间,商户名称,交易说明,交易说明,金额,收/付款方式,交易状态,收/支,备注\n" +
"2025-09-01 01:23:45,xxx,xxx,Test,0.12,银行卡,交易成功,支出,\n" "2025-09-01 01:23:45,xxx,xxx,Test,0.12,银行卡,交易成功,支出,\n"
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data3), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "Test", allNewTransactions[0].Comment) assert.Equal(t, "Test", allNewTransactions[0].Comment)
} }
func TestJDComFinanceCsvFileImporterParseImportedData_SkipUnknownStatusTransaction(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_SkipUnknownStatusTransaction(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -368,12 +369,12 @@ func TestJDComFinanceCsvFileImporterParseImportedData_SkipUnknownStatusTransacti
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,xxxx,支出\n" "2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,xxxx,支出\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestJDComFinanceCsvFileImporterParseImportedData_SkipUnknownMemoTransferTransaction(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_SkipUnknownMemoTransferTransaction(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -387,12 +388,12 @@ func TestJDComFinanceCsvFileImporterParseImportedData_SkipUnknownMemoTransferTra
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,不计收支\n" "2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,不计收支\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestJDComFinanceCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -402,15 +403,15 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingFileHeader(t *testi
data := "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" + data := "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n" "2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message) assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(""), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message) assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
} }
func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -425,7 +426,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
"\n" + "\n" +
"商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" + "商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"xxx,xxx,0.12,银行卡,交易成功,支出\n" "xxx,xxx,0.12,银行卡,交易成功,支出\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message) assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
// Missing Merchant Name Column // Missing Merchant Name Column
@@ -435,7 +436,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
"\n" + "\n" +
"交易时间,交易说明,金额,收/付款方式,交易状态,收/支\n" + "交易时间,交易说明,金额,收/付款方式,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,0.12,银行卡,交易成功,支出\n" "2025-09-01 01:23:45,xxx,0.12,银行卡,交易成功,支出\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Transaction Memo Column // Missing Transaction Memo Column
@@ -445,7 +446,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
"\n" + "\n" +
"交易时间,商户名称,金额,收/付款方式,交易状态,收/支\n" + "交易时间,商户名称,金额,收/付款方式,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,0.12,银行卡,交易成功,支出\n" "2025-09-01 01:23:45,xxx,0.12,银行卡,交易成功,支出\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data3), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Amount Column // Missing Amount Column
@@ -455,7 +456,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
"\n" + "\n" +
"交易时间,商户名称,交易说明,收/付款方式,交易状态,收/支\n" + "交易时间,商户名称,交易说明,收/付款方式,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,xxx,银行卡,交易成功,支出\n" "2025-09-01 01:23:45,xxx,xxx,银行卡,交易成功,支出\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data4), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Related Account Column // Missing Related Account Column
@@ -465,7 +466,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,交易状态,收/支\n" + "交易时间,商户名称,交易说明,金额,交易状态,收/支\n" +
"2025-09-01 01:23:45,xxx,xxx,0.12,交易成功,支出\n" "2025-09-01 01:23:45,xxx,xxx,0.12,交易成功,支出\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data5), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Status Column // Missing Status Column
@@ -475,7 +476,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,收/支\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,收/支\n" +
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,支出\n" "2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,支出\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data6), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data6), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Type Column // Missing Type Column
@@ -485,12 +486,12 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态\n" + "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态\n" +
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功\n" "2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data7), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data7), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
} }
func TestJDComFinanceCsvFileImporterParseImportedData_NoTransactionData(t *testing.T) { func TestJDComFinanceCsvFileImporterParseImportedData_NoTransactionData(t *testing.T) {
converter := JDComFinanceTransactionDataCsvFileImporter importer := JDComFinanceTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -503,6 +504,6 @@ func TestJDComFinanceCsvFileImporterParseImportedData_NoTransactionData(t *testi
"日期区间:2025-01-01 至 2025-09-01\n" + "日期区间:2025-01-01 至 2025-09-01\n" +
"\n" + "\n" +
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
@@ -22,7 +22,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the mt940 file statement data // ParseImportedData returns the imported data by parsing the mt940 file statement data
func (c *mt940TransactionDataFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *mt940TransactionDataFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
mt940DataReader := createNewMT940FileReader(data) mt940DataReader := createNewMT940FileReader(data)
mt940Data, err := mt940DataReader.read(ctx) mt940Data, err := mt940DataReader.read(ctx)
@@ -38,5 +38,5 @@ func (c *mt940TransactionDataFileImporter) ParseImportedData(ctx core.Context, u
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(mt940TransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(mt940TransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -12,7 +13,7 @@ import (
) )
func TestMT940TransactionDataFileParseImportedData_MinimumValidData(t *testing.T) { func TestMT940TransactionDataFileParseImportedData_MinimumValidData(t *testing.T) {
converter := MT940TransactionDataFileImporter importer := MT940TransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -20,7 +21,7 @@ func TestMT940TransactionDataFileParseImportedData_MinimumValidData(t *testing.T
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(
`{1:F01TESTBANK123456789}{2:I940TESTBANK}{4: `{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:
:20:123456789 :20:123456789
:25:12345678 :25:12345678
@@ -31,7 +32,7 @@ func TestMT940TransactionDataFileParseImportedData_MinimumValidData(t *testing.T
:61:2506020603D234,56NTRFFOOBAR :61:2506020603D234,56NTRFFOOBAR
:86:Transaction 2 :86:Transaction 2
:62F:C250601CNY123,45 :62F:C250601CNY123,45
-}`), 0, nil, nil, nil, nil, nil) -}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -70,7 +71,7 @@ func TestMT940TransactionDataFileParseImportedData_MinimumValidData(t *testing.T
} }
func TestMT940TransactionDataFileParseImportedData_ParseTransactionValidAmountAndCurrency(t *testing.T) { func TestMT940TransactionDataFileParseImportedData_ParseTransactionValidAmountAndCurrency(t *testing.T) {
converter := MT940TransactionDataFileImporter importer := MT940TransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -78,7 +79,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionValidAmountAn
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`{1:F01TESTBANK123456789}{2:I940TESTBANK}{4: `{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:
:20:123456789 :20:123456789
:25:12345678 :25:12345678
@@ -91,7 +92,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionValidAmountAn
:61:250603C1,NTRFTEST :61:250603C1,NTRFTEST
:86:Transaction 3 :86:Transaction 3
:62F:C250601CNY123,45 :62F:C250601CNY123,45
-}`), 0, nil, nil, nil, nil, nil) -}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 3, len(allNewTransactions)) assert.Equal(t, 3, len(allNewTransactions))
@@ -101,7 +102,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionValidAmountAn
} }
func TestMT940TransactionDataFileParseImportedData_ParseTransactionInvalidAmountAndCurrency(t *testing.T) { func TestMT940TransactionDataFileParseImportedData_ParseTransactionInvalidAmountAndCurrency(t *testing.T) {
converter := MT940TransactionDataFileImporter importer := MT940TransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -109,7 +110,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionInvalidAmount
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`{1:F01TESTBANK123456789}{2:I940TESTBANK}{4: `{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:
:20:123456789 :20:123456789
:25:12345678 :25:12345678
@@ -117,10 +118,10 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionInvalidAmount
:60F:C250601CNY123,45 :60F:C250601CNY123,45
:61:2506010602C123 45NTRFTEST :61:2506010602C123 45NTRFTEST
:62F:C250601CNY123,45 :62F:C250601CNY123,45
-}`), 0, nil, nil, nil, nil, nil) -}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message) assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
`{1:F01TESTBANK123456789}{2:I940TESTBANK}{4: `{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:
:20:123456789 :20:123456789
:25:12345678 :25:12345678
@@ -128,12 +129,12 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionInvalidAmount
:60F:C250601CNY123,45 :60F:C250601CNY123,45
:61:2506010602C12.45NTRFTEST :61:2506010602C12.45NTRFTEST
:62F:C250601CNY123,45 :62F:C250601CNY123,45
-}`), 0, nil, nil, nil, nil, nil) -}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message) assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
} }
func TestMT940TransactionDataFileParseImportedData_ParseTransactionType(t *testing.T) { func TestMT940TransactionDataFileParseImportedData_ParseTransactionType(t *testing.T) {
converter := MT940TransactionDataFileImporter importer := MT940TransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -141,7 +142,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionType(t *testi
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`{1:F01TESTBANK123456789}{2:I940TESTBANK}{4: `{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:
:20:123456789 :20:123456789
:25:12345678 :25:12345678
@@ -156,7 +157,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionType(t *testi
:61:250604RD123,45NTRFTEST :61:250604RD123,45NTRFTEST
:86:Transaction 4 :86:Transaction 4
:62F:C250601CNY123,45 :62F:C250601CNY123,45
-}`), 0, nil, nil, nil, nil, nil) -}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 4, len(allNewTransactions)) assert.Equal(t, 4, len(allNewTransactions))
@@ -167,7 +168,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionType(t *testi
} }
func TestMT940TransactionDataFileParseImportedData_ParseDescription(t *testing.T) { func TestMT940TransactionDataFileParseImportedData_ParseDescription(t *testing.T) {
converter := MT940TransactionDataFileImporter importer := MT940TransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -175,7 +176,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseDescription(t *testing.T
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`{1:F01TESTBANK123456789}{2:I940TESTBANK}{4: `{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:
:20:123456789 :20:123456789
:25:12345678 :25:12345678
@@ -186,7 +187,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseDescription(t *testing.T
Part 2 Part 2
Part 3 Part 3
:62F:C250601CNY123,45 :62F:C250601CNY123,45
-}`), 0, nil, nil, nil, nil, nil) -}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -194,7 +195,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseDescription(t *testing.T
} }
func TestMT940TransactionDataFileParseImportedData_MissingRequiredField(t *testing.T) { func TestMT940TransactionDataFileParseImportedData_MissingRequiredField(t *testing.T) {
converter := MT940TransactionDataFileImporter importer := MT940TransactionDataFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -203,12 +204,12 @@ func TestMT940TransactionDataFileParseImportedData_MissingRequiredField(t *testi
} }
// Missing opening balance and closing balance // Missing opening balance and closing balance
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
`{1:F01TESTBANK123456789}{2:I940TESTBANK}{4: `{1:F01TESTBANK123456789}{2:I940TESTBANK}{4:
:20:123456789 :20:123456789
:28C:123/1 :28C:123/1
:61:250601C123,45NTRFTEST :61:250601C123,45NTRFTEST
:86:Transaction 1 :86:Transaction 1
-}`), 0, nil, nil, nil, nil, nil) -}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
@@ -23,7 +23,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the open financial exchange (ofx) file transaction data // ParseImportedData returns the imported data by parsing the open financial exchange (ofx) file transaction data
func (c *ofxTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *ofxTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
ofxDataReader, err := createNewOFXFileReader(ctx, data) ofxDataReader, err := createNewOFXFileReader(ctx, data)
if err != nil { if err != nil {
@@ -44,5 +44,5 @@ func (c *ofxTransactionDataImporter) ParseImportedData(ctx core.Context, user *m
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(ofxTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(ofxTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -12,7 +13,7 @@ import (
) )
func TestOFXTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -20,7 +21,7 @@ func TestOFXTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -76,7 +77,7 @@ func TestOFXTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
" </CCSTMTRS>\n"+ " </CCSTMTRS>\n"+
" </CCSTMTTRNRS>\n"+ " </CCSTMTTRNRS>\n"+
" </CREDITCARDMSGSRSV1>\n"+ " </CREDITCARDMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -160,7 +161,7 @@ func TestOFXTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
} }
func TestOFXTransactionDataFileParseImportedData_ParseAccountTo(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_ParseAccountTo(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -168,7 +169,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseAccountTo(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -210,7 +211,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseAccountTo(t *testing.T) {
" </CCSTMTRS>\n"+ " </CCSTMTRS>\n"+
" </CCSTMTTRNRS>\n"+ " </CCSTMTTRNRS>\n"+
" </CREDITCARDMSGSRSV1>\n"+ " </CREDITCARDMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -243,7 +244,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseAccountTo(t *testing.T) {
} }
func TestOFXTransactionDataFileParseImportedData_ParseValidTransactionTime(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_ParseValidTransactionTime(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -251,7 +252,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseValidTransactionTime(t *te
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -295,7 +296,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseValidTransactionTime(t *te
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -310,7 +311,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseValidTransactionTime(t *te
} }
func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -318,7 +319,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -337,10 +338,10 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -359,10 +360,10 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -381,10 +382,10 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -403,12 +404,12 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestOFXTransactionDataFileParseImportedData_ParseAmount_CommaAsDecimalPoint(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_ParseAmount_CommaAsDecimalPoint(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -416,7 +417,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseAmount_CommaAsDecimalPoint
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -435,7 +436,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseAmount_CommaAsDecimalPoint
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -444,7 +445,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseAmount_CommaAsDecimalPoint
} }
func TestOFXTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -452,7 +453,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -471,12 +472,12 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestOFXTransactionDataFileParseImportedData_ParseTransactionCurrency(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_ParseTransactionCurrency(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -484,7 +485,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseTransactionCurrency(t *tes
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -504,7 +505,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseTransactionCurrency(t *tes
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -512,7 +513,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseTransactionCurrency(t *tes
} }
func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -520,7 +521,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -541,13 +542,13 @@ func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "foo bar\t#test", allNewTransactions[0].Comment) assert.Equal(t, "foo bar\t#test", allNewTransactions[0].Comment)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -567,13 +568,13 @@ func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "Test", allNewTransactions[0].Comment) assert.Equal(t, "Test", allNewTransactions[0].Comment)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -595,7 +596,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -603,7 +604,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
} }
func TestOFXTransactionDataFileParseImportedData_MissingAccountFromNode(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_MissingAccountFromNode(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -612,7 +613,7 @@ func TestOFXTransactionDataFileParseImportedData_MissingAccountFromNode(t *testi
} }
// Missing Posted Date Node // Missing Posted Date Node
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -628,12 +629,12 @@ func TestOFXTransactionDataFileParseImportedData_MissingAccountFromNode(t *testi
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingAccountData.Message) assert.EqualError(t, err, errs.ErrMissingAccountData.Message)
} }
func TestOFXTransactionDataFileParseImportedData_MissingCurrencyNode(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_MissingCurrencyNode(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -642,7 +643,7 @@ func TestOFXTransactionDataFileParseImportedData_MissingCurrencyNode(t *testing.
} }
// Missing Default Currency Node // Missing Default Currency Node
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -660,12 +661,12 @@ func TestOFXTransactionDataFileParseImportedData_MissingCurrencyNode(t *testing.
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message) assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
} }
func TestOFXTransactionDataFileParseImportedData_MissingTransactionRequiredNode(t *testing.T) { func TestOFXTransactionDataFileParseImportedData_MissingTransactionRequiredNode(t *testing.T) {
converter := OFXTransactionDataImporter importer := OFXTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -674,7 +675,7 @@ func TestOFXTransactionDataFileParseImportedData_MissingTransactionRequiredNode(
} }
// Missing Posted Date Node // Missing Posted Date Node
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -692,11 +693,11 @@ func TestOFXTransactionDataFileParseImportedData_MissingTransactionRequiredNode(
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message) assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
// Missing Transaction Type Node // Missing Transaction Type Node
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -714,11 +715,11 @@ func TestOFXTransactionDataFileParseImportedData_MissingTransactionRequiredNode(
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
// Missing Amount Node // Missing Amount Node
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"<OFX>\n"+ "<OFX>\n"+
" <BANKMSGSRSV1>\n"+ " <BANKMSGSRSV1>\n"+
" <STMTTRNRS>\n"+ " <STMTTRNRS>\n"+
@@ -736,6 +737,6 @@ func TestOFXTransactionDataFileParseImportedData_MissingTransactionRequiredNode(
" </STMTRS>\n"+ " </STMTRS>\n"+
" </STMTTRNRS>\n"+ " </STMTTRNRS>\n"+
" </BANKMSGSRSV1>\n"+ " </BANKMSGSRSV1>\n"+
"</OFX>"), 0, nil, nil, nil, nil, nil) "</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
@@ -35,7 +35,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the quicken interchange format (qif) transaction data // ParseImportedData returns the imported data by parsing the quicken interchange format (qif) transaction data
func (c *qifTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *qifTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
qifDataReader := createNewQifDataReader(data) qifDataReader := createNewQifDataReader(data)
qifData, err := qifDataReader.read(ctx) qifData, err := qifDataReader.read(ctx)
@@ -51,5 +51,5 @@ func (c *qifTransactionDataImporter) ParseImportedData(ctx core.Context, user *m
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(qifTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(qifTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -12,7 +13,7 @@ import (
) )
func TestQIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -20,7 +21,7 @@ func TestQIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T123.45\n"+ "T123.45\n"+
@@ -42,7 +43,7 @@ func TestQIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
"D2024-09-05\n"+ "D2024-09-05\n"+
"T0.06\n"+ "T0.06\n"+
"L[Test Account2]\n"+ "L[Test Account2]\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -113,7 +114,7 @@ func TestQIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
} }
func TestQIFTransactionDataFileParseImportedData_ParseYearMonthDayDateFormatTime(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseYearMonthDayDateFormatTime(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -121,7 +122,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseYearMonthDayDateFormatTime
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123.45\n"+ "T-123.45\n"+
@@ -137,7 +138,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseYearMonthDayDateFormatTime
"^\n"+ "^\n"+
"D2024'9.5\n"+ "D2024'9.5\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -151,7 +152,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseYearMonthDayDateFormatTime
} }
func TestQIFTransactionDataFileParseImportedData_ParseMonthDayYearDateFormatTime(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseMonthDayYearDateFormatTime(t *testing.T) {
converter := QifMonthDayYearTransactionDataImporter importer := QifMonthDayYearTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -159,7 +160,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseMonthDayYearDateFormatTime
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D09-01-2024\n"+ "D09-01-2024\n"+
"T-123.45\n"+ "T-123.45\n"+
@@ -175,7 +176,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseMonthDayYearDateFormatTime
"^\n"+ "^\n"+
"D9.5'2024\n"+ "D9.5'2024\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -189,7 +190,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseMonthDayYearDateFormatTime
} }
func TestQIFTransactionDataFileParseImportedData_ParseDayYearMonthDateFormatTime(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseDayYearMonthDateFormatTime(t *testing.T) {
converter := QifDayMonthYearTransactionDataImporter importer := QifDayMonthYearTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -197,7 +198,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseDayYearMonthDateFormatTime
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D01-09-2024\n"+ "D01-09-2024\n"+
"T-123.45\n"+ "T-123.45\n"+
@@ -213,7 +214,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseDayYearMonthDateFormatTime
"^\n"+ "^\n"+
"D5'9.2024\n"+ "D5'9.2024\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -227,7 +228,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseDayYearMonthDateFormatTime
} }
func TestQIFTransactionDataFileParseImportedData_ParseShortYearMonthDayDateFormatTime(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseShortYearMonthDayDateFormatTime(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -235,7 +236,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseShortYearMonthDayDateForma
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D24-09-01\n"+ "D24-09-01\n"+
"T-123.45\n"+ "T-123.45\n"+
@@ -251,7 +252,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseShortYearMonthDayDateForma
"^\n"+ "^\n"+
"D24'9.5\n"+ "D24'9.5\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -265,7 +266,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseShortYearMonthDayDateForma
} }
func TestQIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -273,16 +274,16 @@ func TestQIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024 09 01\n"+ "D2024 09 01\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestQIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparator(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparator(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -290,11 +291,11 @@ func TestQIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparat
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123,456.78\n"+ "T-123,456.78\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
@@ -304,7 +305,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparat
} }
func TestQIFTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -312,16 +313,16 @@ func TestQIFTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123 45\n"+ "T-123 45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -329,11 +330,11 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Cash\n"+ "!Type:Cash\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -342,11 +343,11 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T)
assert.Equal(t, int64(1725148800), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148800), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
assert.Equal(t, int64(12345), allNewTransactions[0].Amount) assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!Type:CCard\n"+ "!Type:CCard\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -355,11 +356,11 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T)
assert.Equal(t, int64(1725148800), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148800), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
assert.Equal(t, int64(12345), allNewTransactions[0].Amount) assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!Type:Oth A\n"+ "!Type:Oth A\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -368,11 +369,11 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T)
assert.Equal(t, int64(1725148800), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime)) assert.Equal(t, int64(1725148800), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
assert.Equal(t, int64(12345), allNewTransactions[0].Amount) assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!Type:Oth L\n"+ "!Type:Oth L\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -383,7 +384,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T)
} }
func TestQIFTransactionDataFileParseImportedData_ParseAccount(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseAccount(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -391,14 +392,14 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccount(t *testing.T) {
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Account\n"+ "!Account\n"+
"NTest Account\n"+ "NTest Account\n"+
"^\n"+ "^\n"+
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -412,7 +413,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccount(t *testing.T) {
} }
func TestQIFTransactionDataFileParseImportedData_ParseAmountWithLeadingPlusSign(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseAmountWithLeadingPlusSign(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -420,11 +421,11 @@ func TestQIFTransactionDataFileParseImportedData_ParseAmountWithLeadingPlusSign(
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T+123.45\n"+ "T+123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -432,7 +433,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAmountWithLeadingPlusSign(
} }
func TestQIFTransactionDataFileParseImportedData_ParseSubCategory(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseSubCategory(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -440,12 +441,12 @@ func TestQIFTransactionDataFileParseImportedData_ParseSubCategory(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, allNewSubExpenseCategories, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, allNewSubExpenseCategories, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123.45\n"+ "T-123.45\n"+
"LTest Category:Sub Category\n"+ "LTest Category:Sub Category\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -458,7 +459,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseSubCategory(t *testing.T)
} }
func TestQIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -466,7 +467,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
DefaultCurrency: "CNY", DefaultCurrency: "CNY",
} }
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"T-123.45\n"+ "T-123.45\n"+
@@ -476,7 +477,24 @@ func TestQIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
"D2024-09-02\n"+ "D2024-09-02\n"+
"T-234.56\n"+ "T-234.56\n"+
"PTest2\n"+ "PTest2\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err)
assert.Equal(t, 2, len(allNewTransactions))
assert.Equal(t, "foo bar\t#test", allNewTransactions[0].Comment)
assert.Equal(t, "", allNewTransactions[1].Comment)
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+
"D2024-09-01\n"+
"T-123.45\n"+
"PTest\n"+
"Mfoo bar\t#test\n"+
"^\n"+
"D2024-09-02\n"+
"T-234.56\n"+
"PTest2\n"+
"^\n"), 0, converter.DefaultImporterOptions.WithPayeeAsDescription(), nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, len(allNewTransactions)) assert.Equal(t, 2, len(allNewTransactions))
@@ -484,8 +502,41 @@ func TestQIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
assert.Equal(t, "Test2", allNewTransactions[1].Comment) assert.Equal(t, "Test2", allNewTransactions[1].Comment)
} }
func TestQIFTransactionDataFileParseImportedData_WithAdditionalOptions(t *testing.T) {
importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext()
user := &models.User{
Uid: 1234567890,
DefaultCurrency: "CNY",
}
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+
"D2024-09-01\n"+
"T-123.45\n"+
"PTest2\n"+
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, 0, len(allNewTransactions[0].OriginalTagNames))
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+
"D2024-09-01\n"+
"T-123.45\n"+
"PTest2\n"+
"^\n"), 0, converter.DefaultImporterOptions.WithPayeeAsTag(), nil, nil, nil, nil, nil)
assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, 1, len(allNewTransactions[0].OriginalTagNames))
assert.Equal(t, "Test2", allNewTransactions[0].OriginalTagNames[0])
}
func TestQIFTransactionDataFileParseImportedData_MissingRequiredFields(t *testing.T) { func TestQIFTransactionDataFileParseImportedData_MissingRequiredFields(t *testing.T) {
converter := QifYearMonthDayTransactionDataImporter importer := QifYearMonthDayTransactionDataImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -494,16 +545,16 @@ func TestQIFTransactionDataFileParseImportedData_MissingRequiredFields(t *testin
} }
// Missing Time Field // Missing Time Field
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"T-123.45\n"+ "T-123.45\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message) assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
// Missing Amount Field // Missing Amount Field
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte( _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
"!Type:Bank\n"+ "!Type:Bank\n"+
"D2024-09-01\n"+ "D2024-09-01\n"+
"^\n"), 0, nil, nil, nil, nil, nil) "^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
@@ -22,6 +22,7 @@ var qifTransactionSupportedColumns = map[datatable.TransactionDataTableColumn]bo
datatable.TRANSACTION_DATA_TABLE_AMOUNT: true, datatable.TRANSACTION_DATA_TABLE_AMOUNT: true,
datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME: true, datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME: true,
datatable.TRANSACTION_DATA_TABLE_DESCRIPTION: true, datatable.TRANSACTION_DATA_TABLE_DESCRIPTION: true,
datatable.TRANSACTION_DATA_TABLE_PAYEE: true,
} }
// qifDateFormatType represents the quicken interchange format (qif) date format type // qifDateFormatType represents the quicken interchange format (qif) date format type
@@ -184,8 +185,10 @@ func (t *qifTransactionDataRowIterator) parseTransaction(ctx core.Context, user
if qifTransaction.Memo != "" { if qifTransaction.Memo != "" {
data[datatable.TRANSACTION_DATA_TABLE_DESCRIPTION] = qifTransaction.Memo data[datatable.TRANSACTION_DATA_TABLE_DESCRIPTION] = qifTransaction.Memo
} else if qifTransaction.Payee != "" && qifTransaction.Payee != qifOpeningBalancePayeeText { }
data[datatable.TRANSACTION_DATA_TABLE_DESCRIPTION] = qifTransaction.Payee
if qifTransaction.Payee != "" && qifTransaction.Payee != qifOpeningBalancePayeeText {
data[datatable.TRANSACTION_DATA_TABLE_PAYEE] = qifTransaction.Payee
} }
return data, nil return data, nil
@@ -27,7 +27,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the wechat pay transaction csv data // ParseImportedData returns the imported data by parsing the wechat pay transaction csv data
func (c *wechatPayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *wechatPayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
fallback := unicode.UTF8.NewDecoder() fallback := unicode.UTF8.NewDecoder()
reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback)) reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback))
@@ -58,5 +58,5 @@ func (c *wechatPayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Con
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, wechatPayTransactionSupportedColumns, transactionRowParser) transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, wechatPayTransactionSupportedColumns, transactionRowParser)
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(wechatPayTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(wechatPayTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
@@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
@@ -13,7 +14,7 @@ import (
) )
func TestWeChatPayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -31,7 +32,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T
"2024-09-01 12:34:56,商户消费,支出,¥123.45,支付成功\n" + "2024-09-01 12:34:56,商户消费,支出,¥123.45,支付成功\n" +
"2024-09-01 23:59:59,零钱充值,/,¥0.05,充值完成\n" + "2024-09-01 23:59:59,零钱充值,/,¥0.05,充值完成\n" +
"2024-09-02 23:59:59,零钱提现,/,¥0.03,提现已到账\n" "2024-09-02 23:59:59,零钱提现,/,¥0.03,提现已到账\n"
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 4, len(allNewTransactions)) assert.Equal(t, 4, len(allNewTransactions))
@@ -93,7 +94,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T
} }
func TestWeChatPayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -108,7 +109,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseRefundTransaction(t *tes
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元),当前状态\n" + "交易时间,交易类型,收/支,金额(元),当前状态\n" +
"2024-09-01 01:23:45,xxx-退款,收入,¥0.12,已全额退款\n" "2024-09-01 01:23:45,xxx-退款,收入,¥0.12,已全额退款\n"
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid) assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
@@ -120,7 +121,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseRefundTransaction(t *tes
} }
func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -135,7 +136,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元),当前状态\n" + "交易时间,交易类型,收/支,金额(元),当前状态\n" +
"2024-09-01T01:23:45,二维码收款,收入,¥0.12,已收钱\n" "2024-09-01T01:23:45,二维码收款,收入,¥0.12,已收钱\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
data2 := "微信支付账单明细,,,,\n" + data2 := "微信支付账单明细,,,,\n" +
@@ -145,12 +146,12 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元),当前状态\n" + "交易时间,交易类型,收/支,金额(元),当前状态\n" +
"09/01/2024 12:34:56,二维码收款,收入,¥0.12,已收钱\n" "09/01/2024 12:34:56,二维码收款,收入,¥0.12,已收钱\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message) assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
} }
func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -165,12 +166,12 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元),当前状态\n" + "交易时间,交易类型,收/支,金额(元),当前状态\n" +
"2024-09-01T01:23:45,xxx,,¥0.12,支付成功\n" "2024-09-01T01:23:45,xxx,,¥0.12,支付成功\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidAmount(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidAmount(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -185,12 +186,12 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidAmount(t *testing
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元),当前状态\n" + "交易时间,交易类型,收/支,金额(元),当前状态\n" +
"2024-09-01 01:23:45,二维码收款,收入,¥,已收钱\n" "2024-09-01 01:23:45,二维码收款,收入,¥,已收钱\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrAmountInvalid.Message) assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
} }
func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -206,7 +207,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元),支付方式,当前状态\n" + "交易时间,交易类型,收/支,金额(元),支付方式,当前状态\n" +
"2024-09-01 01:23:45,二维码收款,收入,¥0.12,/,已收钱\n" "2024-09-01 01:23:45,二维码收款,收入,¥0.12,/,已收钱\n"
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -222,7 +223,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
"2024-09-01 01:23:45,xxx-退款,收入,¥0.12,test,已全额退款\n" "2024-09-01 01:23:45,xxx-退款,收入,¥0.12,test,已全额退款\n"
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -238,7 +239,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
"2024-09-01 23:59:59,零钱充值,/,¥0.05,test,充值完成\n" "2024-09-01 23:59:59,零钱充值,/,¥0.05,test,充值完成\n"
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data3), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -255,7 +256,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
"2024-09-02 23:59:59,零钱提现,/,¥0.03,test,提现已到账\n" "2024-09-02 23:59:59,零钱提现,/,¥0.03,test,提现已到账\n"
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data4), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -272,7 +273,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
"2024-09-03 23:59:59,信用卡还款,/,¥0.01,零钱,支付成功\n" "2024-09-03 23:59:59,信用卡还款,/,¥0.01,零钱,支付成功\n"
assert.Nil(t, err) assert.Nil(t, err)
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data5), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -281,7 +282,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
} }
func TestWeChatPayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -296,7 +297,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseDescription(t *testing.T
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元),当前状态,备注\n" + "交易时间,交易类型,收/支,金额(元),当前状态,备注\n" +
"2024-09-01 01:23:45,二维码收款,收入,¥0.12,已收钱,\"/\"\n" "2024-09-01 01:23:45,二维码收款,收入,¥0.12,已收钱,\"/\"\n"
allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
@@ -309,7 +310,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseDescription(t *testing.T
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,商品,收/支,金额(元),当前状态,备注\n" + "交易时间,交易类型,商品,收/支,金额(元),当前状态,备注\n" +
"2024-09-01 01:23:45,二维码收款,Test,收入,¥0.12,已收钱,\"foo\"\"bar,\ntest\"\n" "2024-09-01 01:23:45,二维码收款,Test,收入,¥0.12,已收钱,\"foo\"\"bar,\ntest\"\n"
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "foo\"bar,\ntest", allNewTransactions[0].Comment) assert.Equal(t, "foo\"bar,\ntest", allNewTransactions[0].Comment)
@@ -320,13 +321,13 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseDescription(t *testing.T
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,商品,收/支,金额(元),当前状态,备注\n" + "交易时间,交易类型,商品,收/支,金额(元),当前状态,备注\n" +
"2024-09-01 01:23:45,二维码收款,Test,收入,¥0.12,已收钱,\"\"\n" "2024-09-01 01:23:45,二维码收款,Test,收入,¥0.12,已收钱,\"\"\n"
allNewTransactions, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data3), 0, nil, nil, nil, nil, nil) allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.Equal(t, 1, len(allNewTransactions)) assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "Test", allNewTransactions[0].Comment) assert.Equal(t, "Test", allNewTransactions[0].Comment)
} }
func TestWeChatPayCsvFileImporterParseImportedData_SkipUnknownTransferTransaction(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_SkipUnknownTransferTransaction(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -341,12 +342,12 @@ func TestWeChatPayCsvFileImporterParseImportedData_SkipUnknownTransferTransactio
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元),当前状态\n" + "交易时间,交易类型,收/支,金额(元),当前状态\n" +
"2024-09-01 23:59:59,/,/,¥0.05,充值完成\n" "2024-09-01 23:59:59,/,/,¥0.05,充值完成\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
func TestWeChatPayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -356,15 +357,15 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.
data := "交易时间,交易类型,收/支,金额(元),当前状态\n" + data := "交易时间,交易类型,收/支,金额(元),当前状态\n" +
"2024-09-01 01:23:45,二维码收款,收入,¥0.12,已收钱\n" "2024-09-01 01:23:45,二维码收款,收入,¥0.12,已收钱\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message) assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(""), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message) assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
} }
func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -380,7 +381,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易类型,收/支,金额(元),当前状态\n" + "交易类型,收/支,金额(元),当前状态\n" +
"二维码收款,收入,¥0.12,已收钱\n" "二维码收款,收入,¥0.12,已收钱\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Category Column // Missing Category Column
@@ -391,7 +392,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,收/支,金额(元),当前状态\n" + "交易时间,收/支,金额(元),当前状态\n" +
"2024-09-01 01:23:45,收入,¥0.12,已收钱\n" "2024-09-01 01:23:45,收入,¥0.12,已收钱\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Type Column // Missing Type Column
@@ -402,7 +403,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,金额(元),当前状态\n" + "交易时间,交易类型,金额(元),当前状态\n" +
"2024-09-01 01:23:45,二维码收款,¥0.12,已收钱\n" "2024-09-01 01:23:45,二维码收款,¥0.12,已收钱\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data3), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Amount Column // Missing Amount Column
@@ -413,7 +414,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,当前状态\n" + "交易时间,交易类型,收/支,当前状态\n" +
"2024-09-01 01:23:45,二维码收款,收入,已收钱\n" "2024-09-01 01:23:45,二维码收款,收入,已收钱\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data4), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Status Column // Missing Status Column
@@ -424,12 +425,12 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元)\n" + "交易时间,交易类型,收/支,金额(元)\n" +
"2024-09-01 01:23:45,二维码收款,收入,¥0.12\n" "2024-09-01 01:23:45,二维码收款,收入,¥0.12\n"
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data5), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message) assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
} }
func TestWeChatPayCsvFileImporterParseImportedData_NoTransactionData(t *testing.T) { func TestWeChatPayCsvFileImporterParseImportedData_NoTransactionData(t *testing.T) {
converter := WeChatPayTransactionDataCsvFileImporter importer := WeChatPayTransactionDataCsvFileImporter
context := core.NewNullContext() context := core.NewNullContext()
user := &models.User{ user := &models.User{
@@ -443,6 +444,6 @@ func TestWeChatPayCsvFileImporterParseImportedData_NoTransactionData(t *testing.
",,,,\n" + ",,,,\n" +
"----------------------微信支付账单明细列表--------------------,,,,\n" + "----------------------微信支付账单明细列表--------------------,,,,\n" +
"交易时间,交易类型,收/支,金额(元),当前状态\n" "交易时间,交易类型,收/支,金额(元),当前状态\n"
_, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil) _, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message) assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
} }
@@ -21,7 +21,7 @@ var (
) )
// ParseImportedData returns the imported data by parsing the wechat pay transaction csv data // ParseImportedData returns the imported data by parsing the wechat pay transaction csv data
func (c *wechatPayTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { func (c *wechatPayTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
xlsxDataTable, err := excel.CreateNewExcelOOXMLFileBasicDataTable(data, false) xlsxDataTable, err := excel.CreateNewExcelOOXMLFileBasicDataTable(data, false)
if err != nil { if err != nil {
@@ -49,5 +49,5 @@ func (c *wechatPayTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Co
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, wechatPayTransactionSupportedColumns, transactionRowParser) transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, wechatPayTransactionSupportedColumns, transactionRowParser)
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(wechatPayTransactionTypeNameMapping) dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(wechatPayTransactionTypeNameMapping)
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
} }
+5 -1
View File
@@ -168,7 +168,11 @@ export const SUPPORTED_IMPORT_FILE_CATEGORY_AND_TYPES: ImportFileCategoryAndType
type: 'qif_dmy', type: 'qif_dmy',
name: 'Day-month-year format', name: 'Day-month-year format',
} }
] ],
supportedAdditionalOptions: {
payeeAsTag: false,
payeeAsDescription: true
}
}, },
{ {
type: 'iif', type: 'iif',
+5
View File
@@ -75,6 +75,11 @@ export interface NameNumeralValue {
readonly value: number; readonly value: number;
} }
export interface KeyAndName {
readonly key: string;
readonly name: string;
}
export interface TypeAndName { export interface TypeAndName {
readonly type: number; readonly type: number;
readonly name: string; readonly name: string;
+10
View File
@@ -68,6 +68,14 @@ export interface ImportFileCategoryAndTypes {
readonly fileTypes: ImportFileType[]; readonly fileTypes: ImportFileType[];
} }
export interface ImportFileTypeSupportedAdditionalOptions extends Record<string, boolean | undefined> {
readonly payeeAsTag?: boolean;
readonly payeeAsDescription?: boolean;
readonly memberAsTag?: boolean;
readonly projectAsTag?: boolean;
readonly merchantAsTag?: boolean;
}
export interface ImportFileType extends ImportFileTypeAndExtensions { export interface ImportFileType extends ImportFileTypeAndExtensions {
readonly type: string; readonly type: string;
readonly name: string; readonly name: string;
@@ -75,6 +83,7 @@ export interface ImportFileType extends ImportFileTypeAndExtensions {
readonly subTypes?: ImportFileTypeSubType[]; readonly subTypes?: ImportFileTypeSubType[];
readonly supportedEncodings?: string[]; readonly supportedEncodings?: string[];
readonly dataFromTextbox?: boolean; readonly dataFromTextbox?: boolean;
readonly supportedAdditionalOptions?: ImportFileTypeSupportedAdditionalOptions;
readonly document?: { readonly document?: {
readonly supportMultiLanguages: boolean | string; readonly supportMultiLanguages: boolean | string;
readonly anchor: string; readonly anchor: string;
@@ -99,6 +108,7 @@ export interface LocalizedImportFileType extends ImportFileTypeAndExtensions {
readonly subTypes?: LocalizedImportFileTypeSubType[]; readonly subTypes?: LocalizedImportFileTypeSubType[];
readonly supportedEncodings?: LocalizedImportFileTypeSupportedEncodings[]; readonly supportedEncodings?: LocalizedImportFileTypeSupportedEncodings[];
readonly dataFromTextbox?: boolean; readonly dataFromTextbox?: boolean;
readonly supportedAdditionalOptions?: ImportFileTypeSupportedAdditionalOptions;
readonly document?: LocalizedImportFileDocument; readonly document?: LocalizedImportFileDocument;
} }
+12 -2
View File
@@ -8,6 +8,9 @@ import type {
import type { import type {
VersionInfo VersionInfo
} from '@/core/version.ts'; } from '@/core/version.ts';
import type {
ImportFileTypeSupportedAdditionalOptions
} from '@/core/file.ts';
import { import {
TransactionType TransactionType
} from '@/core/transaction.ts'; } from '@/core/transaction.ts';
@@ -160,7 +163,8 @@ import {
import { import {
isDefined, isDefined,
isBoolean isBoolean,
objectFieldWithValueToArrayItem
} from './common.ts'; } from './common.ts';
import { import {
getGoogleMapAPIKey, getGoogleMapAPIKey,
@@ -588,11 +592,16 @@ export default {
timeout: DEFAULT_UPLOAD_API_TIMEOUT timeout: DEFAULT_UPLOAD_API_TIMEOUT
} as ApiRequestConfig); } as ApiRequestConfig);
}, },
parseImportTransaction: ({ fileType, fileEncoding, importFile, columnMapping, transactionTypeMapping, hasHeaderLine, timeFormat, timezoneFormat, amountDecimalSeparator, amountDigitGroupingSymbol, geoSeparator, geoOrder, tagSeparator }: { fileType: string, fileEncoding?: string, importFile: File, columnMapping?: Record<number, number>, transactionTypeMapping?: Record<string, TransactionType>, hasHeaderLine?: boolean, timeFormat?: string, timezoneFormat?: string, amountDecimalSeparator?: string, amountDigitGroupingSymbol?: string, geoSeparator?: string, geoOrder?: string, tagSeparator?: string }): ApiResponsePromise<ImportTransactionResponsePageWrapper> => { parseImportTransaction: ({ fileType, additionalOptions, fileEncoding, importFile, columnMapping, transactionTypeMapping, hasHeaderLine, timeFormat, timezoneFormat, amountDecimalSeparator, amountDigitGroupingSymbol, geoSeparator, geoOrder, tagSeparator }: { fileType: string, additionalOptions?: ImportFileTypeSupportedAdditionalOptions, fileEncoding?: string, importFile: File, columnMapping?: Record<number, number>, transactionTypeMapping?: Record<string, TransactionType>, hasHeaderLine?: boolean, timeFormat?: string, timezoneFormat?: string, amountDecimalSeparator?: string, amountDigitGroupingSymbol?: string, geoSeparator?: string, geoOrder?: string, tagSeparator?: string }): ApiResponsePromise<ImportTransactionResponsePageWrapper> => {
let textualAdditionalOptions: string | undefined = undefined;
let textualColumnMapping: string | undefined = undefined; let textualColumnMapping: string | undefined = undefined;
let textualTransactionTypeMapping: string | undefined = undefined; let textualTransactionTypeMapping: string | undefined = undefined;
let textualHasHeaderLine: string | undefined = undefined; let textualHasHeaderLine: string | undefined = undefined;
if (additionalOptions) {
textualAdditionalOptions = objectFieldWithValueToArrayItem(additionalOptions, true).join(',');
}
if (columnMapping) { if (columnMapping) {
textualColumnMapping = JSON.stringify(columnMapping); textualColumnMapping = JSON.stringify(columnMapping);
} }
@@ -607,6 +616,7 @@ export default {
return axios.postForm<ApiResponse<ImportTransactionResponsePageWrapper>>('v1/transactions/parse_import.json', { return axios.postForm<ApiResponse<ImportTransactionResponsePageWrapper>>('v1/transactions/parse_import.json', {
fileType: fileType, fileType: fileType,
options: textualAdditionalOptions,
fileEncoding: fileEncoding, fileEncoding: fileEncoding,
file: importFile, file: importFile,
columnMapping: textualColumnMapping, columnMapping: textualColumnMapping,
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "Datendatei", "Data File": "Datendatei",
"Data to import": "Data to import", "Data to import": "Data to import",
"Please select a file to import": "Bitte wählen Sie eine Datei zum Importieren aus", "Please select a file to import": "Bitte wählen Sie eine Datei zum Importieren aus",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "Data File", "Data File": "Data File",
"Data to import": "Data to import", "Data to import": "Data to import",
"Please select a file to import": "Please select a file to import", "Please select a file to import": "Please select a file to import",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "Archivo de datos", "Data File": "Archivo de datos",
"Data to import": "Data to import", "Data to import": "Data to import",
"Please select a file to import": "Please select a file to import", "Please select a file to import": "Please select a file to import",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Script personnalisé", "Custom Script": "Script personnalisé",
"Execute Custom Script": "Exécuter le script personnalisé", "Execute Custom Script": "Exécuter le script personnalisé",
"Execute Custom Script to Parse Data": "Exécuter le script personnalisé pour analyser les données", "Execute Custom Script to Parse Data": "Exécuter le script personnalisé pour analyser les données",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "Fichier de données", "Data File": "Fichier de données",
"Data to import": "Données à importer", "Data to import": "Données à importer",
"Please select a file to import": "Veuillez sélectionner un fichier à importer", "Please select a file to import": "Veuillez sélectionner un fichier à importer",
+1
View File
@@ -1525,6 +1525,7 @@ export function useI18n() {
subTypes: subTypes.length ? subTypes : undefined, subTypes: subTypes.length ? subTypes : undefined,
supportedEncodings: supportedEncodings.length ? supportedEncodings : undefined, supportedEncodings: supportedEncodings.length ? supportedEncodings : undefined,
dataFromTextbox: fileType.dataFromTextbox, dataFromTextbox: fileType.dataFromTextbox,
supportedAdditionalOptions: fileType.supportedAdditionalOptions,
document: document document: document
}; };
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "File dati", "Data File": "File dati",
"Data to import": "Dati da importare", "Data to import": "Dati da importare",
"Please select a file to import": "Seleziona un file da importare", "Please select a file to import": "Seleziona un file da importare",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "データファイル", "Data File": "データファイル",
"Data to import": "インポートするデータ", "Data to import": "インポートするデータ",
"Please select a file to import": "インポートするファイルを選択してください", "Please select a file to import": "インポートするファイルを選択してください",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "사용자 정의 스크립트", "Custom Script": "사용자 정의 스크립트",
"Execute Custom Script": "사용자 정의 스크립트 실행", "Execute Custom Script": "사용자 정의 스크립트 실행",
"Execute Custom Script to Parse Data": "데이터 구문 분석을 위한 사용자 정의 스크립트 실행", "Execute Custom Script to Parse Data": "데이터 구문 분석을 위한 사용자 정의 스크립트 실행",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "데이터 파일", "Data File": "데이터 파일",
"Data to import": "가져올 데이터", "Data to import": "가져올 데이터",
"Please select a file to import": "가져올 파일을 선택하십시오", "Please select a file to import": "가져올 파일을 선택하십시오",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "Gegevensbestand", "Data File": "Gegevensbestand",
"Data to import": "Te importeren gegevens", "Data to import": "Te importeren gegevens",
"Please select a file to import": "Selecteer een bestand om te importeren", "Please select a file to import": "Selecteer een bestand om te importeren",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "Arquivo de Dados", "Data File": "Arquivo de Dados",
"Data to import": "Dados para importar", "Data to import": "Dados para importar",
"Please select a file to import": "Por favor, selecione um arquivo para importar", "Please select a file to import": "Por favor, selecione um arquivo para importar",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "Файл данных", "Data File": "Файл данных",
"Data to import": "Data to import", "Data to import": "Data to import",
"Please select a file to import": "Please select a file to import", "Please select a file to import": "Please select a file to import",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "สคริปต์กำหนดเอง", "Custom Script": "สคริปต์กำหนดเอง",
"Execute Custom Script": "เรียกใช้สคริปต์กำหนดเอง", "Execute Custom Script": "เรียกใช้สคริปต์กำหนดเอง",
"Execute Custom Script to Parse Data": "เรียกใช้สคริปต์กำหนดเองเพื่อแยกข้อมูล", "Execute Custom Script to Parse Data": "เรียกใช้สคริปต์กำหนดเองเพื่อแยกข้อมูล",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "ไฟล์ข้อมูล", "Data File": "ไฟล์ข้อมูล",
"Data to import": "ข้อมูลที่จะนำเข้า", "Data to import": "ข้อมูลที่จะนำเข้า",
"Please select a file to import": "กรุณาเลือกไฟล์เพื่อนำเข้า", "Please select a file to import": "กรุณาเลือกไฟล์เพื่อนำเข้า",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "Файл даних", "Data File": "Файл даних",
"Data to import": "Дані для імпорту", "Data to import": "Дані для імпорту",
"Please select a file to import": "Будь ласка, виберіть файл для імпорту", "Please select a file to import": "Будь ласка, виберіть файл для імпорту",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "Custom Script", "Custom Script": "Custom Script",
"Execute Custom Script": "Execute Custom Script", "Execute Custom Script": "Execute Custom Script",
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data", "Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
"Additional Options": "Additional Options",
"Parse Payee as Tag": "Parse Payee as Tag",
"Parse Payee as Description": "Parse Payee as Description",
"Data File": "Tệp dữ liệu", "Data File": "Tệp dữ liệu",
"Data to import": "Data to import", "Data to import": "Data to import",
"Please select a file to import": "Please select a file to import", "Please select a file to import": "Please select a file to import",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "自定义脚本", "Custom Script": "自定义脚本",
"Execute Custom Script": "执行自定义脚本", "Execute Custom Script": "执行自定义脚本",
"Execute Custom Script to Parse Data": "执行自定义脚本解析数据", "Execute Custom Script to Parse Data": "执行自定义脚本解析数据",
"Additional Options": "附加选项",
"Parse Payee as Tag": "将收款人解析为标签",
"Parse Payee as Description": "将收款人解析为描述",
"Data File": "数据文件", "Data File": "数据文件",
"Data to import": "要导入的数据", "Data to import": "要导入的数据",
"Please select a file to import": "请选择要导入的文件", "Please select a file to import": "请选择要导入的文件",
+3
View File
@@ -1885,6 +1885,9 @@
"Custom Script": "自訂腳本", "Custom Script": "自訂腳本",
"Execute Custom Script": "執行自訂腳本", "Execute Custom Script": "執行自訂腳本",
"Execute Custom Script to Parse Data": "執行自訂腳本來解析資料", "Execute Custom Script to Parse Data": "執行自訂腳本來解析資料",
"Additional Options": "附加選項",
"Parse Payee as Tag": "將收款人解析為標籤",
"Parse Payee as Description": "將收款人解析為描述",
"Data File": "資料檔案", "Data File": "資料檔案",
"Data to import": "要匯入的資料", "Data to import": "要匯入的資料",
"Please select a file to import": "請選擇要匯入的檔案", "Please select a file to import": "請選擇要匯入的檔案",
+3 -2
View File
@@ -12,6 +12,7 @@ import { useExchangeRatesStore } from './exchangeRates.ts';
import { type BeforeResolveFunction, itemAndIndex, entries, keys } from '@/core/base.ts'; import { type BeforeResolveFunction, itemAndIndex, entries, keys } from '@/core/base.ts';
import { type TextualYearMonth, DateRange } from '@/core/datetime.ts'; import { type TextualYearMonth, DateRange } from '@/core/datetime.ts';
import { CategoryType } from '@/core/category.ts'; import { CategoryType } from '@/core/category.ts';
import type { ImportFileTypeSupportedAdditionalOptions } from '@/core/file.ts';
import { TransactionType, TransactionTagFilterType } from '@/core/transaction.ts'; import { TransactionType, TransactionTagFilterType } from '@/core/transaction.ts';
import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts'; import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts';
import { import {
@@ -1264,9 +1265,9 @@ export const useTransactionsStore = defineStore('transactions', () => {
}); });
} }
function parseImportTransaction({ fileType, fileEncoding, importFile, columnMapping, transactionTypeMapping, hasHeaderLine, timeFormat, timezoneFormat, amountDecimalSeparator, amountDigitGroupingSymbol, geoSeparator, geoOrder, tagSeparator }: { fileType: string, fileEncoding?: string, importFile: File, columnMapping?: Record<number, number>, transactionTypeMapping?: Record<string, TransactionType>, hasHeaderLine?: boolean, timeFormat?: string, timezoneFormat?: string, amountDecimalSeparator?: string, amountDigitGroupingSymbol?: string, geoSeparator?: string, geoOrder?: string, tagSeparator?: string }): Promise<ImportTransactionResponsePageWrapper> { function parseImportTransaction({ fileType, additionalOptions, fileEncoding, importFile, columnMapping, transactionTypeMapping, hasHeaderLine, timeFormat, timezoneFormat, amountDecimalSeparator, amountDigitGroupingSymbol, geoSeparator, geoOrder, tagSeparator }: { fileType: string, additionalOptions?: ImportFileTypeSupportedAdditionalOptions, fileEncoding?: string, importFile: File, columnMapping?: Record<number, number>, transactionTypeMapping?: Record<string, TransactionType>, hasHeaderLine?: boolean, timeFormat?: string, timezoneFormat?: string, amountDecimalSeparator?: string, amountDigitGroupingSymbol?: string, geoSeparator?: string, geoOrder?: string, tagSeparator?: string }): Promise<ImportTransactionResponsePageWrapper> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
services.parseImportTransaction({ fileType, fileEncoding, importFile, columnMapping, transactionTypeMapping, hasHeaderLine, timeFormat, timezoneFormat, amountDecimalSeparator, amountDigitGroupingSymbol, geoSeparator, geoOrder, tagSeparator }).then(response => { services.parseImportTransaction({ fileType, additionalOptions, fileEncoding, importFile, columnMapping, transactionTypeMapping, hasHeaderLine, timeFormat, timezoneFormat, amountDecimalSeparator, amountDigitGroupingSymbol, geoSeparator, geoOrder, tagSeparator }).then(response => {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
@@ -145,6 +145,31 @@
/> />
</v-col> </v-col>
<v-col cols="12" md="12" v-if="supportedAdditionalOptions">
<v-select
:disabled="submitting"
:label="tt('Additional Options')"
:placeholder="tt('Additional Options')"
v-model="fileType"
v-model:menu="additionalOptionsMenuState"
>
<template #selection>
<span class="cursor-pointer">{{ displaySelectedAdditionalOptions }}</span>
</template>
<template #no-data>
<v-list class="py-0">
<template v-for="item in allSupportedAdditionalOptions">
<v-list-item :key="item.key"
:append-icon="importAdditionalOptions[item.key] ? mdiCheck : undefined"
@click="importAdditionalOptions[item.key] = !importAdditionalOptions[item.key]"
v-if="isDefined(supportedAdditionalOptions[item.key])">{{ tt(item.name) }}</v-list-item>
</template>
</v-list>
</template>
</v-select>
</v-col>
<v-col cols="12" md="12" v-if="!isImportDataFromTextbox"> <v-col cols="12" md="12" v-if="!isImportDataFromTextbox">
<v-text-field <v-text-field
readonly readonly
@@ -257,15 +282,20 @@ import { useTransactionsStore } from '@/stores/transaction.ts';
import { useOverviewStore } from '@/stores/overview.ts'; import { useOverviewStore } from '@/stores/overview.ts';
import { useStatisticsStore } from '@/stores/statistics.ts'; import { useStatisticsStore } from '@/stores/statistics.ts';
import { itemAndIndex } from '@/core/base.ts'; import { type KeyAndName, itemAndIndex } from '@/core/base.ts';
import { type NumeralSystem } from '@/core/numeral.ts'; import { type NumeralSystem } from '@/core/numeral.ts';
import { TransactionType } from '@/core/transaction.ts'; import { TransactionType } from '@/core/transaction.ts';
import { KnownFileType } from '@/core/file.ts'; import {
type ImportFileTypeSupportedAdditionalOptions,
import type { LocalizedImportFileCategoryAndTypes, LocalizedImportFileType, LocalizedImportFileTypeSubType, LocalizedImportFileTypeSupportedEncodings } from '@/core/file.ts'; type LocalizedImportFileCategoryAndTypes,
type LocalizedImportFileType,
type LocalizedImportFileTypeSubType,
type LocalizedImportFileTypeSupportedEncodings,
KnownFileType
} from '@/core/file.ts';
import { ImportTransaction } from '@/models/imported_transaction.ts'; import { ImportTransaction } from '@/models/imported_transaction.ts';
import { isNumber } from '@/lib/common.ts'; import { isDefined, isNumber } from '@/lib/common.ts';
import { findExtensionByType, isFileExtensionSupported } from '@/lib/file.ts'; import { findExtensionByType, isFileExtensionSupported } from '@/lib/file.ts';
import { generateRandomUUID } from '@/lib/misc.ts'; import { generateRandomUUID } from '@/lib/misc.ts';
import logger from '@/lib/logger.ts'; import logger from '@/lib/logger.ts';
@@ -297,6 +327,7 @@ defineProps<{
const { const {
tt, tt,
joinMultiText,
getCurrentNumeralSystemType, getCurrentNumeralSystemType,
getAllSupportedImportFileCagtegoryAndTypes, getAllSupportedImportFileCagtegoryAndTypes,
formatNumberToLocalizedNumerals formatNumberToLocalizedNumerals
@@ -316,7 +347,19 @@ const importTransactionExecuteCustomScriptTab = useTemplateRef<ImportTransaction
const importTransactionCheckDataTab = useTemplateRef<ImportTransactionCheckDataTabType>('importTransactionCheckDataTab'); const importTransactionCheckDataTab = useTemplateRef<ImportTransactionCheckDataTabType>('importTransactionCheckDataTab');
const fileInput = useTemplateRef<HTMLInputElement>('fileInput'); const fileInput = useTemplateRef<HTMLInputElement>('fileInput');
const allSupportedAdditionalOptions: KeyAndName[] = [
{
key: 'payeeAsTag',
name: 'Parse Payee as Tag'
},
{
key: 'payeeAsDescription',
name: 'Parse Payee as Description'
}
];
const showState = ref<boolean>(false); const showState = ref<boolean>(false);
const additionalOptionsMenuState = ref<boolean>(false);
const clientSessionId = ref<string>(''); const clientSessionId = ref<string>('');
const currentStep = ref<ImportTransactionDialogStep>('uploadFile'); const currentStep = ref<ImportTransactionDialogStep>('uploadFile');
const importProcess = ref<number>(0); const importProcess = ref<number>(0);
@@ -326,6 +369,7 @@ const fileEncoding = ref<string>('utf-8');
const processDSVMethod = ref<ImportDSVProcessMethod>(ImportDSVProcessMethod.ColumnMapping); const processDSVMethod = ref<ImportDSVProcessMethod>(ImportDSVProcessMethod.ColumnMapping);
const importFile = ref<File | null>(null); const importFile = ref<File | null>(null);
const importData = ref<string>(''); const importData = ref<string>('');
const importAdditionalOptions = ref<ImportFileTypeSupportedAdditionalOptions>({});
const parsedFileData = ref<string[][] | undefined>(undefined); const parsedFileData = ref<string[][] | undefined>(undefined);
const importTransactions = ref<ImportTransaction[] | undefined>(undefined); const importTransactions = ref<ImportTransaction[] | undefined>(undefined);
@@ -342,6 +386,7 @@ const allSupportedImportFileCategoryAndTypes = computed<LocalizedImportFileCateg
const allFileSubTypes = computed<LocalizedImportFileTypeSubType[] | undefined>(() => allSupportedImportFileTypesMap.value[fileType.value]?.subTypes); const allFileSubTypes = computed<LocalizedImportFileTypeSubType[] | undefined>(() => allSupportedImportFileTypesMap.value[fileType.value]?.subTypes);
const allSupportedEncodings = computed<LocalizedImportFileTypeSupportedEncodings[] | undefined>(() => allSupportedImportFileTypesMap.value[fileType.value]?.supportedEncodings); const allSupportedEncodings = computed<LocalizedImportFileTypeSupportedEncodings[] | undefined>(() => allSupportedImportFileTypesMap.value[fileType.value]?.supportedEncodings);
const isImportDataFromTextbox = computed<boolean>(() => allSupportedImportFileTypesMap.value[fileType.value]?.dataFromTextbox ?? false); const isImportDataFromTextbox = computed<boolean>(() => allSupportedImportFileTypesMap.value[fileType.value]?.dataFromTextbox ?? false);
const supportedAdditionalOptions = computed<ImportFileTypeSupportedAdditionalOptions | undefined>(() => allSupportedImportFileTypesMap.value[fileType.value]?.supportedAdditionalOptions);
const allSteps = computed<StepBarItem[]>(() => { const allSteps = computed<StepBarItem[]>(() => {
const steps: StepBarItem[] = [ const steps: StepBarItem[] = [
@@ -408,6 +453,26 @@ const supportedImportFileExtensions = computed<string | undefined>(() => {
return allSupportedImportFileTypesMap.value[fileType.value]?.extensions; return allSupportedImportFileTypesMap.value[fileType.value]?.extensions;
}); });
const displaySelectedAdditionalOptions = computed<string>(() => {
if (!supportedAdditionalOptions.value) {
return tt('None');
}
const selectedOptions: string[] = [];
for (const option of allSupportedAdditionalOptions) {
if (isDefined(supportedAdditionalOptions.value[option.key]) && importAdditionalOptions.value[option.key]) {
selectedOptions.push(tt(option.name));
}
}
if (selectedOptions.length < 1) {
return tt('None');
}
return joinMultiText(selectedOptions);
});
const exportFileGuideDocumentUrl = computed<string | undefined>(() => { const exportFileGuideDocumentUrl = computed<string | undefined>(() => {
const document = allSupportedImportFileTypesMap.value[fileType.value]?.document; const document = allSupportedImportFileTypesMap.value[fileType.value]?.document;
@@ -437,6 +502,7 @@ function open(): Promise<void> {
importProcess.value = 0; importProcess.value = 0;
importFile.value = null; importFile.value = null;
importData.value = ''; importData.value = '';
importAdditionalOptions.value = Object.assign({}, supportedAdditionalOptions.value ?? {});
parsedFileData.value = undefined; parsedFileData.value = undefined;
importTransactionDefineColumnTab.value?.reset(); importTransactionDefineColumnTab.value?.reset();
importTransactionExecuteCustomScriptTab.value?.reset(); importTransactionExecuteCustomScriptTab.value?.reset();
@@ -614,6 +680,7 @@ function parseData(): void {
transactionsStore.parseImportTransaction({ transactionsStore.parseImportTransaction({
fileType: type, fileType: type,
additionalOptions: importAdditionalOptions.value,
fileEncoding: encoding, fileEncoding: encoding,
importFile: uploadFile, importFile: uploadFile,
columnMapping: columnMapping, columnMapping: columnMapping,
@@ -773,6 +840,7 @@ watch(fileType, () => {
importFile.value = null; importFile.value = null;
parsedFileData.value = undefined; parsedFileData.value = undefined;
importAdditionalOptions.value = Object.assign({}, supportedAdditionalOptions.value ?? {});
importTransactions.value = undefined; importTransactions.value = undefined;
}); });