diff --git a/pkg/converters/alipay/alipay_transaction_data_csv_file_importer_test.go b/pkg/converters/alipay/alipay_transaction_data_csv_file_importer_test.go index cb86551e..a9b0cb8f 100644 --- a/pkg/converters/alipay/alipay_transaction_data_csv_file_importer_test.go +++ b/pkg/converters/alipay/alipay_transaction_data_csv_file_importer_test.go @@ -102,6 +102,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin DefaultCurrency: "CNY", } + // refund data1, err := simplifiedchinese.GB18030.NewEncoder().String("支付宝交易记录明细查询\n" + "账号:[xxx@xxx.xxx]\n" + "起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" + @@ -121,6 +122,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin assert.Equal(t, "", allNewTransactions[0].OriginalSourceAccountName) assert.Equal(t, "", allNewTransactions[0].OriginalCategoryName) + // tax refund data2, err := simplifiedchinese.GB18030.NewEncoder().String("支付宝交易记录明细查询\n" + "账号:[xxx@xxx.xxx]\n" + "起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" + @@ -141,6 +143,46 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin assert.Equal(t, "", allNewTransactions[0].OriginalCategoryName) } +func TestAlipayCsvFileImporterParseImportedData_ParseInvestmentRefundTransaction(t *testing.T) { + converter := AlipayAppTransactionDataCsvFileImporter + context := core.NewNullContext() + + user := &models.User{ + Uid: 1234567890, + DefaultCurrency: "CNY", + } + + data1, err := simplifiedchinese.GB18030.NewEncoder().String("------------------------------------------------------------------------------------\n" + + "导出信息:\n" + + "姓名:xxx\n" + + "支付宝账户:xxx@xxx.xxx\n" + + "起始时间:[2024-01-01 00:00:00] 终止时间:[2024-09-01 23:59:59]\n" + + "导出交易类型:[全部]\n" + + "------------------------支付宝(中国)网络技术有限公司 电子客户回单------------------------\n" + + "交易时间,交易对方,商品说明,收/支,金额,收/付款方式,交易状态,\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") + + allNewTransactions, _, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) + assert.Nil(t, err) + + assert.Equal(t, 2, len(allNewTransactions)) + + assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid) + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[0].Type) + assert.Equal(t, "2024-09-01 01:00:00", utils.FormatUnixTimeToLongDateTime(utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime), time.UTC)) + assert.Equal(t, int64(1), allNewTransactions[0].Amount) + assert.Equal(t, "Test Account", allNewTransactions[0].OriginalSourceAccountName) + assert.Equal(t, "Test Account2", allNewTransactions[0].OriginalDestinationAccountName) + + assert.Equal(t, int64(1234567890), allNewTransactions[1].Uid) + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[1].Type) + assert.Equal(t, "2024-09-01 02:00:00", utils.FormatUnixTimeToLongDateTime(utils.GetUnixTimeFromTransactionTime(allNewTransactions[1].TransactionTime), time.UTC)) + assert.Equal(t, int64(1), allNewTransactions[1].Amount) + assert.Equal(t, "Test Account2", allNewTransactions[1].OriginalSourceAccountName) + assert.Equal(t, "Test Account", allNewTransactions[1].OriginalDestinationAccountName) +} + func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) { converter := AlipayWebTransactionDataCsvFileImporter context := core.NewNullContext() @@ -380,38 +422,110 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRelatedAccount(t *testing.T "起始时间:[2024-01-01 00:00:00] 终止时间:[2024-09-01 23:59:59]\n" + "导出交易类型:[全部]\n" + "------------------------支付宝(中国)网络技术有限公司 电子客户回单------------------------\n" + - "交易时间,商品说明,收/支,金额,收/付款方式,交易状态,\n" + - "2024-09-01 03:45:07,余额宝-单次转入,不计收支,0.01,Test Account,交易成功,\n" + - "2024-09-01 05:07:29,信用卡还款,不计收支,0.02,Test Account2,交易成功,\n") + "交易时间,交易对方,商品说明,收/支,金额,收/付款方式,交易状态,备注,\n" + + "2024-09-01 00:00:00,xxx,xxx-收益发放,不计收支,0.01,Test Account,交易成功,earning,\n" + + "2024-09-01 01:00:00,Test Account2,xxx-买入,不计收支,0.01,Test Account,交易成功,purchase investment,\n" + + "2024-09-01 02:00:00,Test Account2,xxx-卖出至xxx,不计收支,0.01,Test Account,交易成功,sell investment,\n" + + "2024-09-01 03:00:00,xxx,充值-普通充值,不计收支,0.01,Test Account,交易成功,transfer to alipay wallet,\n" + + "2024-09-01 04:00:00,Test Account3,提现-实时提现,不计收支,0.01,Test Account,交易成功,transfer from alipay wallet,\n" + + "2024-09-01 05:00:00,Test Account3,xxx-单次转入,不计收支,0.01,Test Account,交易成功,transfer in,\n" + + "2024-09-01 06:00:00,Test Account3,xxx-转出到银行卡,不计收支,0.01,Test Account,交易成功,transfer out,\n" + + "2024-09-01 07:00:00,Test Account3,转账xxx,不计收支,0.01,Test Account,交易成功,transfer,\n" + + "2024-09-01 08:00:00,Test Account4,信用卡还款,不计收支,0.01,Test Account,还款成功,repayment,\n") assert.Nil(t, err) allNewTransactions, allNewAccounts, _, _, _, _, err := converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil) assert.Nil(t, err) - assert.Equal(t, 2, len(allNewTransactions)) - assert.Equal(t, 3, len(allNewAccounts)) + assert.Equal(t, 9, len(allNewTransactions)) + assert.Equal(t, 6, len(allNewAccounts)) + assert.Equal(t, models.TRANSACTION_DB_TYPE_INCOME, allNewTransactions[0].Type) assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid) assert.Equal(t, int64(1), allNewTransactions[0].Amount) assert.Equal(t, "Test Account", allNewTransactions[0].OriginalSourceAccountName) assert.Equal(t, "", allNewTransactions[0].OriginalDestinationAccountName) + assert.Equal(t, "earning", allNewTransactions[0].Comment) + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[1].Type) assert.Equal(t, int64(1234567890), allNewTransactions[1].Uid) - assert.Equal(t, int64(2), allNewTransactions[1].Amount) - assert.Equal(t, "Test Account2", allNewTransactions[1].OriginalSourceAccountName) - assert.Equal(t, "", allNewTransactions[1].OriginalDestinationAccountName) + assert.Equal(t, int64(1), allNewTransactions[1].Amount) + assert.Equal(t, "Test Account", allNewTransactions[1].OriginalSourceAccountName) + assert.Equal(t, "Test Account2", allNewTransactions[1].OriginalDestinationAccountName) + assert.Equal(t, "purchase investment", allNewTransactions[1].Comment) + + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[2].Type) + assert.Equal(t, int64(1234567890), allNewTransactions[2].Uid) + assert.Equal(t, int64(1), allNewTransactions[2].Amount) + assert.Equal(t, "Test Account2", allNewTransactions[2].OriginalSourceAccountName) + assert.Equal(t, "Test Account", allNewTransactions[2].OriginalDestinationAccountName) + assert.Equal(t, "sell investment", allNewTransactions[2].Comment) + + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[3].Type) + assert.Equal(t, int64(1234567890), allNewTransactions[3].Uid) + assert.Equal(t, int64(1), allNewTransactions[3].Amount) + assert.Equal(t, "", allNewTransactions[3].OriginalSourceAccountName) + assert.Equal(t, "Alipay", allNewTransactions[3].OriginalDestinationAccountName) + assert.Equal(t, "transfer to alipay wallet", allNewTransactions[3].Comment) + + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[4].Type) + assert.Equal(t, int64(1234567890), allNewTransactions[4].Uid) + assert.Equal(t, int64(1), allNewTransactions[4].Amount) + assert.Equal(t, "Alipay", allNewTransactions[4].OriginalSourceAccountName) + assert.Equal(t, "Test Account3", allNewTransactions[4].OriginalDestinationAccountName) + assert.Equal(t, "transfer from alipay wallet", allNewTransactions[4].Comment) + + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[5].Type) + assert.Equal(t, int64(1234567890), allNewTransactions[5].Uid) + assert.Equal(t, int64(1), allNewTransactions[5].Amount) + assert.Equal(t, "Test Account", allNewTransactions[5].OriginalSourceAccountName) + assert.Equal(t, "Test Account3", allNewTransactions[5].OriginalDestinationAccountName) + assert.Equal(t, "transfer in", allNewTransactions[5].Comment) + + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[6].Type) + assert.Equal(t, int64(1234567890), allNewTransactions[6].Uid) + assert.Equal(t, int64(1), allNewTransactions[6].Amount) + assert.Equal(t, "Test Account", allNewTransactions[6].OriginalSourceAccountName) + assert.Equal(t, "Test Account3", allNewTransactions[6].OriginalDestinationAccountName) + assert.Equal(t, "transfer out", allNewTransactions[6].Comment) + + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[7].Type) + assert.Equal(t, int64(1234567890), allNewTransactions[7].Uid) + assert.Equal(t, int64(1), allNewTransactions[7].Amount) + assert.Equal(t, "Test Account", allNewTransactions[7].OriginalSourceAccountName) + assert.Equal(t, "Test Account3", allNewTransactions[7].OriginalDestinationAccountName) + assert.Equal(t, "transfer", allNewTransactions[7].Comment) + + assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[8].Type) + assert.Equal(t, int64(1234567890), allNewTransactions[8].Uid) + assert.Equal(t, int64(1), allNewTransactions[8].Amount) + assert.Equal(t, "Test Account", allNewTransactions[8].OriginalSourceAccountName) + assert.Equal(t, "Test Account4", allNewTransactions[8].OriginalDestinationAccountName) + assert.Equal(t, "repayment", allNewTransactions[8].Comment) 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, "", allNewAccounts[1].Name) + assert.Equal(t, "Test Account2", allNewAccounts[1].Name) assert.Equal(t, "CNY", allNewAccounts[1].Currency) assert.Equal(t, int64(1234567890), allNewAccounts[2].Uid) - assert.Equal(t, "Test Account2", allNewAccounts[2].Name) + assert.Equal(t, "", allNewAccounts[2].Name) assert.Equal(t, "CNY", allNewAccounts[2].Currency) + + assert.Equal(t, int64(1234567890), allNewAccounts[3].Uid) + assert.Equal(t, "Alipay", allNewAccounts[3].Name) + assert.Equal(t, "CNY", allNewAccounts[3].Currency) + + assert.Equal(t, int64(1234567890), allNewAccounts[4].Uid) + assert.Equal(t, "Test Account3", allNewAccounts[4].Name) + assert.Equal(t, "CNY", allNewAccounts[4].Currency) + + assert.Equal(t, int64(1234567890), allNewAccounts[5].Uid) + assert.Equal(t, "Test Account4", allNewAccounts[5].Name) + assert.Equal(t, "CNY", allNewAccounts[5].Currency) } func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) { diff --git a/pkg/converters/alipay/alipay_transaction_data_row_parser.go b/pkg/converters/alipay/alipay_transaction_data_row_parser.go index 47757b67..9930f2d1 100644 --- a/pkg/converters/alipay/alipay_transaction_data_row_parser.go +++ b/pkg/converters/alipay/alipay_transaction_data_row_parser.go @@ -18,10 +18,15 @@ const alipayTransactionDataStatusClosedName = "交易关闭" const alipayTransactionDataStatusRefundSuccessName = "退款成功" const alipayTransactionDataStatusTaxRefundSuccessName = "退税成功" +const alipayTransactionDataProductNameEarningText = "-收益发放" +const alipayTransactionDataProductNamePurchaseInvestmentText = "-买入" +const alipayTransactionDataProductNamePurchaseInvestmentRefundText = "-买入退款" +const alipayTransactionDataProductNameSellInvestmentRefundText = "-卖出" const alipayTransactionDataProductNameTransferToAlipayPrefix = "充值-" const alipayTransactionDataProductNameTransferFromAlipayPrefix = "提现-" const alipayTransactionDataProductNameTransferInText = "转入" const alipayTransactionDataProductNameTransferOutText = "转出" +const alipayTransactionDataProductNameTransferText = "转账" const alipayTransactionDataProductNameRepaymentText = "还款" // alipayTransactionDataRowParser defines the structure of alipay transaction data row parser @@ -127,11 +132,29 @@ func (p *alipayTransactionDataRowParser) Parse(ctx core.Context, user *models.Us } if statusName == alipayTransactionDataStatusRefundSuccessName { - data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] - data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = relatedAccountName - data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = "" + if len(productName) > len(alipayTransactionDataProductNamePurchaseInvestmentText) && strings.Index(productName, alipayTransactionDataProductNamePurchaseInvestmentText) == len(productName)-len(alipayTransactionDataProductNamePurchaseInvestmentText) { // purchase investment + data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = relatedAccountName + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName + } else if len(productName) > len(alipayTransactionDataProductNamePurchaseInvestmentRefundText) && strings.Index(productName, alipayTransactionDataProductNamePurchaseInvestmentRefundText) == len(productName)-len(alipayTransactionDataProductNamePurchaseInvestmentRefundText) { // purchase investment refund + data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = targetName + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = relatedAccountName + } else { + data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] + data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = relatedAccountName + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = "" + } } else { - if strings.Index(productName, alipayTransactionDataProductNameTransferToAlipayPrefix) == 0 { // transfer to alipay wallet + if len(productName) > len(alipayTransactionDataProductNameEarningText) && strings.Index(productName, alipayTransactionDataProductNameEarningText) == len(productName)-len(alipayTransactionDataProductNameEarningText) { // earning + data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] + data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = relatedAccountName + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName + } else if len(productName) > len(alipayTransactionDataProductNamePurchaseInvestmentText) && strings.Index(productName, alipayTransactionDataProductNamePurchaseInvestmentText) == len(productName)-len(alipayTransactionDataProductNamePurchaseInvestmentText) { // purchase investment + data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = relatedAccountName + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName + } else if strings.Index(productName, alipayTransactionDataProductNameSellInvestmentRefundText) >= 0 { // sell investment + data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = targetName + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = relatedAccountName + } else if strings.Index(productName, alipayTransactionDataProductNameTransferToAlipayPrefix) == 0 { // transfer to alipay wallet data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = "" data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = localeTextItems.DataConverterTextItems.Alipay } else if strings.Index(productName, alipayTransactionDataProductNameTransferFromAlipayPrefix) == 0 { // transfer from alipay wallet @@ -143,6 +166,9 @@ func (p *alipayTransactionDataRowParser) Parse(ctx core.Context, user *models.Us } else if strings.Index(productName, alipayTransactionDataProductNameTransferOutText) >= 0 { // transfer out data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = relatedAccountName data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName + } else if strings.Index(productName, alipayTransactionDataProductNameTransferText) >= 0 { // transfer + data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = relatedAccountName + data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName } else if strings.Index(productName, alipayTransactionDataProductNameRepaymentText) >= 0 { // repayment data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = relatedAccountName data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName