diff --git a/pkg/converters/ofx/ofx_transaction_data_file_importer_test.go b/pkg/converters/ofx/ofx_transaction_data_file_importer_test.go index e92e4c2d..bc512e0f 100644 --- a/pkg/converters/ofx/ofx_transaction_data_file_importer_test.go +++ b/pkg/converters/ofx/ofx_transaction_data_file_importer_test.go @@ -42,9 +42,14 @@ func TestOFXTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) " "+ " "+ " XFER"+ - " 20240901235959.000[+8:CST]"+ + " 20240901225959.000[+8:CST]"+ " -1.00"+ " "+ + " "+ + " XFER"+ + " 20240901235959.000[+8:CST]"+ + " 2.00"+ + " "+ " "+ " "+ " "+ @@ -75,7 +80,7 @@ func TestOFXTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) assert.Nil(t, err) - assert.Equal(t, 5, len(allNewTransactions)) + assert.Equal(t, 6, len(allNewTransactions)) assert.Equal(t, 3, len(allNewAccounts)) assert.Equal(t, 1, len(allNewSubExpenseCategories)) assert.Equal(t, 1, len(allNewSubIncomeCategories)) @@ -100,28 +105,36 @@ func TestOFXTransactionDataFileParseImportedData_MinimumValidData(t *testing.T) assert.Equal(t, int64(1234567890), allNewTransactions[2].Uid) assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[2].Type) - assert.Equal(t, int64(1725206399), utils.GetUnixTimeFromTransactionTime(allNewTransactions[2].TransactionTime)) + assert.Equal(t, int64(1725202799), utils.GetUnixTimeFromTransactionTime(allNewTransactions[2].TransactionTime)) assert.Equal(t, int64(100), allNewTransactions[2].Amount) assert.Equal(t, "123", allNewTransactions[2].OriginalSourceAccountName) assert.Equal(t, "", allNewTransactions[2].OriginalDestinationAccountName) assert.Equal(t, "", allNewTransactions[2].OriginalCategoryName) assert.Equal(t, int64(1234567890), allNewTransactions[3].Uid) - assert.Equal(t, models.TRANSACTION_DB_TYPE_INCOME, allNewTransactions[3].Type) - assert.Equal(t, int64(1725211425), utils.GetUnixTimeFromTransactionTime(allNewTransactions[3].TransactionTime)) - assert.Equal(t, int64(123), allNewTransactions[3].Amount) - assert.Equal(t, "456", allNewTransactions[3].OriginalSourceAccountName) - assert.Equal(t, "USD", allNewTransactions[3].OriginalSourceAccountCurrency) + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[3].Type) + assert.Equal(t, int64(1725206399), utils.GetUnixTimeFromTransactionTime(allNewTransactions[3].TransactionTime)) + assert.Equal(t, int64(200), allNewTransactions[3].Amount) + assert.Equal(t, "", allNewTransactions[3].OriginalSourceAccountName) + assert.Equal(t, "123", allNewTransactions[3].OriginalDestinationAccountName) assert.Equal(t, "", allNewTransactions[3].OriginalCategoryName) assert.Equal(t, int64(1234567890), allNewTransactions[4].Uid) - assert.Equal(t, models.TRANSACTION_DB_TYPE_EXPENSE, allNewTransactions[4].Type) - assert.Equal(t, int64(1725251696), utils.GetUnixTimeFromTransactionTime(allNewTransactions[4].TransactionTime)) - assert.Equal(t, int64(1), allNewTransactions[4].Amount) + assert.Equal(t, models.TRANSACTION_DB_TYPE_INCOME, allNewTransactions[4].Type) + assert.Equal(t, int64(1725211425), utils.GetUnixTimeFromTransactionTime(allNewTransactions[4].TransactionTime)) + assert.Equal(t, int64(123), allNewTransactions[4].Amount) assert.Equal(t, "456", allNewTransactions[4].OriginalSourceAccountName) assert.Equal(t, "USD", allNewTransactions[4].OriginalSourceAccountCurrency) assert.Equal(t, "", allNewTransactions[4].OriginalCategoryName) + assert.Equal(t, int64(1234567890), allNewTransactions[5].Uid) + assert.Equal(t, models.TRANSACTION_DB_TYPE_EXPENSE, allNewTransactions[5].Type) + assert.Equal(t, int64(1725251696), utils.GetUnixTimeFromTransactionTime(allNewTransactions[5].TransactionTime)) + assert.Equal(t, int64(1), allNewTransactions[5].Amount) + assert.Equal(t, "456", allNewTransactions[5].OriginalSourceAccountName) + assert.Equal(t, "USD", allNewTransactions[5].OriginalSourceAccountCurrency) + assert.Equal(t, "", allNewTransactions[5].OriginalCategoryName) + assert.Equal(t, int64(1234567890), allNewAccounts[0].Uid) assert.Equal(t, "123", allNewAccounts[0].Name) assert.Equal(t, "CNY", allNewAccounts[0].Currency) diff --git a/pkg/converters/ofx/ofx_transaction_table.go b/pkg/converters/ofx/ofx_transaction_table.go index c8c6d744..b47dc975 100644 --- a/pkg/converters/ofx/ofx_transaction_table.go +++ b/pkg/converters/ofx/ofx_transaction_table.go @@ -130,38 +130,10 @@ func (t *ofxTransactionDataRowIterator) parseTransaction(ctx core.Context, user data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = datetime data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = timezone - if ofxTransaction.Amount == "" { - return nil, errs.ErrAmountInvalid - } - - amount, err := utils.ParseAmount(strings.ReplaceAll(ofxTransaction.Amount, ",", ".")) // ofx supports decimal point or comma to indicate the start of the fractional amount - - if err != nil { - return nil, errs.ErrAmountInvalid - } - if ofxTransaction.TransactionType == "" { return nil, errs.ErrTransactionTypeInvalid } - if transactionType, exists := ofxTransactionTypeMapping[ofxTransaction.TransactionType]; exists { - data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = utils.IntToString(int(transactionType)) - - if data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] == ofxTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] { - data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(amount) - } else { - data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount) - } - } else { - if amount >= 0 { - data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = ofxTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] - data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(amount) - } else { - data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = ofxTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE] - data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount) - } - } - if ofxTransaction.FromAccountId == "" { return nil, errs.ErrMissingAccountData } @@ -174,10 +146,45 @@ func (t *ofxTransactionDataRowIterator) parseTransaction(ctx core.Context, user data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY] = ofxTransaction.DefaultCurrency } - if data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] == ofxTransactionTypeNameMapping[models.TRANSACTION_TYPE_TRANSFER] { - data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = ofxTransaction.ToAccountId - data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_CURRENCY] = data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY] - data[datatable.TRANSACTION_DATA_TABLE_RELATED_AMOUNT] = data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] + if ofxTransaction.Amount == "" { + return nil, errs.ErrAmountInvalid + } + + amount, err := utils.ParseAmount(strings.ReplaceAll(ofxTransaction.Amount, ",", ".")) // ofx supports decimal point or comma to indicate the start of the fractional amount + + if err != nil { + return nil, errs.ErrAmountInvalid + } + + if transactionType, exists := ofxTransactionTypeMapping[ofxTransaction.TransactionType]; exists { // known transaction type + data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = utils.IntToString(int(transactionType)) + + if data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] == ofxTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] { // income + data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(amount) + } else if data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] == ofxTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE] { // expense + data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount) + } else { // transfer + if amount >= 0 { // transfer in + data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(amount) + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_CURRENCY] = data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY] + data[datatable.TRANSACTION_DATA_TABLE_RELATED_AMOUNT] = data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] + data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = "" + } else { // transfer out + data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount) + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = ofxTransaction.ToAccountId + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_CURRENCY] = data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY] + data[datatable.TRANSACTION_DATA_TABLE_RELATED_AMOUNT] = data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] + } + } + } else { // transaction type depends on signage of amount + if amount >= 0 { // income + data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = ofxTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] + data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(amount) + } else { // expense + data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = ofxTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE] + data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount) + } } if ofxTransaction.Memo != "" {