diff --git a/pkg/converters/feidee/feidee_mymoney_app_transaction_data_csv_file_importer.go b/pkg/converters/feidee/feidee_mymoney_app_transaction_data_csv_file_importer.go index fa02ca03..7caf5687 100644 --- a/pkg/converters/feidee/feidee_mymoney_app_transaction_data_csv_file_importer.go +++ b/pkg/converters/feidee/feidee_mymoney_app_transaction_data_csv_file_importer.go @@ -30,6 +30,7 @@ const feideeMymoneyAppTransactionDescriptionColumnName = "备注" const feideeMymoneyAppTransactionRelatedIdColumnName = "关联Id" const feideeMymoneyAppTransactionTypeModifyBalanceText = "余额变更" +const feideeMymoneyAppTransactionTypeModifyOutstandingBalanceText = "负债变更" const feideeMymoneyAppTransactionTypeIncomeText = "收入" const feideeMymoneyAppTransactionTypeExpenseText = "支出" const feideeMymoneyAppTransactionTypeTransferInText = "转入" @@ -190,9 +191,12 @@ func (c *feideeMymoneyAppTransactionDataCsvFileImporter) createNewFeideeMymoneyA transactionType := data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] - if transactionType == feideeMymoneyAppTransactionTypeModifyBalanceText || transactionType == feideeMymoneyAppTransactionTypeIncomeText || transactionType == feideeMymoneyAppTransactionTypeExpenseText { + if transactionType == feideeMymoneyAppTransactionTypeModifyBalanceText || transactionType == feideeMymoneyAppTransactionTypeModifyOutstandingBalanceText || + transactionType == feideeMymoneyAppTransactionTypeIncomeText || transactionType == feideeMymoneyAppTransactionTypeExpenseText { if transactionType == feideeMymoneyAppTransactionTypeModifyBalanceText { data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_MODIFY_BALANCE] + } else if transactionType == feideeMymoneyAppTransactionTypeModifyOutstandingBalanceText { + data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeModifyOutstandingBalanceName } else if transactionType == feideeMymoneyAppTransactionTypeIncomeText { data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] } else if transactionType == feideeMymoneyAppTransactionTypeExpenseText { diff --git a/pkg/converters/feidee/feidee_mymoney_app_transaction_data_csv_file_importer_test.go b/pkg/converters/feidee/feidee_mymoney_app_transaction_data_csv_file_importer_test.go index 6bc7c20e..b4b80233 100644 --- a/pkg/converters/feidee/feidee_mymoney_app_transaction_data_csv_file_importer_test.go +++ b/pkg/converters/feidee/feidee_mymoney_app_transaction_data_csv_file_importer_test.go @@ -109,6 +109,56 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MinimumValidData(t *testi assert.Equal(t, "Test Category3", allNewSubTransferCategories[0].Name) } +func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseOutstandingBalanceModification(t *testing.T) { + converter := FeideeMymoneyAppTransactionDataCsvFileImporter + context := core.NewNullContext() + + user := &models.User{ + Uid: 1234567890, + DefaultCurrency: "CNY", + } + + allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, _, _, err := converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ + "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\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) + + assert.Nil(t, err) + + assert.Equal(t, 2, len(allNewTransactions)) + assert.Equal(t, 2, len(allNewAccounts)) + assert.Equal(t, 1, len(allNewSubExpenseCategories)) + assert.Equal(t, 1, len(allNewSubIncomeCategories)) + + assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid) + assert.Equal(t, models.TRANSACTION_DB_TYPE_EXPENSE, allNewTransactions[0].Type) + assert.Equal(t, "2024-09-01 00:00:00", utils.FormatUnixTimeToLongDateTime(utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime), time.UTC)) + assert.Equal(t, int64(12345), allNewTransactions[0].Amount) + assert.Equal(t, "Test Account", allNewTransactions[0].OriginalSourceAccountName) + assert.Equal(t, "", allNewTransactions[0].OriginalCategoryName) + + assert.Equal(t, int64(1234567890), allNewTransactions[1].Uid) + assert.Equal(t, models.TRANSACTION_DB_TYPE_INCOME, allNewTransactions[1].Type) + assert.Equal(t, "2024-09-01 01:00:00", utils.FormatUnixTimeToLongDateTime(utils.GetUnixTimeFromTransactionTime(allNewTransactions[1].TransactionTime), time.UTC)) + assert.Equal(t, int64(12), allNewTransactions[1].Amount) + assert.Equal(t, "Test Account2", allNewTransactions[1].OriginalSourceAccountName) + assert.Equal(t, "", allNewTransactions[1].OriginalCategoryName) + + assert.Equal(t, int64(1234567890), allNewAccounts[0].Uid) + assert.Equal(t, "Test Account", allNewAccounts[0].Name) + assert.Equal(t, "CNY", allNewAccounts[0].Currency) + + assert.Equal(t, int64(1234567890), allNewAccounts[1].Uid) + assert.Equal(t, "Test Account2", allNewAccounts[1].Name) + assert.Equal(t, "CNY", allNewAccounts[1].Currency) + + assert.Equal(t, int64(1234567890), allNewSubExpenseCategories[0].Uid) + assert.Equal(t, "", allNewSubExpenseCategories[0].Name) + + assert.Equal(t, int64(1234567890), allNewSubIncomeCategories[0].Uid) + assert.Equal(t, "", allNewSubIncomeCategories[0].Name) +} + func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) { converter := FeideeMymoneyAppTransactionDataCsvFileImporter context := core.NewNullContext() @@ -238,6 +288,11 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidAmount(t *tes "\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), 0, nil, nil, nil, nil, nil) assert.EqualError(t, err, errs.ErrAmountInvalid.Message) + _, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ + "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ + "\"负债变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), 0, nil, nil, nil, nil, nil) + assert.EqualError(t, err, errs.ErrAmountInvalid.Message) + _, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+ "\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+ "\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123 45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+ diff --git a/pkg/converters/feidee/feidee_mymoney_elecloud_transaction_data_row_parser.go b/pkg/converters/feidee/feidee_mymoney_elecloud_transaction_data_row_parser.go index b48759c7..b29ca18e 100644 --- a/pkg/converters/feidee/feidee_mymoney_elecloud_transaction_data_row_parser.go +++ b/pkg/converters/feidee/feidee_mymoney_elecloud_transaction_data_row_parser.go @@ -10,13 +10,15 @@ import ( ) var FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_MODIFY_BALANCE_NAME = "余额变更" +var FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_OUTSTANDING_MODIFY_BALANCE_NAME = "负债变更" var FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_INCOME_NAME = "收入" var FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_EXPENSE_NAME = "支出" var feideeMymoneyElecloudTransactionTypeNameMapping = map[string]models.TransactionType{ - FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_MODIFY_BALANCE_NAME: models.TRANSACTION_TYPE_MODIFY_BALANCE, - FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_INCOME_NAME: models.TRANSACTION_TYPE_INCOME, - FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_EXPENSE_NAME: models.TRANSACTION_TYPE_EXPENSE, + FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_MODIFY_BALANCE_NAME: models.TRANSACTION_TYPE_MODIFY_BALANCE, + FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_OUTSTANDING_MODIFY_BALANCE_NAME: models.TRANSACTION_TYPE_MODIFY_BALANCE, + FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_INCOME_NAME: models.TRANSACTION_TYPE_INCOME, + FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_EXPENSE_NAME: models.TRANSACTION_TYPE_EXPENSE, "转账": models.TRANSACTION_TYPE_TRANSFER, "借入": models.TRANSACTION_TYPE_TRANSFER, "借出": models.TRANSACTION_TYPE_TRANSFER, @@ -60,6 +62,20 @@ func (p *feideeMymoneyElecloudTransactionDataRowParser) Parse(data map[datatable rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_EXPENSE_NAME rowData[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount) } + } else if rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] == FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_OUTSTANDING_MODIFY_BALANCE_NAME { + amount, err := utils.ParseAmount(rowData[datatable.TRANSACTION_DATA_TABLE_AMOUNT]) + + if err != nil { + return nil, false, errs.ErrAmountInvalid + } + + // outstanding balance modification transaction in feidee mymoney app is not the opening balance transaction, it can be added many times + if amount >= 0 { + rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_EXPENSE_NAME + } else { + rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = FEIDEE_MYMONEY_ELECLOUD_TRANSACTION_TYPE_INCOME_NAME + rowData[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount) + } } return rowData, true, nil diff --git a/pkg/converters/feidee/feidee_mymoney_transaction_data_row_parser.go b/pkg/converters/feidee/feidee_mymoney_transaction_data_row_parser.go index 9697c988..21d9e256 100644 --- a/pkg/converters/feidee/feidee_mymoney_transaction_data_row_parser.go +++ b/pkg/converters/feidee/feidee_mymoney_transaction_data_row_parser.go @@ -14,6 +14,8 @@ var feideeMymoneyTransactionTypeNameMapping = map[models.TransactionType]string{ models.TRANSACTION_TYPE_TRANSFER: "转账", } +var feideeMymoneyTransactionTypeModifyOutstandingBalanceName = "负债变更" + // feideeMymoneyTransactionDataRowParser defines the structure of feidee mymoney transaction data row parser type feideeMymoneyTransactionDataRowParser struct { } @@ -49,6 +51,20 @@ func (p *feideeMymoneyTransactionDataRowParser) Parse(data map[datatable.Transac rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE] rowData[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount) } + } else if rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] == feideeMymoneyTransactionTypeModifyOutstandingBalanceName { + amount, err := utils.ParseAmount(rowData[datatable.TRANSACTION_DATA_TABLE_AMOUNT]) + + if err != nil { + return nil, false, errs.ErrAmountInvalid + } + + // outstanding balance modification transaction in feidee mymoney app is not the opening balance transaction, it can be added many times + if amount >= 0 { + rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE] + } else { + rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] + rowData[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount) + } } return rowData, true, nil