code refactor

This commit is contained in:
MaysWind
2024-10-07 23:54:50 +08:00
parent a6e765f51c
commit ae26f00a36
5 changed files with 413 additions and 383 deletions
@@ -1,328 +0,0 @@
package alipay
import (
"bytes"
"encoding/csv"
"io"
"strings"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
"github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/locales"
"github.com/mayswind/ezbookkeeping/pkg/log"
"github.com/mayswind/ezbookkeeping/pkg/models"
"github.com/mayswind/ezbookkeeping/pkg/utils"
)
const alipayTransactionDataCsvFileHeader = "支付宝交易记录明细查询"
const alipayTransactionDataCsvDataHeaderLineStartContent = "交易记录明细列表"
const alipayTransactionDataCsvDataHeaderLineEndLineRune = '-'
const alipayTransactionDataStatusSuccessName = "交易成功"
const alipayTransactionDataStatusPaymentSuccessName = "支付成功"
const alipayTransactionDataStatusRepaymentSuccessName = "还款成功"
const alipayTransactionDataStatusClosedName = "交易关闭"
const alipayTransactionDataStatusRefundSuccessName = "退款成功"
const alipayTransactionDataStatusTaxRefundSuccessName = "退税成功"
const alipayTransactionDataProductNameRechargePrefix = "充值-"
const alipayTransactionDataProductNameCashWithdrawalPrefix = "提现-"
const alipayTransactionDataProductNameTransferInText = "转入"
const alipayTransactionDataProductNameTransferOutText = "转出"
const alipayTransactionDataProductNameRepaymentText = "还款"
var alipayTransactionTypeFundStatusNameMapping = map[models.TransactionType]string{
models.TRANSACTION_TYPE_INCOME: "已收入",
models.TRANSACTION_TYPE_EXPENSE: "已支出",
models.TRANSACTION_TYPE_TRANSFER: "资金转移",
}
// alipayTransactionDataCsvImporter defines the structure of alipay csv importer for transaction data
type alipayTransactionDataCsvImporter struct{}
// Initialize a alipay transaction data csv file importer singleton instance
var (
AlipayTransactionDataCsvImporter = &alipayTransactionDataCsvImporter{}
)
// ParseImportedData returns the imported data by parsing the alipay transaction csv data
func (c *alipayTransactionDataCsvImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]*models.TransactionCategory, incomeCategoryMap map[string]*models.TransactionCategory, transferCategoryMap 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
reader := transform.NewReader(bytes.NewReader(data), enc.NewDecoder())
allLines, err := c.parseAllLinesFromCsvData(ctx, reader)
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
if len(allLines) <= 1 {
log.Errorf(ctx, "[alipayTransactionDataCsvImporter.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
}
headerLineItems := allLines[0]
headerItemMap := make(map[string]int)
for i := 0; i < len(headerLineItems); i++ {
headerItemMap[headerLineItems[i]] = i
}
timeColumnIdx, timeColumnExists := headerItemMap["交易创建时间"]
targetNameColumnIdx, targetNameColumnExists := headerItemMap["交易对方"]
productNameColumnIdx, productNameColumnExists := headerItemMap["商品名称"]
amountColumnIdx, amountColumnExists := headerItemMap["金额(元)"]
statusColumnIdx, statusColumnExists := headerItemMap["交易状态"]
descriptionColumnIdx, descriptionColumnExists := headerItemMap["备注"]
fundStatusColumnIdx, fundStatusColumnExists := headerItemMap["资金状态"]
if !timeColumnExists || !amountColumnExists || !statusColumnExists || !fundStatusColumnExists {
log.Errorf(ctx, "[alipayTransactionDataCsvImporter.ParseImportedData] cannot parse import data for user \"uid:%d\", because missing essential columns in header row", user.Uid)
return nil, nil, nil, nil, nil, nil, errs.ErrMissingRequiredFieldInHeaderRow
}
newColumns := make([]datatable.DataTableColumn, 0, 7)
newColumns = append(newColumns, datatable.DATA_TABLE_TRANSACTION_TYPE)
newColumns = append(newColumns, datatable.DATA_TABLE_TRANSACTION_TIME)
newColumns = append(newColumns, datatable.DATA_TABLE_SUB_CATEGORY)
newColumns = append(newColumns, datatable.DATA_TABLE_ACCOUNT_NAME)
newColumns = append(newColumns, datatable.DATA_TABLE_AMOUNT)
newColumns = append(newColumns, datatable.DATA_TABLE_RELATED_ACCOUNT_NAME)
newColumns = append(newColumns, datatable.DATA_TABLE_DESCRIPTION)
dataTable := datatable.CreateNewWritableDataTable(newColumns)
for i := 1; i < len(allLines); i++ {
items := allLines[i]
if len(items) < len(headerLineItems) {
log.Errorf(ctx, "[alipayTransactionDataCsvImporter.ParseImportedData] cannot parse row \"index:%d\" for user \"uid:%d\", because may missing some columns (column count %d in data row is less than header column count %d)", i, user.Uid, len(items), len(headerLineItems))
return nil, nil, nil, nil, nil, nil, errs.ErrFewerFieldsInDataRowThanInHeaderRow
}
if items[fundStatusColumnIdx] != alipayTransactionTypeFundStatusNameMapping[models.TRANSACTION_TYPE_INCOME] &&
items[fundStatusColumnIdx] != alipayTransactionTypeFundStatusNameMapping[models.TRANSACTION_TYPE_EXPENSE] &&
items[fundStatusColumnIdx] != alipayTransactionTypeFundStatusNameMapping[models.TRANSACTION_TYPE_TRANSFER] {
log.Warnf(ctx, "[alipayTransactionDataCsvImporter.ParseImportedData] skip parsing transaction in row \"index:%d\" for user \"uid:%d\", because fund status is \"%s\"", i, user.Uid, items[fundStatusColumnIdx])
continue
}
data := c.parseTransactionData(ctx,
user,
items,
timeColumnIdx,
timeColumnExists,
targetNameColumnIdx,
targetNameColumnExists,
productNameColumnIdx,
productNameColumnExists,
amountColumnIdx,
amountColumnExists,
statusColumnIdx,
statusColumnExists,
descriptionColumnIdx,
descriptionColumnExists,
fundStatusColumnIdx,
fundStatusColumnExists,
)
if items[statusColumnIdx] == alipayTransactionDataStatusSuccessName || items[statusColumnIdx] == alipayTransactionDataStatusPaymentSuccessName || items[statusColumnIdx] == alipayTransactionDataStatusRepaymentSuccessName {
dataTable.Add(data)
} else if items[statusColumnIdx] == alipayTransactionDataStatusClosedName {
dataTable.Add(data)
} else if items[statusColumnIdx] == alipayTransactionDataStatusRefundSuccessName || items[statusColumnIdx] == alipayTransactionDataStatusTaxRefundSuccessName {
amount, err := utils.ParseAmount(data[datatable.DATA_TABLE_AMOUNT])
if err == nil {
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = alipayTransactionTypeFundStatusNameMapping[models.TRANSACTION_TYPE_EXPENSE]
data[datatable.DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount)
}
dataTable.Add(data)
}
}
dataTableImporter := datatable.CreateNewSimpleImporterFromWritableDataTable(
dataTable,
alipayTransactionTypeFundStatusNameMapping,
)
return dataTableImporter.ParseImportedData(ctx, user, dataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
}
func (c *alipayTransactionDataCsvImporter) parseAllLinesFromCsvData(ctx core.Context, reader io.Reader) ([][]string, error) {
csvReader := csv.NewReader(reader)
csvReader.FieldsPerRecord = -1
allLines := make([][]string, 0)
hasFileHeader := false
foundContentBeforeDataHeaderLine := false
for {
items, err := csvReader.Read()
if err == io.EOF {
break
}
if err != nil {
log.Errorf(ctx, "[alipayTransactionDataCsvImporter.parseAllLinesFromCsvData] cannot parse alipay csv data, because %s", err.Error())
return nil, errs.ErrInvalidCSVFile
}
if !hasFileHeader {
if len(items) <= 0 {
continue
} else if strings.Index(items[0], alipayTransactionDataCsvFileHeader) == 0 {
hasFileHeader = true
continue
} else {
log.Warnf(ctx, "[alipayTransactionDataCsvImporter.parseAllLinesFromCsvData] read unexpected line before read file header, line content is %s", strings.Join(items, ","))
}
}
if !foundContentBeforeDataHeaderLine {
if len(items) <= 0 {
continue
} else if strings.Index(items[0], alipayTransactionDataCsvDataHeaderLineStartContent) >= 0 {
foundContentBeforeDataHeaderLine = true
continue
} else {
continue
}
}
if foundContentBeforeDataHeaderLine {
if len(items) <= 0 {
continue
} else if len(items) == 1 && utils.ContainsOnlyOneRune(items[0], alipayTransactionDataCsvDataHeaderLineEndLineRune) {
break
}
for i := 0; i < len(items); i++ {
items[i] = strings.Trim(items[i], " ")
}
allLines = append(allLines, items)
}
}
if !hasFileHeader || !foundContentBeforeDataHeaderLine {
return nil, errs.ErrInvalidFileHeader
}
return allLines, nil
}
func (c *alipayTransactionDataCsvImporter) parseTransactionData(
ctx core.Context,
user *models.User,
items []string,
timeColumnIdx int,
timeColumnExists bool,
targetNameColumnIdx int,
targetNameColumnExists bool,
productNameColumnIdx int,
productNameColumnExists bool,
amountColumnIdx int,
amountColumnExists bool,
statusColumnIdx int,
statusColumnExists bool,
descriptionColumnIdx int,
descriptionColumnExists bool,
fundStatusColumnIdx int,
fundStatusColumnExists bool,
) map[datatable.DataTableColumn]string {
data := make(map[datatable.DataTableColumn]string, 11)
if timeColumnExists && timeColumnIdx < len(items) {
data[datatable.DATA_TABLE_TRANSACTION_TIME] = items[timeColumnIdx]
}
if amountColumnExists && amountColumnIdx < len(items) {
data[datatable.DATA_TABLE_AMOUNT] = items[amountColumnIdx]
}
data[datatable.DATA_TABLE_SUB_CATEGORY] = ""
if descriptionColumnExists && descriptionColumnIdx < len(items) && items[descriptionColumnIdx] != "" {
data[datatable.DATA_TABLE_DESCRIPTION] = items[descriptionColumnIdx]
} else if productNameColumnExists && productNameColumnIdx < len(items) && items[productNameColumnIdx] != "" {
data[datatable.DATA_TABLE_DESCRIPTION] = items[productNameColumnIdx]
} else {
data[datatable.DATA_TABLE_DESCRIPTION] = ""
}
if fundStatusColumnExists && fundStatusColumnIdx < len(items) {
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = items[fundStatusColumnIdx]
if items[fundStatusColumnIdx] == alipayTransactionTypeFundStatusNameMapping[models.TRANSACTION_TYPE_INCOME] {
locale := user.Language
if locale == "" {
locale = ctx.GetClientLocale()
}
localeTextItems := locales.GetLocaleTextItems(locale)
statusName := ""
if statusColumnExists && statusColumnIdx < len(items) {
statusName = items[statusColumnIdx]
}
if statusName == alipayTransactionDataStatusSuccessName {
data[datatable.DATA_TABLE_ACCOUNT_NAME] = localeTextItems.DataConverterTextItems.Alipay
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
} else {
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
}
} else if items[fundStatusColumnIdx] == alipayTransactionTypeFundStatusNameMapping[models.TRANSACTION_TYPE_TRANSFER] {
locale := user.Language
if locale == "" {
locale = ctx.GetClientLocale()
}
localeTextItems := locales.GetLocaleTextItems(locale)
targetName := ""
productName := ""
if targetNameColumnExists && targetNameColumnIdx < len(items) {
targetName = items[targetNameColumnIdx]
}
if productNameColumnExists && productNameColumnIdx < len(items) {
productName = items[productNameColumnIdx]
}
if strings.Index(productName, alipayTransactionDataProductNameRechargePrefix) == 0 { // transfer to alipay wallet
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = localeTextItems.DataConverterTextItems.Alipay
} else if strings.Index(productName, alipayTransactionDataProductNameCashWithdrawalPrefix) == 0 { // transfer from alipay wallet
data[datatable.DATA_TABLE_ACCOUNT_NAME] = localeTextItems.DataConverterTextItems.Alipay
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName
} else if strings.Index(productName, alipayTransactionDataProductNameTransferInText) >= 0 { // transfer in
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName
} else if strings.Index(productName, alipayTransactionDataProductNameTransferOutText) >= 0 { // transfer out
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName
} else if strings.Index(productName, alipayTransactionDataProductNameRepaymentText) >= 0 { // repayment
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName
} else {
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
}
} else {
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
}
}
return data
}
@@ -0,0 +1,349 @@
package alipay
import (
"bytes"
"encoding/csv"
"fmt"
"io"
"strings"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
"github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/locales"
"github.com/mayswind/ezbookkeeping/pkg/log"
"github.com/mayswind/ezbookkeeping/pkg/models"
"github.com/mayswind/ezbookkeeping/pkg/utils"
)
const alipayWebTransactionDataCsvFileHeader = "支付宝交易记录明细查询"
const alipayWebTransactionDataCsvDataHeaderLineStartContent = "交易记录明细列表"
const alipayWebTransactionDataCsvDataDataLineEndLineRune = '-'
const alipayWebTransactionDataStatusSuccessName = "交易成功"
const alipayWebTransactionDataStatusPaymentSuccessName = "支付成功"
const alipayWebTransactionDataStatusRepaymentSuccessName = "还款成功"
const alipayWebTransactionDataStatusClosedName = "交易关闭"
const alipayWebTransactionDataStatusRefundSuccessName = "退款成功"
const alipayWebTransactionDataStatusTaxRefundSuccessName = "退税成功"
const alipayWebTransactionDataProductNameRechargePrefix = "充值-"
const alipayWebTransactionDataProductNameCashWithdrawalPrefix = "提现-"
const alipayWebTransactionDataProductNameTransferInText = "转入"
const alipayWebTransactionDataProductNameTransferOutText = "转出"
const alipayWebTransactionDataProductNameRepaymentText = "还款"
var alipayTransactionTypeNameMapping = map[models.TransactionType]string{
models.TRANSACTION_TYPE_INCOME: "收入",
models.TRANSACTION_TYPE_EXPENSE: "支出",
models.TRANSACTION_TYPE_TRANSFER: "不计收支",
}
// alipayWebTransactionDataCsvImporter defines the structure of alipay (web) csv importer for transaction data
type alipayWebTransactionDataCsvImporter struct{}
// Initialize a alipay (web) transaction data csv file importer singleton instance
var (
AlipayWebTransactionDataCsvImporter = &alipayWebTransactionDataCsvImporter{}
)
// ParseImportedData returns the imported data by parsing the alipay (web) transaction csv data
func (c *alipayWebTransactionDataCsvImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]*models.TransactionCategory, incomeCategoryMap map[string]*models.TransactionCategory, transferCategoryMap 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
reader := transform.NewReader(bytes.NewReader(data), enc.NewDecoder())
allLines, err := c.parseAllLinesFromCsvData(ctx, reader)
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
if len(allLines) <= 1 {
log.Errorf(ctx, "[alipayWebTransactionDataCsvImporter.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
}
headerLineItems := allLines[0]
headerItemMap := make(map[string]int)
for i := 0; i < len(headerLineItems); i++ {
headerItemMap[headerLineItems[i]] = i
}
timeColumnIdx, timeColumnExists := headerItemMap["交易创建时间"]
targetNameColumnIdx, targetNameColumnExists := headerItemMap["交易对方"]
productNameColumnIdx, productNameColumnExists := headerItemMap["商品名称"]
amountColumnIdx, amountColumnExists := headerItemMap["金额(元)"]
typeColumnIdx, typeColumnExists := headerItemMap["收/支"]
statusColumnIdx, statusColumnExists := headerItemMap["交易状态"]
descriptionColumnIdx, descriptionColumnExists := headerItemMap["备注"]
if !timeColumnExists || !amountColumnExists || !typeColumnExists || !statusColumnExists {
log.Errorf(ctx, "[alipayWebTransactionDataCsvImporter.ParseImportedData] cannot parse import data for user \"uid:%d\", because missing essential columns in header row", user.Uid)
return nil, nil, nil, nil, nil, nil, errs.ErrMissingRequiredFieldInHeaderRow
}
newColumns := make([]datatable.DataTableColumn, 0, 7)
newColumns = append(newColumns, datatable.DATA_TABLE_TRANSACTION_TYPE)
newColumns = append(newColumns, datatable.DATA_TABLE_TRANSACTION_TIME)
newColumns = append(newColumns, datatable.DATA_TABLE_SUB_CATEGORY)
newColumns = append(newColumns, datatable.DATA_TABLE_ACCOUNT_NAME)
newColumns = append(newColumns, datatable.DATA_TABLE_AMOUNT)
newColumns = append(newColumns, datatable.DATA_TABLE_RELATED_ACCOUNT_NAME)
newColumns = append(newColumns, datatable.DATA_TABLE_DESCRIPTION)
dataTable := datatable.CreateNewWritableDataTable(newColumns)
for i := 1; i < len(allLines); i++ {
items := allLines[i]
if len(items) < len(headerLineItems) {
log.Errorf(ctx, "[alipayWebTransactionDataCsvImporter.ParseImportedData] cannot parse row \"index:%d\" for user \"uid:%d\", because may missing some columns (column count %d in data row is less than header column count %d)", i, user.Uid, len(items), len(headerLineItems))
return nil, nil, nil, nil, nil, nil, errs.ErrFewerFieldsInDataRowThanInHeaderRow
}
if items[typeColumnIdx] != alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] &&
items[typeColumnIdx] != alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE] &&
items[typeColumnIdx] != alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_TRANSFER] {
log.Warnf(ctx, "[alipayWebTransactionDataCsvImporter.ParseImportedData] skip parsing transaction in row \"index:%d\" for user \"uid:%d\", because type is \"%s\"", i, user.Uid, items[typeColumnIdx])
continue
}
if items[statusColumnIdx] != alipayWebTransactionDataStatusSuccessName &&
items[statusColumnIdx] != alipayWebTransactionDataStatusPaymentSuccessName &&
items[statusColumnIdx] != alipayWebTransactionDataStatusRepaymentSuccessName &&
items[statusColumnIdx] != alipayWebTransactionDataStatusClosedName &&
items[statusColumnIdx] != alipayWebTransactionDataStatusRefundSuccessName &&
items[statusColumnIdx] != alipayWebTransactionDataStatusTaxRefundSuccessName {
log.Warnf(ctx, "[alipayWebTransactionDataCsvImporter.ParseImportedData] skip parsing transaction in row \"index:%d\" for user \"uid:%d\", because status is \"%s\"", i, user.Uid, items[statusColumnIdx])
continue
}
data, errMsg := c.parseTransactionData(ctx,
user,
items,
timeColumnIdx,
timeColumnExists,
targetNameColumnIdx,
targetNameColumnExists,
productNameColumnIdx,
productNameColumnExists,
amountColumnIdx,
amountColumnExists,
typeColumnIdx,
typeColumnExists,
statusColumnIdx,
statusColumnExists,
descriptionColumnIdx,
descriptionColumnExists,
)
if data == nil {
log.Warnf(ctx, "[alipayWebTransactionDataCsvImporter.ParseImportedData] skip parsing transaction in row \"index:%d\" for user \"uid:%d\", because %s", i, user.Uid, errMsg)
continue
}
dataTable.Add(data)
}
dataTableImporter := datatable.CreateNewSimpleImporterFromWritableDataTable(
dataTable,
alipayTransactionTypeNameMapping,
)
return dataTableImporter.ParseImportedData(ctx, user, dataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
}
func (c *alipayWebTransactionDataCsvImporter) parseAllLinesFromCsvData(ctx core.Context, reader io.Reader) ([][]string, error) {
csvReader := csv.NewReader(reader)
csvReader.FieldsPerRecord = -1
allLines := make([][]string, 0)
hasFileHeader := false
foundContentBeforeDataHeaderLine := false
for {
items, err := csvReader.Read()
if err == io.EOF {
break
}
if err != nil {
log.Errorf(ctx, "[alipayWebTransactionDataCsvImporter.parseAllLinesFromCsvData] cannot parse alipay csv data, because %s", err.Error())
return nil, errs.ErrInvalidCSVFile
}
if !hasFileHeader {
if len(items) <= 0 {
continue
} else if strings.Index(items[0], alipayWebTransactionDataCsvFileHeader) == 0 {
hasFileHeader = true
continue
} else {
log.Warnf(ctx, "[alipayWebTransactionDataCsvImporter.parseAllLinesFromCsvData] read unexpected line before read file header, line content is %s", strings.Join(items, ","))
}
}
if !foundContentBeforeDataHeaderLine {
if len(items) <= 0 {
continue
} else if strings.Index(items[0], alipayWebTransactionDataCsvDataHeaderLineStartContent) >= 0 {
foundContentBeforeDataHeaderLine = true
continue
} else {
continue
}
}
if foundContentBeforeDataHeaderLine {
if len(items) <= 0 {
continue
} else if len(items) == 1 && utils.ContainsOnlyOneRune(items[0], alipayWebTransactionDataCsvDataDataLineEndLineRune) {
break
}
for i := 0; i < len(items); i++ {
items[i] = strings.Trim(items[i], " ")
}
allLines = append(allLines, items)
}
}
if !hasFileHeader || !foundContentBeforeDataHeaderLine {
return nil, errs.ErrInvalidFileHeader
}
return allLines, nil
}
func (c *alipayWebTransactionDataCsvImporter) parseTransactionData(
ctx core.Context,
user *models.User,
items []string,
timeColumnIdx int,
timeColumnExists bool,
targetNameColumnIdx int,
targetNameColumnExists bool,
productNameColumnIdx int,
productNameColumnExists bool,
amountColumnIdx int,
amountColumnExists bool,
typeColumnIdx int,
typeColumnExists bool,
statusColumnIdx int,
statusColumnExists bool,
descriptionColumnIdx int,
descriptionColumnExists bool,
) (map[datatable.DataTableColumn]string, string) {
data := make(map[datatable.DataTableColumn]string, 11)
if timeColumnExists && timeColumnIdx < len(items) {
data[datatable.DATA_TABLE_TRANSACTION_TIME] = items[timeColumnIdx]
}
if amountColumnExists && amountColumnIdx < len(items) {
data[datatable.DATA_TABLE_AMOUNT] = items[amountColumnIdx]
}
data[datatable.DATA_TABLE_SUB_CATEGORY] = ""
if descriptionColumnExists && descriptionColumnIdx < len(items) && items[descriptionColumnIdx] != "" {
data[datatable.DATA_TABLE_DESCRIPTION] = items[descriptionColumnIdx]
} else if productNameColumnExists && productNameColumnIdx < len(items) && items[productNameColumnIdx] != "" {
data[datatable.DATA_TABLE_DESCRIPTION] = items[productNameColumnIdx]
} else {
data[datatable.DATA_TABLE_DESCRIPTION] = ""
}
statusName := ""
if statusColumnExists && statusColumnIdx < len(items) {
statusName = items[statusColumnIdx]
}
locale := user.Language
if locale == "" {
locale = ctx.GetClientLocale()
}
localeTextItems := locales.GetLocaleTextItems(locale)
if typeColumnExists && typeColumnIdx < len(items) {
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = items[typeColumnIdx]
if items[typeColumnIdx] == alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] {
if statusName == alipayWebTransactionDataStatusClosedName {
return nil, fmt.Sprintf("income transaction is closed")
}
if statusName == alipayWebTransactionDataStatusSuccessName {
data[datatable.DATA_TABLE_ACCOUNT_NAME] = localeTextItems.DataConverterTextItems.Alipay
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
} else {
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
}
} else if items[typeColumnIdx] == alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_TRANSFER] {
if statusName == alipayWebTransactionDataStatusClosedName {
return nil, fmt.Sprintf("non-income/expense transaction is closed")
}
targetName := ""
productName := ""
if targetNameColumnExists && targetNameColumnIdx < len(items) {
targetName = items[targetNameColumnIdx]
}
if productNameColumnExists && productNameColumnIdx < len(items) {
productName = items[productNameColumnIdx]
}
if statusName == alipayWebTransactionDataStatusRefundSuccessName {
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME]
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
} else {
if strings.Index(productName, alipayWebTransactionDataProductNameRechargePrefix) == 0 { // transfer to alipay wallet
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = localeTextItems.DataConverterTextItems.Alipay
} else if strings.Index(productName, alipayWebTransactionDataProductNameCashWithdrawalPrefix) == 0 { // transfer from alipay wallet
data[datatable.DATA_TABLE_ACCOUNT_NAME] = localeTextItems.DataConverterTextItems.Alipay
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName
} else if strings.Index(productName, alipayWebTransactionDataProductNameTransferInText) >= 0 { // transfer in
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName
} else if strings.Index(productName, alipayWebTransactionDataProductNameTransferOutText) >= 0 { // transfer out
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName
} else if strings.Index(productName, alipayWebTransactionDataProductNameRepaymentText) >= 0 { // repayment
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = targetName
} else {
return nil, fmt.Sprintf("product name (\"%s\") is unknown", productName)
}
}
} else {
data[datatable.DATA_TABLE_ACCOUNT_NAME] = ""
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
}
}
if data[datatable.DATA_TABLE_TRANSACTION_TYPE] == alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME] && statusName != "" {
if statusName == alipayWebTransactionDataStatusRefundSuccessName || statusName == alipayWebTransactionDataStatusTaxRefundSuccessName {
amount, err := utils.ParseAmount(data[datatable.DATA_TABLE_AMOUNT])
if err == nil {
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = alipayTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE]
data[datatable.DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount)
}
}
}
return data, ""
}
@@ -15,7 +15,7 @@ import (
)
func TestAlipayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
converter := AlipayTransactionDataCsvImporter
converter := AlipayWebTransactionDataCsvImporter
context := core.NewNullContext()
user := &models.User{
@@ -27,17 +27,18 @@ func TestAlipayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 01:23:45 ,0.12 ,交易成功 ,已收入 ,\n" +
"2024-09-01 12:34:56 ,123.45 ,交易成功 ,已支出 ,\n" +
"2024-09-01 23:59:59 ,0.05 ,交易成功 ,资金转移 ,\n" +
"交易创建时间 ,商品名称 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 01:23:45 ,xxxx ,0.12 ,收入 ,交易成功 ,\n" +
"2024-09-01 12:34:56 ,xxxx ,123.45 ,支出 ,交易成功 ,\n" +
"2024-09-01 23:59:59 ,充值-普通充值 ,0.05 ,不计收支 ,交易成功 ,\n" +
"2024-09-02 23:59:59 ,提现-普通提现 ,0.03 ,不计收支 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := converter.ParseImportedData(context, user, []byte(data), 0, nil, nil, nil, nil, nil)
assert.Nil(t, err)
assert.Equal(t, 3, len(allNewTransactions))
assert.Equal(t, 4, len(allNewTransactions))
assert.Equal(t, 2, len(allNewAccounts))
assert.Equal(t, 1, len(allNewSubExpenseCategories))
assert.Equal(t, 1, len(allNewSubIncomeCategories))
@@ -63,9 +64,17 @@ func TestAlipayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
assert.Equal(t, "2024-09-01 23:59:59", utils.FormatUnixTimeToLongDateTime(utils.GetUnixTimeFromTransactionTime(allNewTransactions[2].TransactionTime), time.UTC))
assert.Equal(t, int64(5), allNewTransactions[2].Amount)
assert.Equal(t, "", allNewTransactions[2].OriginalSourceAccountName)
assert.Equal(t, "", allNewTransactions[2].OriginalDestinationAccountName)
assert.Equal(t, "Alipay", allNewTransactions[2].OriginalDestinationAccountName)
assert.Equal(t, "", allNewTransactions[2].OriginalCategoryName)
assert.Equal(t, int64(1234567890), allNewTransactions[3].Uid)
assert.Equal(t, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, allNewTransactions[3].Type)
assert.Equal(t, "2024-09-02 23:59:59", utils.FormatUnixTimeToLongDateTime(utils.GetUnixTimeFromTransactionTime(allNewTransactions[3].TransactionTime), time.UTC))
assert.Equal(t, int64(3), allNewTransactions[3].Amount)
assert.Equal(t, "Alipay", allNewTransactions[3].OriginalSourceAccountName)
assert.Equal(t, "", allNewTransactions[3].OriginalDestinationAccountName)
assert.Equal(t, "", allNewTransactions[3].OriginalCategoryName)
assert.Equal(t, int64(1234567890), allNewAccounts[0].Uid)
assert.Equal(t, "Alipay", allNewAccounts[0].Name)
assert.Equal(t, "CNY", allNewAccounts[0].Currency)
@@ -85,7 +94,7 @@ func TestAlipayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
}
func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testing.T) {
converter := AlipayTransactionDataCsvImporter
converter := AlipayWebTransactionDataCsvImporter
context := core.NewNullContext()
user := &models.User{
@@ -97,8 +106,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 01:23:45 ,0.12 ,退款成功 ,已收入 ,\n" +
"交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 01:23:45 ,0.12 ,不计收支 ,退款成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -116,8 +125,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 01:23:45 ,0.12 ,退税成功 ,已收入 ,\n" +
"交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 01:23:45 ,0.12 ,收入 ,退税成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -133,7 +142,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin
}
func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
converter := AlipayTransactionDataCsvImporter
converter := AlipayWebTransactionDataCsvImporter
context := core.NewNullContext()
user := &models.User{
@@ -145,8 +154,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01T12:34:56 ,0.12 ,交易成功 ,已收入 ,\n" +
"交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01T12:34:56 ,0.12 ,收入 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -157,8 +166,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,金额(元),交易状态 ,资金状态 ,\n" +
"09/01/2024 12:34:56 ,0.12 ,交易成功 ,已收入 ,\n" +
"交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" +
"09/01/2024 12:34:56 ,0.12 ,收入 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -167,7 +176,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
}
func TestAlipayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) {
converter := AlipayTransactionDataCsvImporter
converter := AlipayWebTransactionDataCsvImporter
context := core.NewNullContext()
user := &models.User{
@@ -179,8 +188,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,0.12 ,交易成功 , ,\n" +
"交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,0.12 , ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -189,7 +198,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) {
}
func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
converter := AlipayTransactionDataCsvImporter
converter := AlipayWebTransactionDataCsvImporter
context := core.NewNullContext()
user := &models.User{
@@ -202,8 +211,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,交易对方 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,test ,0.12 ,交易成功 ,已收入 ,\n" +
"交易创建时间 ,交易对方 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,test ,0.12 ,收入 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -213,13 +222,13 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
assert.Equal(t, 1, len(allNewTransactions))
assert.Equal(t, "Alipay", allNewTransactions[0].OriginalSourceAccountName)
// income to other account
// refund to other account
data2, err := simplifiedchinese.GB18030.NewEncoder().String("支付宝交易记录明细查询\n" +
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,交易对方 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,test ,0.12 ,退款成功 ,已收入 ,\n" +
"交易创建时间 ,交易对方 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,test ,0.12 ,不计收支 ,退款成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -234,8 +243,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,test ,充值-普通充值 ,0.12 ,交易成功 ,资金转移 ,\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,test ,充值-普通充值 ,0.12 ,不计收支 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -251,8 +260,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,test ,提现-实时提现 ,0.12 ,交易成功 ,资金转移 ,\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,test ,提现-实时提现 ,0.12 ,不计收支 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -268,8 +277,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,test ,xx-转入 ,0.12 ,交易成功 ,资金转移 ,\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,test ,xx-转入 ,0.12 ,不计收支 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -285,8 +294,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,test ,xx-转出 ,0.12 ,交易成功 ,资金转移 ,\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,test ,xx-转出 ,0.12 ,不计收支 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -302,8 +311,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,test ,xx还款 ,0.12 ,交易成功 ,资金转移 ,\n" +
"交易创建时间 ,交易对方 ,商品名称 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,test ,xx还款 ,0.12 ,不计收支 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -316,7 +325,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
}
func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
converter := AlipayTransactionDataCsvImporter
converter := AlipayWebTransactionDataCsvImporter
context := core.NewNullContext()
user := &models.User{
@@ -328,8 +337,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,商品名称 ,金额(元),交易状态 ,备注 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,test ,0.12 ,交易成功 ,test2 ,已收入 ,\n" +
"交易创建时间 ,商品名称 ,金额(元),收/支 ,交易状态 ,备注 ,\n" +
"2024-09-01 12:34:56 ,test ,0.12 ,收入 ,交易成功 ,test2 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -343,8 +352,8 @@ func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,商品名称 ,金额(元),交易状态 ,备注 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,test ,0.12 ,交易成功 , ,已收入 ,\n" +
"交易创建时间 ,商品名称 ,金额(元),收/支 ,交易状态 ,备注 ,\n" +
"2024-09-01 12:34:56 ,test ,0.12 ,收入 ,交易成功 , ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -356,7 +365,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
}
func TestAlipayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T) {
converter := AlipayTransactionDataCsvImporter
converter := AlipayWebTransactionDataCsvImporter
context := core.NewNullContext()
user := &models.User{
@@ -365,8 +374,8 @@ func TestAlipayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T)
}
data, err := simplifiedchinese.GB18030.NewEncoder().String(
"交易创建时间 ,金额(元),交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,0.12 ,交易成功 ,Type ,\n" +
"交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,0.12 ,收入 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
assert.Nil(t, err)
@@ -378,7 +387,7 @@ func TestAlipayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T)
}
func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing.T) {
converter := AlipayTransactionDataCsvImporter
converter := AlipayWebTransactionDataCsvImporter
context := core.NewNullContext()
user := &models.User{
@@ -391,8 +400,8 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"金额(元),交易状态 ,资金状态 ,\n" +
"0.12 ,交易成功 ,已收入 ,\n" +
"金额(元),收/支 ,交易状态 ,\n" +
"0.12 ,收入 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data1), 0, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
@@ -402,8 +411,8 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,交易状态 ,资金状态 ,\n" +
"2024-09-01 12:34:56 ,交易成功 ,已收入 ,\n" +
"交易创建时间 ,收/支 ,交易状态 ,\n" +
"2024-09-01 12:34:56 ,收入 ,交易成功 ,\n" +
"------------------------------------------------------------------------------------\n")
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data2), 0, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
@@ -413,13 +422,13 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
"---------------------------------交易记录明细列表------------------------------------\n" +
"交易创建时间 ,金额(元),资金状态 ,\n" +
"2024-09-01 12:34:56 ,0.12 ,收入 ,\n" +
"交易创建时间 ,金额(元),收/支 ,\n" +
"2024-09-01 12:34:56 ,0.12 ,收入 ,\n" +
"------------------------------------------------------------------------------------\n")
_, _, _, _, _, _, err = converter.ParseImportedData(context, user, []byte(data3), 0, nil, nil, nil, nil, nil)
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
// Missing Fund Status Column
// Missing Type Column
data4, err := simplifiedchinese.GB18030.NewEncoder().String("支付宝交易记录明细查询\n" +
"账号:[xxx@xxx.xxx]\n" +
"起始日期:[2024-01-01 00:00:00] 终止日期:[2024-09-01 23:59:59]\n" +
@@ -29,8 +29,8 @@ func GetTransactionDataImporter(fileType string) (base.TransactionDataImporter,
return feidee.FeideeMymoneyTransactionDataCsvImporter, nil
} else if fileType == "feidee_mymoney_xls" {
return feidee.FeideeMymoneyTransactionDataXlsImporter, nil
} else if fileType == "alipay_csv" {
return alipay.AlipayTransactionDataCsvImporter, nil
} else if fileType == "alipay_web_csv" {
return alipay.AlipayWebTransactionDataCsvImporter, nil
} else {
return nil, errs.ErrImportFileTypeNotSupported
}
+1 -1
View File
@@ -38,7 +38,7 @@ const supportedImportFileTypes = [
}
},
{
type: 'alipay_csv',
type: 'alipay_web_csv',
name: 'Alipay (Web) Data Export File',
extensions: '.csv',
document: {