code refactor
This commit is contained in:
@@ -43,7 +43,7 @@ func (c *feideeMymoneyTransactionDataCsvImporter) ParseImportedData(ctx core.Con
|
||||
return nil, nil, nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
if len(allLines) <= 1 {
|
||||
if len(allLines) < 2 {
|
||||
log.Errorf(ctx, "[feidee_mymoney_transaction_data_csv_file_importer.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
|
||||
}
|
||||
@@ -71,36 +71,37 @@ func (c *feideeMymoneyTransactionDataCsvImporter) ParseImportedData(ctx core.Con
|
||||
return nil, nil, nil, nil, nil, nil, errs.ErrMissingRequiredFieldInHeaderRow
|
||||
}
|
||||
|
||||
newColumns := make([]datatable.DataTableColumn, 0, 11)
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_TRANSACTION_TYPE)
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_TRANSACTION_TIME)
|
||||
newColumns := make([]datatable.TransactionDataTableColumn, 0, 11)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME)
|
||||
|
||||
if categoryColumnExists {
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_CATEGORY)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_CATEGORY)
|
||||
}
|
||||
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_SUB_CATEGORY)
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_ACCOUNT_NAME)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_SUB_CATEGORY)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME)
|
||||
|
||||
if accountCurrencyColumnExists {
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_ACCOUNT_CURRENCY)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY)
|
||||
}
|
||||
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_AMOUNT)
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_RELATED_ACCOUNT_NAME)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_AMOUNT)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME)
|
||||
|
||||
if accountCurrencyColumnExists {
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_RELATED_ACCOUNT_CURRENCY)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_CURRENCY)
|
||||
}
|
||||
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_RELATED_AMOUNT)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_RELATED_AMOUNT)
|
||||
|
||||
if descriptionColumnExists {
|
||||
newColumns = append(newColumns, datatable.DATA_TABLE_DESCRIPTION)
|
||||
newColumns = append(newColumns, datatable.TRANSACTION_DATA_TABLE_DESCRIPTION)
|
||||
}
|
||||
|
||||
dataTable := datatable.CreateNewWritableDataTable(newColumns)
|
||||
transferTransactionsMap := make(map[string]map[datatable.DataTableColumn]string, 0)
|
||||
transactionRowParser := createFeideeMymoneyTransactionDataRowParser()
|
||||
dataTable := datatable.CreateNewWritableTransactionDataTableWithRowParser(newColumns, transactionRowParser)
|
||||
transferTransactionsMap := make(map[string]map[datatable.TransactionDataTableColumn]string, 0)
|
||||
|
||||
for i := 1; i < len(allLines); i++ {
|
||||
items := allLines[i]
|
||||
@@ -131,20 +132,20 @@ func (c *feideeMymoneyTransactionDataCsvImporter) ParseImportedData(ctx core.Con
|
||||
relatedIdColumnExists,
|
||||
)
|
||||
|
||||
transactionType := data[datatable.DATA_TABLE_TRANSACTION_TYPE]
|
||||
transactionType := data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE]
|
||||
|
||||
if transactionType == feideeMymoneyCsvFileTransactionTypeModifyBalanceText || transactionType == feideeMymoneyCsvFileTransactionTypeIncomeText || transactionType == feideeMymoneyCsvFileTransactionTypeExpenseText {
|
||||
if transactionType == feideeMymoneyCsvFileTransactionTypeModifyBalanceText {
|
||||
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_MODIFY_BALANCE]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_MODIFY_BALANCE]
|
||||
} else if transactionType == feideeMymoneyCsvFileTransactionTypeIncomeText {
|
||||
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME]
|
||||
} else if transactionType == feideeMymoneyCsvFileTransactionTypeExpenseText {
|
||||
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE]
|
||||
}
|
||||
|
||||
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
|
||||
data[datatable.DATA_TABLE_RELATED_ACCOUNT_CURRENCY] = ""
|
||||
data[datatable.DATA_TABLE_RELATED_AMOUNT] = ""
|
||||
data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = ""
|
||||
data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_CURRENCY] = ""
|
||||
data[datatable.TRANSACTION_DATA_TABLE_RELATED_AMOUNT] = ""
|
||||
dataTable.Add(data)
|
||||
} else if transactionType == feideeMymoneyCsvFileTransactionTypeTransferInText || transactionType == feideeMymoneyCsvFileTransactionTypeTransferOutText {
|
||||
if relatedId == "" {
|
||||
@@ -159,18 +160,18 @@ func (c *feideeMymoneyTransactionDataCsvImporter) ParseImportedData(ctx core.Con
|
||||
continue
|
||||
}
|
||||
|
||||
if transactionType == feideeMymoneyCsvFileTransactionTypeTransferInText && relatedData[datatable.DATA_TABLE_TRANSACTION_TYPE] == feideeMymoneyCsvFileTransactionTypeTransferOutText {
|
||||
relatedData[datatable.DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_TRANSFER]
|
||||
relatedData[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = data[datatable.DATA_TABLE_ACCOUNT_NAME]
|
||||
relatedData[datatable.DATA_TABLE_RELATED_ACCOUNT_CURRENCY] = data[datatable.DATA_TABLE_ACCOUNT_CURRENCY]
|
||||
relatedData[datatable.DATA_TABLE_RELATED_AMOUNT] = data[datatable.DATA_TABLE_AMOUNT]
|
||||
if transactionType == feideeMymoneyCsvFileTransactionTypeTransferInText && relatedData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] == feideeMymoneyCsvFileTransactionTypeTransferOutText {
|
||||
relatedData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_TRANSFER]
|
||||
relatedData[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME]
|
||||
relatedData[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_CURRENCY] = data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY]
|
||||
relatedData[datatable.TRANSACTION_DATA_TABLE_RELATED_AMOUNT] = data[datatable.TRANSACTION_DATA_TABLE_AMOUNT]
|
||||
dataTable.Add(relatedData)
|
||||
delete(transferTransactionsMap, relatedId)
|
||||
} else if transactionType == feideeMymoneyCsvFileTransactionTypeTransferOutText && relatedData[datatable.DATA_TABLE_TRANSACTION_TYPE] == feideeMymoneyCsvFileTransactionTypeTransferInText {
|
||||
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_TRANSFER]
|
||||
data[datatable.DATA_TABLE_RELATED_ACCOUNT_NAME] = relatedData[datatable.DATA_TABLE_ACCOUNT_NAME]
|
||||
data[datatable.DATA_TABLE_RELATED_ACCOUNT_CURRENCY] = relatedData[datatable.DATA_TABLE_ACCOUNT_CURRENCY]
|
||||
data[datatable.DATA_TABLE_RELATED_AMOUNT] = relatedData[datatable.DATA_TABLE_AMOUNT]
|
||||
} else if transactionType == feideeMymoneyCsvFileTransactionTypeTransferOutText && relatedData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] == feideeMymoneyCsvFileTransactionTypeTransferInText {
|
||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_TRANSFER]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME] = relatedData[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_CURRENCY] = relatedData[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_RELATED_AMOUNT] = relatedData[datatable.TRANSACTION_DATA_TABLE_AMOUNT]
|
||||
dataTable.Add(data)
|
||||
delete(transferTransactionsMap, relatedId)
|
||||
} else {
|
||||
@@ -188,11 +189,7 @@ func (c *feideeMymoneyTransactionDataCsvImporter) ParseImportedData(ctx core.Con
|
||||
return nil, nil, nil, nil, nil, nil, errs.ErrFoundRecordNotHasRelatedRecord
|
||||
}
|
||||
|
||||
dataTableImporter := datatable.CreateNewSimpleImporterFromWritableDataTableWithPostProcessFunc(
|
||||
dataTable,
|
||||
feideeMymoneyTransactionTypeNameMapping,
|
||||
feideeMymoneyTransactionDataImporterPostProcess,
|
||||
)
|
||||
dataTableImporter := datatable.CreateNewSimpleImporter(feideeMymoneyTransactionTypeNameMapping)
|
||||
|
||||
return dataTableImporter.ParseImportedData(ctx, user, dataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||
}
|
||||
@@ -253,40 +250,40 @@ func (c *feideeMymoneyTransactionDataCsvImporter) parseTransactionData(
|
||||
descriptionColumnExists bool,
|
||||
relatedIdColumnIdx int,
|
||||
relatedIdColumnExists bool,
|
||||
) (map[datatable.DataTableColumn]string, string) {
|
||||
data := make(map[datatable.DataTableColumn]string, 11)
|
||||
) (map[datatable.TransactionDataTableColumn]string, string) {
|
||||
data := make(map[datatable.TransactionDataTableColumn]string, 11)
|
||||
relatedId := ""
|
||||
|
||||
if timeColumnExists && timeColumnIdx < len(items) {
|
||||
data[datatable.DATA_TABLE_TRANSACTION_TIME] = items[timeColumnIdx]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = items[timeColumnIdx]
|
||||
}
|
||||
|
||||
if typeColumnExists && typeColumnIdx < len(items) {
|
||||
data[datatable.DATA_TABLE_TRANSACTION_TYPE] = items[typeColumnIdx]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = items[typeColumnIdx]
|
||||
}
|
||||
|
||||
if categoryColumnExists && categoryColumnIdx < len(items) {
|
||||
data[datatable.DATA_TABLE_CATEGORY] = items[categoryColumnIdx]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_CATEGORY] = items[categoryColumnIdx]
|
||||
}
|
||||
|
||||
if subCategoryColumnExists && subCategoryColumnIdx < len(items) {
|
||||
data[datatable.DATA_TABLE_SUB_CATEGORY] = items[subCategoryColumnIdx]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_SUB_CATEGORY] = items[subCategoryColumnIdx]
|
||||
}
|
||||
|
||||
if accountColumnExists && accountColumnIdx < len(items) {
|
||||
data[datatable.DATA_TABLE_ACCOUNT_NAME] = items[accountColumnIdx]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = items[accountColumnIdx]
|
||||
}
|
||||
|
||||
if accountCurrencyColumnExists && accountCurrencyColumnIdx < len(items) {
|
||||
data[datatable.DATA_TABLE_ACCOUNT_CURRENCY] = items[accountCurrencyColumnIdx]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY] = items[accountCurrencyColumnIdx]
|
||||
}
|
||||
|
||||
if amountColumnExists && amountColumnIdx < len(items) {
|
||||
data[datatable.DATA_TABLE_AMOUNT] = items[amountColumnIdx]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = items[amountColumnIdx]
|
||||
}
|
||||
|
||||
if descriptionColumnExists && descriptionColumnIdx < len(items) {
|
||||
data[datatable.DATA_TABLE_DESCRIPTION] = items[descriptionColumnIdx]
|
||||
data[datatable.TRANSACTION_DATA_TABLE_DESCRIPTION] = items[descriptionColumnIdx]
|
||||
}
|
||||
|
||||
if relatedIdColumnExists && relatedIdColumnIdx < len(items) {
|
||||
@@ -296,7 +293,7 @@ func (c *feideeMymoneyTransactionDataCsvImporter) parseTransactionData(
|
||||
return data, relatedId
|
||||
}
|
||||
|
||||
func (c *feideeMymoneyTransactionDataCsvImporter) getRelatedIds(transferTransactionsMap map[string]map[datatable.DataTableColumn]string) string {
|
||||
func (c *feideeMymoneyTransactionDataCsvImporter) getRelatedIds(transferTransactionsMap map[string]map[datatable.TransactionDataTableColumn]string) string {
|
||||
builder := strings.Builder{}
|
||||
|
||||
for relatedId := range transferTransactionsMap {
|
||||
|
||||
@@ -36,8 +36,8 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MinimumValidData(t *testi
|
||||
|
||||
assert.Equal(t, 6, len(allNewTransactions))
|
||||
assert.Equal(t, 2, len(allNewAccounts))
|
||||
assert.Equal(t, 1, len(allNewSubExpenseCategories))
|
||||
assert.Equal(t, 1, len(allNewSubIncomeCategories))
|
||||
assert.Equal(t, 2, len(allNewSubExpenseCategories))
|
||||
assert.Equal(t, 2, len(allNewSubIncomeCategories))
|
||||
assert.Equal(t, 1, len(allNewSubTransferCategories))
|
||||
assert.Equal(t, 0, len(allNewTags))
|
||||
|
||||
@@ -94,10 +94,16 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MinimumValidData(t *testi
|
||||
assert.Equal(t, "CNY", allNewAccounts[1].Currency)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubExpenseCategories[0].Uid)
|
||||
assert.Equal(t, "Test Category2", allNewSubExpenseCategories[0].Name)
|
||||
assert.Equal(t, "", allNewSubExpenseCategories[0].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubExpenseCategories[1].Uid)
|
||||
assert.Equal(t, "Test Category2", allNewSubExpenseCategories[1].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubIncomeCategories[0].Uid)
|
||||
assert.Equal(t, "Test Category", allNewSubIncomeCategories[0].Name)
|
||||
assert.Equal(t, "", allNewSubIncomeCategories[0].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubIncomeCategories[1].Uid)
|
||||
assert.Equal(t, "Test Category", allNewSubIncomeCategories[1].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubTransferCategories[0].Uid)
|
||||
assert.Equal(t, "Test Category3", allNewSubTransferCategories[0].Name)
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
package feidee
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
"github.com/shakinm/xlsReader/xls"
|
||||
|
||||
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||
)
|
||||
|
||||
// feideeMymoneyTransactionExcelFileDataTable defines the structure of feidee mymoney transaction plain text data table
|
||||
type feideeMymoneyTransactionExcelFileDataTable struct {
|
||||
workbook *xls.Workbook
|
||||
headerLineColumnNames []string
|
||||
}
|
||||
|
||||
// feideeMymoneyTransactionExcelFileDataRow defines the structure of feidee mymoney transaction plain text data row
|
||||
type feideeMymoneyTransactionExcelFileDataRow struct {
|
||||
sheet *xls.Sheet
|
||||
rowIndex int
|
||||
}
|
||||
|
||||
// feideeMymoneyTransactionExcelFileDataRowIterator defines the structure of feidee mymoney transaction plain text data row iterator
|
||||
type feideeMymoneyTransactionExcelFileDataRowIterator struct {
|
||||
dataTable *feideeMymoneyTransactionExcelFileDataTable
|
||||
currentTableIndex int
|
||||
currentRowIndexInTable int
|
||||
}
|
||||
|
||||
// DataRowCount returns the total count of data row
|
||||
func (t *feideeMymoneyTransactionExcelFileDataTable) DataRowCount() int {
|
||||
allSheets := t.workbook.GetSheets()
|
||||
totalDataRowCount := 0
|
||||
|
||||
for i := 0; i < len(allSheets); i++ {
|
||||
sheet := allSheets[i]
|
||||
|
||||
if sheet.GetNumberRows() <= 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
totalDataRowCount += sheet.GetNumberRows() - 1
|
||||
}
|
||||
|
||||
return totalDataRowCount
|
||||
}
|
||||
|
||||
// HeaderLineColumnNames returns the header column name list
|
||||
func (t *feideeMymoneyTransactionExcelFileDataTable) HeaderLineColumnNames() []string {
|
||||
return t.headerLineColumnNames
|
||||
}
|
||||
|
||||
// DataRowIterator returns the iterator of data row
|
||||
func (t *feideeMymoneyTransactionExcelFileDataTable) DataRowIterator() datatable.ImportedDataRowIterator {
|
||||
return &feideeMymoneyTransactionExcelFileDataRowIterator{
|
||||
dataTable: t,
|
||||
currentTableIndex: 0,
|
||||
currentRowIndexInTable: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid returns whether this row contains valid data for importing
|
||||
func (r *feideeMymoneyTransactionExcelFileDataRow) IsValid() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ColumnCount returns the total count of column in this data row
|
||||
func (r *feideeMymoneyTransactionExcelFileDataRow) ColumnCount() int {
|
||||
row, err := r.sheet.GetRow(r.rowIndex)
|
||||
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return len(row.GetCols())
|
||||
}
|
||||
|
||||
// GetData returns the data in the specified column index
|
||||
func (r *feideeMymoneyTransactionExcelFileDataRow) GetData(columnIndex int) string {
|
||||
row, err := r.sheet.GetRow(r.rowIndex)
|
||||
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
cell, err := row.GetCol(columnIndex)
|
||||
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return cell.GetString()
|
||||
}
|
||||
|
||||
// GetTime returns the time in the specified column index
|
||||
func (r *feideeMymoneyTransactionExcelFileDataRow) GetTime(columnIndex int, timezoneOffset int16) (time.Time, error) {
|
||||
str := r.GetData(columnIndex)
|
||||
|
||||
if utils.IsValidLongDateTimeFormat(str) {
|
||||
return utils.ParseFromLongDateTime(str, timezoneOffset)
|
||||
}
|
||||
|
||||
if utils.IsValidLongDateTimeWithoutSecondFormat(str) {
|
||||
return utils.ParseFromLongDateTimeWithoutSecond(str, timezoneOffset)
|
||||
}
|
||||
|
||||
if utils.IsValidLongDateFormat(str) {
|
||||
return utils.ParseFromLongDateTimeWithoutSecond(str+" 00:00", timezoneOffset)
|
||||
}
|
||||
|
||||
return time.Unix(0, 0), errs.ErrTransactionTimeInvalid
|
||||
}
|
||||
|
||||
// GetTimezoneOffset returns the time zone offset in the specified column index
|
||||
func (r *feideeMymoneyTransactionExcelFileDataRow) GetTimezoneOffset(columnIndex int) (*time.Location, error) {
|
||||
return nil, errs.ErrNotSupported
|
||||
}
|
||||
|
||||
// HasNext returns whether the iterator does not reach the end
|
||||
func (t *feideeMymoneyTransactionExcelFileDataRowIterator) HasNext() bool {
|
||||
allSheets := t.dataTable.workbook.GetSheets()
|
||||
|
||||
if t.currentTableIndex >= len(allSheets) {
|
||||
return false
|
||||
}
|
||||
|
||||
currentSheet := allSheets[t.currentTableIndex]
|
||||
|
||||
if t.currentRowIndexInTable+1 < currentSheet.GetNumberRows() {
|
||||
return true
|
||||
}
|
||||
|
||||
for i := t.currentTableIndex + 1; i < len(allSheets); i++ {
|
||||
sheet := allSheets[i]
|
||||
|
||||
if sheet.GetNumberRows() <= 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Next returns the next imported data row
|
||||
func (t *feideeMymoneyTransactionExcelFileDataRowIterator) Next(ctx core.Context, user *models.User) datatable.ImportedDataRow {
|
||||
allSheets := t.dataTable.workbook.GetSheets()
|
||||
currentRowIndexInTable := t.currentRowIndexInTable
|
||||
|
||||
for i := t.currentTableIndex; i < len(allSheets); i++ {
|
||||
sheet := allSheets[i]
|
||||
|
||||
if currentRowIndexInTable+1 < sheet.GetNumberRows() {
|
||||
t.currentRowIndexInTable++
|
||||
currentRowIndexInTable = t.currentRowIndexInTable
|
||||
break
|
||||
}
|
||||
|
||||
t.currentTableIndex++
|
||||
t.currentRowIndexInTable = 0
|
||||
currentRowIndexInTable = 0
|
||||
}
|
||||
|
||||
if t.currentTableIndex >= len(allSheets) {
|
||||
return nil
|
||||
}
|
||||
|
||||
currentSheet := allSheets[t.currentTableIndex]
|
||||
|
||||
if t.currentRowIndexInTable >= currentSheet.GetNumberRows() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &feideeMymoneyTransactionExcelFileDataRow{
|
||||
sheet: ¤tSheet,
|
||||
rowIndex: t.currentRowIndexInTable,
|
||||
}
|
||||
}
|
||||
|
||||
func createNewFeideeMymoneyTransactionExcelFileDataTable(data []byte) (*feideeMymoneyTransactionExcelFileDataTable, error) {
|
||||
reader := bytes.NewReader(data)
|
||||
workbook, err := xls.OpenReader(reader)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allSheets := workbook.GetSheets()
|
||||
var headerRowItems []string
|
||||
|
||||
for i := 0; i < len(allSheets); i++ {
|
||||
sheet := allSheets[i]
|
||||
|
||||
if sheet.GetNumberRows() < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
row, err := sheet.GetRow(0)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cells := row.GetCols()
|
||||
|
||||
if i == 0 {
|
||||
for j := 0; j < len(cells); j++ {
|
||||
headerItem := cells[j].GetString()
|
||||
|
||||
if headerItem == "" {
|
||||
break
|
||||
}
|
||||
|
||||
headerRowItems = append(headerRowItems, headerItem)
|
||||
}
|
||||
} else {
|
||||
for j := 0; j < min(len(cells), len(headerRowItems)); j++ {
|
||||
headerItem := cells[j].GetString()
|
||||
|
||||
if headerItem != headerRowItems[j] {
|
||||
return nil, errs.ErrFieldsInMultiTableAreDifferent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &feideeMymoneyTransactionExcelFileDataTable{
|
||||
workbook: &workbook,
|
||||
headerLineColumnNames: headerRowItems,
|
||||
}, nil
|
||||
}
|
||||
@@ -2,19 +2,18 @@ package feidee
|
||||
|
||||
import (
|
||||
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||
)
|
||||
|
||||
var feideeMymoneyDataColumnNameMapping = map[datatable.DataTableColumn]string{
|
||||
datatable.DATA_TABLE_TRANSACTION_TIME: "日期",
|
||||
datatable.DATA_TABLE_TRANSACTION_TYPE: "交易类型",
|
||||
datatable.DATA_TABLE_CATEGORY: "分类",
|
||||
datatable.DATA_TABLE_SUB_CATEGORY: "子分类",
|
||||
datatable.DATA_TABLE_ACCOUNT_NAME: "账户1",
|
||||
datatable.DATA_TABLE_AMOUNT: "金额",
|
||||
datatable.DATA_TABLE_RELATED_ACCOUNT_NAME: "账户2",
|
||||
datatable.DATA_TABLE_DESCRIPTION: "备注",
|
||||
var feideeMymoneyDataColumnNameMapping = map[datatable.TransactionDataTableColumn]string{
|
||||
datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME: "日期",
|
||||
datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE: "交易类型",
|
||||
datatable.TRANSACTION_DATA_TABLE_CATEGORY: "分类",
|
||||
datatable.TRANSACTION_DATA_TABLE_SUB_CATEGORY: "子分类",
|
||||
datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME: "账户1",
|
||||
datatable.TRANSACTION_DATA_TABLE_AMOUNT: "金额",
|
||||
datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME: "账户2",
|
||||
datatable.TRANSACTION_DATA_TABLE_DESCRIPTION: "备注",
|
||||
}
|
||||
|
||||
var feideeMymoneyTransactionTypeNameMapping = map[models.TransactionType]string{
|
||||
@@ -23,16 +22,3 @@ var feideeMymoneyTransactionTypeNameMapping = map[models.TransactionType]string{
|
||||
models.TRANSACTION_TYPE_EXPENSE: "支出",
|
||||
models.TRANSACTION_TYPE_TRANSFER: "转账",
|
||||
}
|
||||
|
||||
func feideeMymoneyTransactionDataImporterPostProcess(ctx core.Context, transaction *models.ImportTransaction) error {
|
||||
if transaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
|
||||
if transaction.Amount >= 0 {
|
||||
transaction.Type = models.TRANSACTION_DB_TYPE_INCOME
|
||||
} else if transaction.Amount < 0 {
|
||||
transaction.Amount = -transaction.Amount
|
||||
transaction.Type = models.TRANSACTION_DB_TYPE_EXPENSE
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package feidee
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||
)
|
||||
|
||||
// feideeMymoneyTransactionDataRowParser defines the structure of feidee mymoney transaction data row parser
|
||||
type feideeMymoneyTransactionDataRowParser struct {
|
||||
}
|
||||
|
||||
// GetAddedColumns returns the added columns after converting the data row
|
||||
func (p *feideeMymoneyTransactionDataRowParser) GetAddedColumns() []datatable.TransactionDataTableColumn {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse returns the converted transaction data row
|
||||
func (p *feideeMymoneyTransactionDataRowParser) Parse(data map[datatable.TransactionDataTableColumn]string) (rowData map[datatable.TransactionDataTableColumn]string, rowDataValid bool, err error) {
|
||||
rowData = make(map[datatable.TransactionDataTableColumn]string, len(data))
|
||||
|
||||
for column, value := range data {
|
||||
rowData[column] = value
|
||||
}
|
||||
|
||||
if rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] != "" {
|
||||
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = p.getLongDateTime(rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME])
|
||||
}
|
||||
|
||||
if rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] == feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_MODIFY_BALANCE] {
|
||||
amount, err := utils.ParseAmount(rowData[datatable.TRANSACTION_DATA_TABLE_AMOUNT])
|
||||
|
||||
if err != nil {
|
||||
return nil, false, errs.ErrAmountInvalid
|
||||
}
|
||||
|
||||
if amount >= 0 {
|
||||
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_INCOME]
|
||||
} else {
|
||||
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = feideeMymoneyTransactionTypeNameMapping[models.TRANSACTION_TYPE_EXPENSE]
|
||||
rowData[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(-amount)
|
||||
}
|
||||
}
|
||||
|
||||
return rowData, true, nil
|
||||
}
|
||||
|
||||
// Parse returns the converted transaction data row
|
||||
func (p *feideeMymoneyTransactionDataRowParser) getLongDateTime(str string) string {
|
||||
if utils.IsValidLongDateTimeFormat(str) {
|
||||
return str
|
||||
}
|
||||
|
||||
utcTimezone := time.UTC
|
||||
utcTimezoneOffsetMinutes := utils.GetTimezoneOffsetMinutes(utcTimezone)
|
||||
|
||||
if utils.IsValidLongDateTimeWithoutSecondFormat(str) {
|
||||
dateTime, err := utils.ParseFromLongDateTimeWithoutSecond(str, utcTimezoneOffsetMinutes)
|
||||
|
||||
if err == nil {
|
||||
return utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), utcTimezone)
|
||||
}
|
||||
}
|
||||
|
||||
if utils.IsValidLongDateFormat(str) {
|
||||
dateTime, err := utils.ParseFromLongDateTimeWithoutSecond(str+" 00:00", utcTimezoneOffsetMinutes)
|
||||
|
||||
if err == nil {
|
||||
return utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), utcTimezone)
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// createFeideeMymoneyTransactionDataRowParser returns feidee mymoney transaction data row parser
|
||||
func createFeideeMymoneyTransactionDataRowParser() datatable.TransactionDataRowParser {
|
||||
return &feideeMymoneyTransactionDataRowParser{}
|
||||
}
|
||||
@@ -18,17 +18,15 @@ var (
|
||||
|
||||
// ParseImportedData returns the imported data by parsing the feidee mymoney transaction xls data
|
||||
func (c *feideeMymoneyTransactionDataXlsImporter) 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) {
|
||||
dataTable, err := createNewFeideeMymoneyTransactionExcelFileDataTable(data)
|
||||
dataTable, err := datatable.CreateNewDefaultExcelFileImportedDataTable(data)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
dataTableImporter := datatable.CreateNewSimpleImporterWithPostProcessFunc(
|
||||
feideeMymoneyDataColumnNameMapping,
|
||||
feideeMymoneyTransactionTypeNameMapping,
|
||||
feideeMymoneyTransactionDataImporterPostProcess,
|
||||
)
|
||||
transactionRowParser := createFeideeMymoneyTransactionDataRowParser()
|
||||
transactionDataTable := datatable.CreateImportedTransactionDataTableWithRowParser(dataTable, feideeMymoneyDataColumnNameMapping, transactionRowParser)
|
||||
dataTableImporter := datatable.CreateNewSimpleImporter(feideeMymoneyTransactionTypeNameMapping)
|
||||
|
||||
return dataTableImporter.ParseImportedData(ctx, user, dataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ func TestFeideeMymoneyTransactionDataXlsImporterParseImportedData_MinimumValidDa
|
||||
|
||||
assert.Equal(t, 7, len(allNewTransactions))
|
||||
assert.Equal(t, 2, len(allNewAccounts))
|
||||
assert.Equal(t, 2, len(allNewSubExpenseCategories))
|
||||
assert.Equal(t, 2, len(allNewSubIncomeCategories))
|
||||
assert.Equal(t, 3, len(allNewSubExpenseCategories))
|
||||
assert.Equal(t, 3, len(allNewSubIncomeCategories))
|
||||
assert.Equal(t, 1, len(allNewSubTransferCategories))
|
||||
assert.Equal(t, 0, len(allNewTags))
|
||||
|
||||
@@ -95,16 +95,22 @@ func TestFeideeMymoneyTransactionDataXlsImporterParseImportedData_MinimumValidDa
|
||||
assert.Equal(t, "CNY", allNewAccounts[1].Currency)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubExpenseCategories[0].Uid)
|
||||
assert.Equal(t, "Test Category2", allNewSubExpenseCategories[0].Name)
|
||||
assert.Equal(t, "", allNewSubExpenseCategories[0].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubExpenseCategories[1].Uid)
|
||||
assert.Equal(t, "Test Category4", allNewSubExpenseCategories[1].Name)
|
||||
assert.Equal(t, "Test Category2", allNewSubExpenseCategories[1].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubExpenseCategories[2].Uid)
|
||||
assert.Equal(t, "Test Category4", allNewSubExpenseCategories[2].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubIncomeCategories[0].Uid)
|
||||
assert.Equal(t, "Test Category", allNewSubIncomeCategories[0].Name)
|
||||
assert.Equal(t, "", allNewSubIncomeCategories[0].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubIncomeCategories[1].Uid)
|
||||
assert.Equal(t, "Test Category5", allNewSubIncomeCategories[1].Name)
|
||||
assert.Equal(t, "Test Category", allNewSubIncomeCategories[1].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubIncomeCategories[2].Uid)
|
||||
assert.Equal(t, "Test Category5", allNewSubIncomeCategories[2].Name)
|
||||
|
||||
assert.Equal(t, int64(1234567890), allNewSubTransferCategories[0].Uid)
|
||||
assert.Equal(t, "Test Category3", allNewSubTransferCategories[0].Name)
|
||||
|
||||
Reference in New Issue
Block a user