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 != "" {