diff --git a/pkg/converters/data_table_transaction_data_converter.go b/pkg/converters/data_table_transaction_data_converter.go index dc162ff1..6fb3dda8 100644 --- a/pkg/converters/data_table_transaction_data_converter.go +++ b/pkg/converters/data_table_transaction_data_converter.go @@ -35,10 +35,19 @@ const ( DATA_TABLE_DESCRIPTION DataTableColumn = 14 ) -// DataTableTransactionDataConverter defines the structure of data table importer for transaction data -type DataTableTransactionDataConverter struct { +// DataTableTransactionDataExporter defines the structure of plain text data table exporter for transaction data +type DataTableTransactionDataExporter struct { + dataColumnMapping map[DataTableColumn]string + transactionTypeMapping map[models.TransactionDbType]string + columnSeparator string + lineSeparator string + geoLocationSeparator string + transactionTagSeparator string +} + +// DataTableTransactionDataImporter defines the structure of plain text data table importer for transaction data +type DataTableTransactionDataImporter struct { dataColumnMapping map[DataTableColumn]string - transactionTypeMapping map[models.TransactionDbType]string transactionTypeNameMapping map[string]models.TransactionDbType columnSeparator string lineSeparator string @@ -46,7 +55,7 @@ type DataTableTransactionDataConverter struct { transactionTagSeparator string } -func (c *DataTableTransactionDataConverter) buildExportedContent(ctx core.Context, dataTableBuilder DataTableBuilder, uid int64, transactions []*models.Transaction, accountMap map[int64]*models.Account, categoryMap map[int64]*models.TransactionCategory, tagMap map[int64]*models.TransactionTag, allTagIndexes map[int64][]int64) error { +func (c *DataTableTransactionDataExporter) buildExportedContent(ctx core.Context, dataTableBuilder DataTableBuilder, uid int64, transactions []*models.Transaction, accountMap map[int64]*models.Account, categoryMap map[int64]*models.TransactionCategory, tagMap map[int64]*models.TransactionTag, allTagIndexes map[int64][]int64) error { for i := 0; i < len(transactions); i++ { transaction := transactions[i] @@ -82,7 +91,112 @@ func (c *DataTableTransactionDataConverter) buildExportedContent(ctx core.Contex return nil } -func (c *DataTableTransactionDataConverter) parseImportedData(ctx core.Context, user *models.User, dataTable ImportedDataTable, defaultTimezoneOffset int16, accountMap map[string]*models.Account, categoryMap map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionTag, error) { +func (c *DataTableTransactionDataExporter) getDisplayTransactionTypeName(transactionDbType models.TransactionDbType) string { + transactionTypeName, exists := c.transactionTypeMapping[transactionDbType] + + if !exists { + return "" + } + + return transactionTypeName +} + +func (c *DataTableTransactionDataExporter) getExportedTransactionCategoryName(categoryId int64, categoryMap map[int64]*models.TransactionCategory) string { + category, exists := categoryMap[categoryId] + + if !exists { + return "" + } + + if category.ParentCategoryId == 0 { + return c.replaceDelimiters(category.Name) + } + + parentCategory, exists := categoryMap[category.ParentCategoryId] + + if !exists { + return "" + } + + return c.replaceDelimiters(parentCategory.Name) +} + +func (c *DataTableTransactionDataExporter) getExportedTransactionSubCategoryName(categoryId int64, categoryMap map[int64]*models.TransactionCategory) string { + category, exists := categoryMap[categoryId] + + if exists { + return c.replaceDelimiters(category.Name) + } else { + return "" + } +} + +func (c *DataTableTransactionDataExporter) getExportedAccountName(accountId int64, accountMap map[int64]*models.Account) string { + account, exists := accountMap[accountId] + + if exists { + return c.replaceDelimiters(account.Name) + } else { + return "" + } +} + +func (c *DataTableTransactionDataExporter) getAccountCurrency(accountId int64, accountMap map[int64]*models.Account) string { + account, exists := accountMap[accountId] + + if exists { + return c.replaceDelimiters(account.Currency) + } else { + return "" + } +} + +func (c *DataTableTransactionDataExporter) getExportedGeographicLocation(transaction *models.Transaction) string { + if transaction.GeoLongitude != 0 || transaction.GeoLatitude != 0 { + return fmt.Sprintf("%f%s%f", transaction.GeoLongitude, c.geoLocationSeparator, transaction.GeoLatitude) + } + + return "" +} + +func (c *DataTableTransactionDataExporter) getExportedTags(transactionId int64, allTagIndexes map[int64][]int64, tagMap map[int64]*models.TransactionTag) string { + tagIndexes, exists := allTagIndexes[transactionId] + + if !exists { + return "" + } + + var ret strings.Builder + + for i := 0; i < len(tagIndexes); i++ { + tagIndex := tagIndexes[i] + tag, exists := tagMap[tagIndex] + + if !exists { + continue + } + + if ret.Len() > 0 { + ret.WriteString(c.transactionTagSeparator) + } + + ret.WriteString(strings.Replace(tag.Name, c.transactionTagSeparator, " ", -1)) + } + + return c.replaceDelimiters(ret.String()) +} + +func (c *DataTableTransactionDataExporter) replaceDelimiters(text string) string { + text = strings.Replace(text, "\r\n", " ", -1) + text = strings.Replace(text, "\r", " ", -1) + text = strings.Replace(text, "\n", " ", -1) + text = strings.Replace(text, c.columnSeparator, " ", -1) + text = strings.Replace(text, c.lineSeparator, " ", -1) + + return text +} + +func (c *DataTableTransactionDataImporter) parseImportedData(ctx core.Context, user *models.User, dataTable ImportedDataTable, defaultTimezoneOffset int16, accountMap map[string]*models.Account, categoryMap map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionTag, error) { if dataTable.DataRowCount() < 1 { log.Errorf(ctx, "[data_table_transaction_data_converter.parseImportedData] cannot parse import data for user \"uid:%d\", because data table row count is less 1", user.Uid) return nil, nil, nil, nil, errs.ErrOperationFailed @@ -389,7 +503,7 @@ func (c *DataTableTransactionDataConverter) parseImportedData(ctx core.Context, return allNewTransactions, allNewAccounts, allNewSubCategories, allNewTags, nil } -func (c *DataTableTransactionDataConverter) getTransactionDbType(transactionTypeName string) (models.TransactionDbType, error) { +func (c *DataTableTransactionDataImporter) getTransactionDbType(transactionTypeName string) (models.TransactionDbType, error) { transactionType, exists := c.transactionTypeNameMapping[transactionTypeName] if !exists { @@ -399,7 +513,7 @@ func (c *DataTableTransactionDataConverter) getTransactionDbType(transactionType return transactionType, nil } -func (c *DataTableTransactionDataConverter) getTransactionCategoryType(transactionType models.TransactionDbType) (models.TransactionCategoryType, error) { +func (c *DataTableTransactionDataImporter) getTransactionCategoryType(transactionType models.TransactionDbType) (models.TransactionCategoryType, error) { if transactionType == models.TRANSACTION_DB_TYPE_INCOME { return models.CATEGORY_TYPE_INCOME, nil } else if transactionType == models.TRANSACTION_DB_TYPE_EXPENSE { @@ -411,112 +525,7 @@ func (c *DataTableTransactionDataConverter) getTransactionCategoryType(transacti } } -func (c *DataTableTransactionDataConverter) getDisplayTransactionTypeName(transactionDbType models.TransactionDbType) string { - transactionTypeName, exists := c.transactionTypeMapping[transactionDbType] - - if !exists { - return "" - } - - return transactionTypeName -} - -func (c *DataTableTransactionDataConverter) getExportedTransactionCategoryName(categoryId int64, categoryMap map[int64]*models.TransactionCategory) string { - category, exists := categoryMap[categoryId] - - if !exists { - return "" - } - - if category.ParentCategoryId == 0 { - return c.replaceDelimiters(category.Name) - } - - parentCategory, exists := categoryMap[category.ParentCategoryId] - - if !exists { - return "" - } - - return c.replaceDelimiters(parentCategory.Name) -} - -func (c *DataTableTransactionDataConverter) getExportedTransactionSubCategoryName(categoryId int64, categoryMap map[int64]*models.TransactionCategory) string { - category, exists := categoryMap[categoryId] - - if exists { - return c.replaceDelimiters(category.Name) - } else { - return "" - } -} - -func (c *DataTableTransactionDataConverter) getExportedAccountName(accountId int64, accountMap map[int64]*models.Account) string { - account, exists := accountMap[accountId] - - if exists { - return c.replaceDelimiters(account.Name) - } else { - return "" - } -} - -func (c *DataTableTransactionDataConverter) getAccountCurrency(accountId int64, accountMap map[int64]*models.Account) string { - account, exists := accountMap[accountId] - - if exists { - return c.replaceDelimiters(account.Currency) - } else { - return "" - } -} - -func (c *DataTableTransactionDataConverter) getExportedGeographicLocation(transaction *models.Transaction) string { - if transaction.GeoLongitude != 0 || transaction.GeoLatitude != 0 { - return fmt.Sprintf("%f%s%f", transaction.GeoLongitude, c.geoLocationSeparator, transaction.GeoLatitude) - } - - return "" -} - -func (c *DataTableTransactionDataConverter) getExportedTags(transactionId int64, allTagIndexes map[int64][]int64, tagMap map[int64]*models.TransactionTag) string { - tagIndexes, exists := allTagIndexes[transactionId] - - if !exists { - return "" - } - - var ret strings.Builder - - for i := 0; i < len(tagIndexes); i++ { - tagIndex := tagIndexes[i] - tag, exists := tagMap[tagIndex] - - if !exists { - continue - } - - if ret.Len() > 0 { - ret.WriteString(c.transactionTagSeparator) - } - - ret.WriteString(strings.Replace(tag.Name, c.transactionTagSeparator, " ", -1)) - } - - return c.replaceDelimiters(ret.String()) -} - -func (c *DataTableTransactionDataConverter) replaceDelimiters(text string) string { - text = strings.Replace(text, "\r\n", " ", -1) - text = strings.Replace(text, "\r", " ", -1) - text = strings.Replace(text, "\n", " ", -1) - text = strings.Replace(text, c.columnSeparator, " ", -1) - text = strings.Replace(text, c.lineSeparator, " ", -1) - - return text -} - -func (c *DataTableTransactionDataConverter) createNewAccountModel(uid int64, accountName string, currency string) *models.Account { +func (c *DataTableTransactionDataImporter) createNewAccountModel(uid int64, accountName string, currency string) *models.Account { return &models.Account{ Uid: uid, Name: accountName, @@ -524,7 +533,7 @@ func (c *DataTableTransactionDataConverter) createNewAccountModel(uid int64, acc } } -func (c *DataTableTransactionDataConverter) createNewTransactionCategoryModel(uid int64, categoryName string, transactionCategoryType models.TransactionCategoryType) *models.TransactionCategory { +func (c *DataTableTransactionDataImporter) createNewTransactionCategoryModel(uid int64, categoryName string, transactionCategoryType models.TransactionCategoryType) *models.TransactionCategory { return &models.TransactionCategory{ Uid: uid, Name: categoryName, @@ -532,7 +541,7 @@ func (c *DataTableTransactionDataConverter) createNewTransactionCategoryModel(ui } } -func (c *DataTableTransactionDataConverter) createNewTransactionTagModel(uid int64, tagName string) *models.TransactionTag { +func (c *DataTableTransactionDataImporter) createNewTransactionTagModel(uid int64, tagName string) *models.TransactionTag { return &models.TransactionTag{ Uid: uid, Name: tagName, diff --git a/pkg/converters/ezbookkeeping_transaction_data_csv_file_converter.go b/pkg/converters/ezbookkeeping_transaction_data_csv_file_converter.go index 82f56898..ef8969bc 100644 --- a/pkg/converters/ezbookkeeping_transaction_data_csv_file_converter.go +++ b/pkg/converters/ezbookkeeping_transaction_data_csv_file_converter.go @@ -2,23 +2,33 @@ package converters // ezBookKeepingTransactionDataCSVFileConverter defines the structure of CSV file converter type ezBookKeepingTransactionDataCSVFileConverter struct { - ezBookKeepingTransactionDataPlainTextConverter + ezBookKeepingTransactionDataPlainTextExporter + ezBookKeepingTransactionDataPlainTextImporter } // Initialize an ezbookkeeping transaction data csv file converter singleton instance var ( EzBookKeepingTransactionDataCSVFileConverter = &ezBookKeepingTransactionDataCSVFileConverter{ - ezBookKeepingTransactionDataPlainTextConverter{ - DataTableTransactionDataConverter: DataTableTransactionDataConverter{ + ezBookKeepingTransactionDataPlainTextExporter{ + DataTableTransactionDataExporter: DataTableTransactionDataExporter{ + dataColumnMapping: ezbookkeepingDataColumnNameMapping, + transactionTypeMapping: ezbookkeepingTransactionTypeNameMapping, + columnSeparator: ",", + lineSeparator: "\n", + geoLocationSeparator: " ", + transactionTagSeparator: ";", + }, + columns: ezbookkeepingDataColumns, + }, + ezBookKeepingTransactionDataPlainTextImporter{ + DataTableTransactionDataImporter: DataTableTransactionDataImporter{ dataColumnMapping: ezbookkeepingDataColumnNameMapping, - transactionTypeMapping: ezbookkeepingTransactionTypeNameMapping, transactionTypeNameMapping: ezbookkeepingNameTransactionTypeMapping, columnSeparator: ",", lineSeparator: "\n", geoLocationSeparator: " ", transactionTagSeparator: ";", }, - columns: ezbookkeepingDataColumns, }, } ) diff --git a/pkg/converters/ezbookkeeping_transaction_data_plain_text_converter.go b/pkg/converters/ezbookkeeping_transaction_data_plain_text_converter.go index 63088898..1147d600 100644 --- a/pkg/converters/ezbookkeeping_transaction_data_plain_text_converter.go +++ b/pkg/converters/ezbookkeeping_transaction_data_plain_text_converter.go @@ -5,12 +5,17 @@ import ( "github.com/mayswind/ezbookkeeping/pkg/models" ) -// ezBookKeepingTransactionDataPlainTextConverter defines the structure of plain file converter for transaction data -type ezBookKeepingTransactionDataPlainTextConverter struct { - DataTableTransactionDataConverter +// ezBookKeepingTransactionDataPlainTextExporter defines the structure of ezbookkeeping plain text exporter for transaction data +type ezBookKeepingTransactionDataPlainTextExporter struct { + DataTableTransactionDataExporter columns []DataTableColumn } +// ezBookKeepingTransactionDataPlainTextImporter defines the structure of ezbookkeeping plain text importer for transaction data +type ezBookKeepingTransactionDataPlainTextImporter struct { + DataTableTransactionDataImporter +} + var ezbookkeepingDataColumnNameMapping = map[DataTableColumn]string{ DATA_TABLE_TRANSACTION_TIME: "Time", DATA_TABLE_TRANSACTION_TIMEZONE: "Timezone", @@ -61,7 +66,7 @@ var ezbookkeepingDataColumns = []DataTableColumn{ } // ToExportedContent returns the exported transaction plain text data -func (c *ezBookKeepingTransactionDataPlainTextConverter) ToExportedContent(ctx core.Context, uid int64, transactions []*models.Transaction, accountMap map[int64]*models.Account, categoryMap map[int64]*models.TransactionCategory, tagMap map[int64]*models.TransactionTag, allTagIndexes map[int64][]int64) ([]byte, error) { +func (c *ezBookKeepingTransactionDataPlainTextExporter) ToExportedContent(ctx core.Context, uid int64, transactions []*models.Transaction, accountMap map[int64]*models.Account, categoryMap map[int64]*models.TransactionCategory, tagMap map[int64]*models.TransactionTag, allTagIndexes map[int64][]int64) ([]byte, error) { dataTableBuilder := createNewezbookkeepingTransactionPlainTextDataTableBuilder(len(transactions), c.columns, c.dataColumnMapping, c.columnSeparator, c.lineSeparator) err := c.buildExportedContent(ctx, dataTableBuilder, uid, transactions, accountMap, categoryMap, tagMap, allTagIndexes) @@ -73,7 +78,7 @@ func (c *ezBookKeepingTransactionDataPlainTextConverter) ToExportedContent(ctx c } // ParseImportedData returns the imported data by parsing the transaction plain text data -func (c *ezBookKeepingTransactionDataPlainTextConverter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, categoryMap map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionTag, error) { +func (c *ezBookKeepingTransactionDataPlainTextImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, categoryMap map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionTag, error) { dataTable, err := createNewezbookkeepingTransactionPlainTextDataTable(string(data), c.columnSeparator, c.lineSeparator) if err != nil { diff --git a/pkg/converters/ezbookkeeping_transaction_data_tsv_file_converter.go b/pkg/converters/ezbookkeeping_transaction_data_tsv_file_converter.go index c8cf3850..1060c3dc 100644 --- a/pkg/converters/ezbookkeeping_transaction_data_tsv_file_converter.go +++ b/pkg/converters/ezbookkeeping_transaction_data_tsv_file_converter.go @@ -2,23 +2,33 @@ package converters // ezBookKeepingTransactionDataTSVFileConverter defines the structure of TSV file converter type ezBookKeepingTransactionDataTSVFileConverter struct { - ezBookKeepingTransactionDataPlainTextConverter + ezBookKeepingTransactionDataPlainTextExporter + ezBookKeepingTransactionDataPlainTextImporter } // Initialize an ezbookkeeping transaction data tsv file converter singleton instance var ( EzBookKeepingTransactionDataTSVFileConverter = &ezBookKeepingTransactionDataTSVFileConverter{ - ezBookKeepingTransactionDataPlainTextConverter{ - DataTableTransactionDataConverter: DataTableTransactionDataConverter{ + ezBookKeepingTransactionDataPlainTextExporter{ + DataTableTransactionDataExporter: DataTableTransactionDataExporter{ + dataColumnMapping: ezbookkeepingDataColumnNameMapping, + transactionTypeMapping: ezbookkeepingTransactionTypeNameMapping, + columnSeparator: "\t", + lineSeparator: "\n", + geoLocationSeparator: " ", + transactionTagSeparator: ";", + }, + columns: ezbookkeepingDataColumns, + }, + ezBookKeepingTransactionDataPlainTextImporter{ + DataTableTransactionDataImporter: DataTableTransactionDataImporter{ dataColumnMapping: ezbookkeepingDataColumnNameMapping, - transactionTypeMapping: ezbookkeepingTransactionTypeNameMapping, transactionTypeNameMapping: ezbookkeepingNameTransactionTypeMapping, columnSeparator: "\t", lineSeparator: "\n", geoLocationSeparator: " ", transactionTagSeparator: ";", }, - columns: ezbookkeepingDataColumns, }, } )