support import transaction tags
This commit is contained in:
@@ -1158,6 +1158,8 @@ func (a *TransactionsApi) TransactionImportHandler(c *core.WebContext) (any, *er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newTransactionTagIdsMap := make(map[int][]int64, len(transactionImportReq.Transactions))
|
||||||
|
|
||||||
for i := 0; i < len(transactionImportReq.Transactions); i++ {
|
for i := 0; i < len(transactionImportReq.Transactions); i++ {
|
||||||
transactionCreateReq := transactionImportReq.Transactions[i]
|
transactionCreateReq := transactionImportReq.Transactions[i]
|
||||||
tagIds, err := utils.StringArrayToInt64Array(transactionCreateReq.TagIds)
|
tagIds, err := utils.StringArrayToInt64Array(transactionCreateReq.TagIds)
|
||||||
@@ -1193,6 +1195,8 @@ func (a *TransactionsApi) TransactionImportHandler(c *core.WebContext) (any, *er
|
|||||||
log.Warnf(c, "[transactions.TransactionImportHandler] non-transfer transaction \"index:%d\" destination amount cannot be set", i)
|
log.Warnf(c, "[transactions.TransactionImportHandler] non-transfer transaction \"index:%d\" destination amount cannot be set", i)
|
||||||
return nil, errs.ErrTransactionDestinationAmountCannotBeSet
|
return nil, errs.ErrTransactionDestinationAmountCannotBeSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newTransactionTagIdsMap[i] = tagIds
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := a.users.GetUserById(c, uid)
|
user, err := a.users.GetUserById(c, uid)
|
||||||
@@ -1219,7 +1223,7 @@ func (a *TransactionsApi) TransactionImportHandler(c *core.WebContext) (any, *er
|
|||||||
newTransactions[i] = transaction
|
newTransactions[i] = transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.transactions.BatchCreateTransactions(c, user.Uid, newTransactions)
|
err = a.transactions.BatchCreateTransactions(c, user.Uid, newTransactions, newTransactionTagIdsMap)
|
||||||
count := len(newTransactions)
|
count := len(newTransactions)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+11
-3
@@ -693,14 +693,14 @@ func (l *UserDataCli) ImportTransaction(c *core.CliContext, username string, fil
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
newTransactions, newAccounts, newCategories, newTags, err := dataImporter.ParseImportedData(c, user, data, utils.GetTimezoneOffsetMinutes(time.Local), accountMap, categoryMap, tagMap)
|
parsedTransactions, newAccounts, newCategories, newTags, err := dataImporter.ParseImportedData(c, user, data, utils.GetTimezoneOffsetMinutes(time.Local), accountMap, categoryMap, tagMap)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.BootErrorf(c, "[user_data.ImportTransaction] failed to parse imported data for \"%s\", because %s", username, err.Error())
|
log.BootErrorf(c, "[user_data.ImportTransaction] failed to parse imported data for \"%s\", because %s", username, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(newTransactions) < 1 {
|
if len(parsedTransactions) < 1 {
|
||||||
log.BootErrorf(c, "[user_data.ImportTransaction] there are no transactions in import file")
|
log.BootErrorf(c, "[user_data.ImportTransaction] there are no transactions in import file")
|
||||||
return errs.ErrOperationFailed
|
return errs.ErrOperationFailed
|
||||||
}
|
}
|
||||||
@@ -720,7 +720,15 @@ func (l *UserDataCli) ImportTransaction(c *core.CliContext, username string, fil
|
|||||||
return errs.ErrOperationFailed
|
return errs.ErrOperationFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
err = l.transactions.BatchCreateTransactions(c, user.Uid, newTransactions.ToTransactionsList())
|
newTransactions := parsedTransactions.ToTransactionsList()
|
||||||
|
newTransactionTagIdsMap, err := parsedTransactions.ToTransactionTagIdsMap()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.BootErrorf(c, "[user_data.ImportTransaction] failed to get transaction tag ids map, because %s", err.Error())
|
||||||
|
return errs.ErrOperationFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
err = l.transactions.BatchCreateTransactions(c, user.Uid, newTransactions, newTransactionTagIdsMap)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.BootErrorf(c, "[user_data.ImportTransaction] failed to create transaction, because %s", err.Error())
|
log.BootErrorf(c, "[user_data.ImportTransaction] failed to create transaction, because %s", err.Error())
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ func (s ImportedTransactionSlice) Less(i, j int) bool {
|
|||||||
return s[i].TransactionTime < s[j].TransactionTime
|
return s[i].TransactionTime < s[j].TransactionTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTransactionsList returns the a list of transactions
|
// ToTransactionsList returns a list of transaction models
|
||||||
func (s ImportedTransactionSlice) ToTransactionsList() []*Transaction {
|
func (s ImportedTransactionSlice) ToTransactionsList() []*Transaction {
|
||||||
transactions := make([]*Transaction, s.Len())
|
transactions := make([]*Transaction, s.Len())
|
||||||
|
|
||||||
@@ -126,6 +126,23 @@ func (s ImportedTransactionSlice) ToTransactionsList() []*Transaction {
|
|||||||
return transactions
|
return transactions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToTransactionTagIdsMap returns a list of transaction tag ids
|
||||||
|
func (s ImportedTransactionSlice) ToTransactionTagIdsMap() (map[int][]int64, error) {
|
||||||
|
transactionTagIdsMap := make(map[int][]int64, s.Len())
|
||||||
|
|
||||||
|
for i := 0; i < s.Len(); i++ {
|
||||||
|
tagIds, err := utils.StringArrayToInt64Array(s[i].TagIds)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionTagIdsMap[i] = tagIds
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactionTagIdsMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ToImportTransactionResponseList returns the a list of view-objects according to imported transaction data
|
// ToImportTransactionResponseList returns the a list of view-objects according to imported transaction data
|
||||||
func (s ImportedTransactionSlice) ToImportTransactionResponseList() []*ImportTransactionResponse {
|
func (s ImportedTransactionSlice) ToImportTransactionResponseList() []*ImportTransactionResponse {
|
||||||
transactionResps := make([]*ImportTransactionResponse, 0, s.Len())
|
transactionResps := make([]*ImportTransactionResponse, 0, s.Len())
|
||||||
|
|||||||
@@ -272,9 +272,10 @@ func (s *TransactionService) CreateTransaction(c core.Context, transaction *mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BatchCreateTransactions saves new transactions to database
|
// BatchCreateTransactions saves new transactions to database
|
||||||
func (s *TransactionService) BatchCreateTransactions(c core.Context, uid int64, transactions []*models.Transaction) error {
|
func (s *TransactionService) BatchCreateTransactions(c core.Context, uid int64, transactions []*models.Transaction, allTagIds map[int][]int64) error {
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
needUuidCount := uint16(0)
|
needTransactionUuidCount := uint16(0)
|
||||||
|
needTagIndexUuidCount := uint16(0)
|
||||||
|
|
||||||
for i := 0; i < len(transactions); i++ {
|
for i := 0; i < len(transactions); i++ {
|
||||||
transaction := transactions[i]
|
transaction := transactions[i]
|
||||||
@@ -291,9 +292,9 @@ func (s *TransactionService) BatchCreateTransactions(c core.Context, uid int64,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
|
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
|
||||||
needUuidCount += 2
|
needTransactionUuidCount += 2
|
||||||
} else {
|
} else {
|
||||||
needUuidCount++
|
needTransactionUuidCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.TransactionTime = utils.GetMinTransactionTimeFromUnixTime(utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime))
|
transaction.TransactionTime = utils.GetMinTransactionTimeFromUnixTime(utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime))
|
||||||
@@ -302,33 +303,78 @@ func (s *TransactionService) BatchCreateTransactions(c core.Context, uid int64,
|
|||||||
transaction.UpdatedUnixTime = now
|
transaction.UpdatedUnixTime = now
|
||||||
}
|
}
|
||||||
|
|
||||||
if needUuidCount > uint16(65535) {
|
for index, tagIds := range allTagIds {
|
||||||
|
if index < 0 || index >= len(transactions) {
|
||||||
|
return errs.ErrOperationFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
uniqueTagIds := utils.ToUniqueInt64Slice(tagIds)
|
||||||
|
needTagIndexUuidCount += uint16(len(uniqueTagIds))
|
||||||
|
}
|
||||||
|
|
||||||
|
if needTransactionUuidCount > uint16(65535) || needTagIndexUuidCount > uint16(65535) {
|
||||||
return errs.ErrImportTooManyTransaction
|
return errs.ErrImportTooManyTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
uuids := s.GenerateUuids(uuid.UUID_TYPE_TRANSACTION, needUuidCount)
|
transactionUuids := s.GenerateUuids(uuid.UUID_TYPE_TRANSACTION, needTransactionUuidCount)
|
||||||
uuidIndex := 0
|
transactionUuidIndex := 0
|
||||||
|
|
||||||
if len(uuids) < int(needUuidCount) {
|
if len(transactionUuids) < int(needTransactionUuidCount) {
|
||||||
return errs.ErrSystemIsBusy
|
return errs.ErrSystemIsBusy
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(transactions); i++ {
|
for i := 0; i < len(transactions); i++ {
|
||||||
transaction := transactions[i]
|
transaction := transactions[i]
|
||||||
|
|
||||||
transaction.TransactionId = uuids[uuidIndex]
|
transaction.TransactionId = transactionUuids[transactionUuidIndex]
|
||||||
uuidIndex++
|
transactionUuidIndex++
|
||||||
|
|
||||||
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
|
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
|
||||||
transaction.RelatedId = uuids[uuidIndex]
|
transaction.RelatedId = transactionUuids[transactionUuidIndex]
|
||||||
uuidIndex++
|
transactionUuidIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tagIndexUuids := s.GenerateUuids(uuid.UUID_TYPE_TAG_INDEX, needTagIndexUuidCount)
|
||||||
|
tagIndexUuidIndex := 0
|
||||||
|
|
||||||
|
if len(tagIndexUuids) < int(needTagIndexUuidCount) {
|
||||||
|
return errs.ErrSystemIsBusy
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransactionTagIndexes := make(map[int64][]*models.TransactionTagIndex)
|
||||||
|
allTransactionTagIds := make(map[int64][]int64)
|
||||||
|
|
||||||
|
for index, tagIds := range allTagIds {
|
||||||
|
transaction := transactions[index]
|
||||||
|
uniqueTagIds := utils.ToUniqueInt64Slice(tagIds)
|
||||||
|
|
||||||
|
transactionTagIndexes := make([]*models.TransactionTagIndex, len(uniqueTagIds))
|
||||||
|
|
||||||
|
for i := 0; i < len(uniqueTagIds); i++ {
|
||||||
|
transactionTagIndexes[i] = &models.TransactionTagIndex{
|
||||||
|
TagIndexId: tagIndexUuids[tagIndexUuidIndex],
|
||||||
|
Uid: transaction.Uid,
|
||||||
|
Deleted: false,
|
||||||
|
TagId: uniqueTagIds[i],
|
||||||
|
TransactionId: transaction.TransactionId,
|
||||||
|
CreatedUnixTime: now,
|
||||||
|
UpdatedUnixTime: now,
|
||||||
|
}
|
||||||
|
|
||||||
|
tagIndexUuidIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransactionTagIndexes[transaction.TransactionId] = transactionTagIndexes
|
||||||
|
allTransactionTagIds[transaction.TransactionId] = uniqueTagIds
|
||||||
|
}
|
||||||
|
|
||||||
return s.UserDataDB(uid).DoTransaction(c, func(sess *xorm.Session) error {
|
return s.UserDataDB(uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||||
for i := 0; i < len(transactions); i++ {
|
for i := 0; i < len(transactions); i++ {
|
||||||
transaction := transactions[i]
|
transaction := transactions[i]
|
||||||
err := s.doCreateTransaction(sess, transaction, nil, nil, nil, nil)
|
transactionTagIndexes := allTransactionTagIndexes[transaction.TransactionId]
|
||||||
|
transactionTagIds := allTransactionTagIds[transaction.TransactionId]
|
||||||
|
err := s.doCreateTransaction(sess, transaction, transactionTagIndexes, transactionTagIds, nil, nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
transactionUnixTime := utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime)
|
transactionUnixTime := utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime)
|
||||||
|
|||||||
Reference in New Issue
Block a user