check whether transaction template uses specified accounts / categories / tags when deleting them

This commit is contained in:
MaysWind
2025-08-24 01:29:26 +08:00
parent 601a1f83c6
commit 01aeb945ff
3 changed files with 70 additions and 0 deletions
+40
View File
@@ -1,6 +1,7 @@
package services package services
import ( import (
"fmt"
"strings" "strings"
"time" "time"
@@ -662,9 +663,15 @@ func (s *AccountService) DeleteAccount(c core.Context, uid int64, accountId int6
return errs.ErrAccountNotFound return errs.ErrAccountNotFound
} }
var accountAndSubAccountIdsConditions strings.Builder
accountAndSubAccountIds := make([]int64, len(accountAndSubAccounts)) accountAndSubAccountIds := make([]int64, len(accountAndSubAccounts))
for i := 0; i < len(accountAndSubAccounts); i++ { for i := 0; i < len(accountAndSubAccounts); i++ {
if accountAndSubAccountIdsConditions.Len() > 0 {
accountAndSubAccountIdsConditions.WriteString(",")
}
accountAndSubAccountIdsConditions.WriteString("?")
accountAndSubAccountIds[i] = accountAndSubAccounts[i].AccountId accountAndSubAccountIds[i] = accountAndSubAccounts[i].AccountId
} }
@@ -691,6 +698,31 @@ func (s *AccountService) DeleteAccount(c core.Context, uid int64, accountId int6
} }
} }
transactionTemplateQueryCondition := fmt.Sprintf("uid=? AND deleted=? AND (template_type=? || (template_type=? && scheduled_frequency_type<>? && (scheduled_end_time IS NULL OR scheduled_end_time>=?))) AND (account_id IN (%s) OR related_account_id IN (%s))", accountAndSubAccountIdsConditions.String(), accountAndSubAccountIdsConditions.String())
transactionTemplateQueryConditionParams := make([]any, 0, len(accountAndSubAccountIds)*2+6)
transactionTemplateQueryConditionParams = append(transactionTemplateQueryConditionParams, uid)
transactionTemplateQueryConditionParams = append(transactionTemplateQueryConditionParams, false)
transactionTemplateQueryConditionParams = append(transactionTemplateQueryConditionParams, models.TRANSACTION_TEMPLATE_TYPE_NORMAL)
transactionTemplateQueryConditionParams = append(transactionTemplateQueryConditionParams, models.TRANSACTION_TEMPLATE_TYPE_SCHEDULE)
transactionTemplateQueryConditionParams = append(transactionTemplateQueryConditionParams, models.TRANSACTION_SCHEDULE_FREQUENCY_TYPE_DISABLED)
transactionTemplateQueryConditionParams = append(transactionTemplateQueryConditionParams, now)
for i := 0; i < len(accountAndSubAccountIds); i++ {
transactionTemplateQueryConditionParams = append(transactionTemplateQueryConditionParams, accountAndSubAccountIds[i])
}
for i := 0; i < len(accountAndSubAccountIds); i++ {
transactionTemplateQueryConditionParams = append(transactionTemplateQueryConditionParams, accountAndSubAccountIds[i])
}
exists, err := sess.Cols("uid", "deleted", "account_id", "related_account_id", "template_type", "scheduled_frequency_type", "scheduled_end_time").Where(transactionTemplateQueryCondition, transactionTemplateQueryConditionParams...).Limit(1).Exist(&models.TransactionTemplate{})
if err != nil {
return err
} else if exists {
return errs.ErrAccountInUseCannotBeDeleted
}
deletedRows, err := sess.Cols("balance", "deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).In("account_id", accountAndSubAccountIds).Update(updateModel) deletedRows, err := sess.Cols("balance", "deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).In("account_id", accountAndSubAccountIds).Update(updateModel)
if err != nil { if err != nil {
@@ -772,6 +804,14 @@ func (s *AccountService) DeleteSubAccount(c core.Context, uid int64, accountId i
} }
} }
exists, err := sess.Cols("uid", "deleted", "account_id", "related_account_id", "template_type", "scheduled_frequency_type", "scheduled_end_time").Where("uid=? AND deleted=? AND (template_type=? || (template_type=? && scheduled_frequency_type<>? && (scheduled_end_time IS NULL OR scheduled_end_time>=?))) AND (account_id=? OR related_account_id=?)", uid, false, models.TRANSACTION_TEMPLATE_TYPE_NORMAL, models.TRANSACTION_TEMPLATE_TYPE_SCHEDULE, models.TRANSACTION_SCHEDULE_FREQUENCY_TYPE_DISABLED, now, accountId, accountId).Limit(1).Exist(&models.TransactionTemplate{})
if err != nil {
return err
} else if exists {
return errs.ErrSubAccountInUseCannotBeDeleted
}
deletedRows, err := sess.Cols("balance", "deleted", "deleted_unix_time").Where("uid=? AND deleted=? AND account_id=?", uid, false, accountId).Update(updateModel) deletedRows, err := sess.Cols("balance", "deleted", "deleted_unix_time").Where("uid=? AND deleted=? AND account_id=?", uid, false, accountId).Update(updateModel)
if err != nil { if err != nil {
+8
View File
@@ -397,6 +397,14 @@ func (s *TransactionCategoryService) DeleteCategory(c core.Context, uid int64, c
return errs.ErrTransactionCategoryInUseCannotBeDeleted return errs.ErrTransactionCategoryInUseCannotBeDeleted
} }
exists, err = sess.Cols("uid", "deleted", "category_id", "template_type", "scheduled_frequency_type", "scheduled_end_time").Where("uid=? AND deleted=? AND (template_type=? || (template_type=? && scheduled_frequency_type<>? && (scheduled_end_time IS NULL OR scheduled_end_time>=?)))", uid, false, models.TRANSACTION_TEMPLATE_TYPE_NORMAL, models.TRANSACTION_TEMPLATE_TYPE_SCHEDULE, models.TRANSACTION_SCHEDULE_FREQUENCY_TYPE_DISABLED, now).In("category_id", categoryAndSubCategoryIds).Limit(1).Exist(&models.TransactionTemplate{})
if err != nil {
return err
} else if exists {
return errs.ErrTransactionCategoryInUseCannotBeDeleted
}
deletedRows, err := sess.Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).In("category_id", categoryAndSubCategoryIds).Update(updateModel) deletedRows, err := sess.Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).In("category_id", categoryAndSubCategoryIds).Update(updateModel)
if err != nil { if err != nil {
+22
View File
@@ -396,6 +396,28 @@ func (s *TransactionTagService) DeleteTag(c core.Context, uid int64, tagId int64
return errs.ErrTransactionTagInUseCannotBeDeleted return errs.ErrTransactionTagInUseCannotBeDeleted
} }
var relatedTransactionTemplatesByTag []*models.TransactionTemplate
err = sess.Cols("uid", "deleted", "tag_ids", "template_type", "scheduled_frequency_type", "scheduled_end_time").Where("uid=? AND deleted=? AND (template_type=? || (template_type=? && scheduled_frequency_type<>? && (scheduled_end_time IS NULL OR scheduled_end_time>=?))) && tag_ids LIKE ?", uid, false, models.TRANSACTION_TEMPLATE_TYPE_NORMAL, models.TRANSACTION_TEMPLATE_TYPE_SCHEDULE, models.TRANSACTION_SCHEDULE_FREQUENCY_TYPE_DISABLED, now, "%%"+utils.Int64ToString(tagId)+"%%").Find(&relatedTransactionTemplatesByTag)
if err != nil {
return err
}
for i := 0; i < len(relatedTransactionTemplatesByTag); i++ {
template := relatedTransactionTemplatesByTag[i]
tagIds, err := s.GetTagIds(template.TagIds)
if err != nil {
return err
}
for j := 0; j < len(tagIds); j++ {
if tagIds[j] == tagId {
return errs.ErrTransactionTagInUseCannotBeDeleted
}
}
}
deletedRows, err := sess.ID(tagId).Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).Update(updateModel) deletedRows, err := sess.ID(tagId).Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).Update(updateModel)
if err != nil { if err != nil {