support transaction tag group
This commit is contained in:
@@ -28,6 +28,7 @@ type DataManagementsApi struct {
|
||||
transactions *services.TransactionService
|
||||
categories *services.TransactionCategoryService
|
||||
tags *services.TransactionTagService
|
||||
tagGroups *services.TransactionTagGroupService
|
||||
pictures *services.TransactionPictureService
|
||||
templates *services.TransactionTemplateService
|
||||
userCustomExchangeRates *services.UserCustomExchangeRatesService
|
||||
@@ -46,6 +47,7 @@ var (
|
||||
transactions: services.Transactions,
|
||||
categories: services.TransactionCategories,
|
||||
tags: services.TransactionTags,
|
||||
tagGroups: services.TransactionTagGroups,
|
||||
pictures: services.TransactionPictures,
|
||||
templates: services.TransactionTemplates,
|
||||
userCustomExchangeRates: services.UserCustomExchangeRates,
|
||||
@@ -193,6 +195,13 @@ func (a *DataManagementsApi) ClearAllDataHandler(c *core.WebContext) (any, *errs
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
err = a.tagGroups.DeleteAllTagGroups(c, uid)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[data_managements.ClearAllDataHandler] failed to delete all transaction tag groups, because %s", err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
err = a.userCustomExchangeRates.DeleteAllCustomExchangeRates(c, uid)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/log"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/services"
|
||||
)
|
||||
|
||||
// TransactionTagGroupsApi represents transaction tag group api
|
||||
type TransactionTagGroupsApi struct {
|
||||
tagGroups *services.TransactionTagGroupService
|
||||
}
|
||||
|
||||
// Initialize a transaction tag group api singleton instance
|
||||
var (
|
||||
TransactionTagGroups = &TransactionTagGroupsApi{
|
||||
tagGroups: services.TransactionTagGroups,
|
||||
}
|
||||
)
|
||||
|
||||
// TagGroupListHandler returns transaction tag group list of current user
|
||||
func (a *TransactionTagGroupsApi) TagGroupListHandler(c *core.WebContext) (any, *errs.Error) {
|
||||
uid := c.GetCurrentUid()
|
||||
tagGroups, err := a.tagGroups.GetAllTagGroupsByUid(c, uid)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tag_groups.TagGroupListHandler] failed to get tag groups for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
tagGroupResps := make(models.TransactionTagGroupInfoResponseSlice, len(tagGroups))
|
||||
|
||||
for i := 0; i < len(tagGroups); i++ {
|
||||
tagGroupResps[i] = tagGroups[i].ToTransactionTagGroupInfoResponse()
|
||||
}
|
||||
|
||||
sort.Sort(tagGroupResps)
|
||||
|
||||
return tagGroupResps, nil
|
||||
}
|
||||
|
||||
// TagGroupGetHandler returns one specific transaction tag group of current user
|
||||
func (a *TransactionTagGroupsApi) TagGroupGetHandler(c *core.WebContext) (any, *errs.Error) {
|
||||
var tagGroupGetReq models.TransactionTagGroupGetRequest
|
||||
err := c.ShouldBindQuery(&tagGroupGetReq)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf(c, "[transaction_tag_groups.TagGroupGetHandler] parse request failed, because %s", err.Error())
|
||||
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||
}
|
||||
|
||||
uid := c.GetCurrentUid()
|
||||
tagGroup, err := a.tagGroups.GetTagGroupByTagGroupId(c, uid, tagGroupGetReq.Id)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tag_groups.TagGroupGetHandler] failed to get tag group \"id:%d\" for user \"uid:%d\", because %s", tagGroupGetReq.Id, uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
tagGroupResp := tagGroup.ToTransactionTagGroupInfoResponse()
|
||||
|
||||
return tagGroupResp, nil
|
||||
}
|
||||
|
||||
// TagGroupCreateHandler saves a new transaction tag group by request parameters for current user
|
||||
func (a *TransactionTagGroupsApi) TagGroupCreateHandler(c *core.WebContext) (any, *errs.Error) {
|
||||
var tagGroupCreateReq models.TransactionTagGroupCreateRequest
|
||||
err := c.ShouldBindJSON(&tagGroupCreateReq)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf(c, "[transaction_tag_groups.TagGroupCreateHandler] parse request failed, because %s", err.Error())
|
||||
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||
}
|
||||
|
||||
uid := c.GetCurrentUid()
|
||||
|
||||
maxOrderId, err := a.tagGroups.GetMaxDisplayOrder(c, uid)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tag_groups.TagGroupCreateHandler] failed to get max display order for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
tagGroup := a.createNewTagGroupModel(uid, &tagGroupCreateReq, maxOrderId+1)
|
||||
|
||||
err = a.tagGroups.CreateTagGroup(c, tagGroup)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tag_groups.TagGroupCreateHandler] failed to create tag group \"id:%d\" for user \"uid:%d\", because %s", tagGroup.TagGroupId, uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
log.Infof(c, "[transaction_tag_groups.TagGroupCreateHandler] user \"uid:%d\" has created a new tag group \"id:%d\" successfully", uid, tagGroup.TagGroupId)
|
||||
|
||||
tagGroupResp := tagGroup.ToTransactionTagGroupInfoResponse()
|
||||
|
||||
return tagGroupResp, nil
|
||||
}
|
||||
|
||||
// TagGroupModifyHandler saves an existed transaction tag group by request parameters for current user
|
||||
func (a *TransactionTagGroupsApi) TagGroupModifyHandler(c *core.WebContext) (any, *errs.Error) {
|
||||
var tagGroupModifyReq models.TransactionTagGroupModifyRequest
|
||||
err := c.ShouldBindJSON(&tagGroupModifyReq)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf(c, "[transaction_tag_groups.TagGroupModifyHandler] parse request failed, because %s", err.Error())
|
||||
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||
}
|
||||
|
||||
uid := c.GetCurrentUid()
|
||||
tagGroup, err := a.tagGroups.GetTagGroupByTagGroupId(c, uid, tagGroupModifyReq.Id)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tag_groups.TagGroupModifyHandler] failed to get tag group \"id:%d\" for user \"uid:%d\", because %s", tagGroupModifyReq.Id, uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
newTagGroup := &models.TransactionTagGroup{
|
||||
TagGroupId: tagGroup.TagGroupId,
|
||||
Uid: uid,
|
||||
Name: tagGroupModifyReq.Name,
|
||||
}
|
||||
|
||||
if newTagGroup.Name == tagGroup.Name {
|
||||
return nil, errs.ErrNothingWillBeUpdated
|
||||
}
|
||||
|
||||
err = a.tagGroups.ModifyTagGroup(c, newTagGroup)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tag_groups.TagGroupModifyHandler] failed to update tag group \"id:%d\" for user \"uid:%d\", because %s", tagGroupModifyReq.Id, uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
log.Infof(c, "[transaction_tag_groups.TagGroupModifyHandler] user \"uid:%d\" has updated tag group \"id:%d\" successfully", uid, tagGroupModifyReq.Id)
|
||||
|
||||
tagGroup.Name = newTagGroup.Name
|
||||
tagGroupResp := tagGroup.ToTransactionTagGroupInfoResponse()
|
||||
|
||||
return tagGroupResp, nil
|
||||
}
|
||||
|
||||
// TagGroupMoveHandler moves display order of existed transaction tag groups by request parameters for current user
|
||||
func (a *TransactionTagGroupsApi) TagGroupMoveHandler(c *core.WebContext) (any, *errs.Error) {
|
||||
var tagGroupMoveReq models.TransactionTagGroupMoveRequest
|
||||
err := c.ShouldBindJSON(&tagGroupMoveReq)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf(c, "[transaction_tag_groups.TagGroupMoveHandler] parse request failed, because %s", err.Error())
|
||||
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||
}
|
||||
|
||||
uid := c.GetCurrentUid()
|
||||
tagGroups := make([]*models.TransactionTagGroup, len(tagGroupMoveReq.NewDisplayOrders))
|
||||
|
||||
for i := 0; i < len(tagGroupMoveReq.NewDisplayOrders); i++ {
|
||||
newDisplayOrder := tagGroupMoveReq.NewDisplayOrders[i]
|
||||
tagGroup := &models.TransactionTagGroup{
|
||||
Uid: uid,
|
||||
TagGroupId: newDisplayOrder.Id,
|
||||
DisplayOrder: newDisplayOrder.DisplayOrder,
|
||||
}
|
||||
|
||||
tagGroups[i] = tagGroup
|
||||
}
|
||||
|
||||
err = a.tagGroups.ModifyTagGroupDisplayOrders(c, uid, tagGroups)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tag_groups.TagGroupMoveHandler] failed to move tag groups for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
log.Infof(c, "[transaction_tag_groups.TagGroupMoveHandler] user \"uid:%d\" has moved tag groups", uid)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// TagGroupDeleteHandler deletes an existed transaction tag group by request parameters for current user
|
||||
func (a *TransactionTagGroupsApi) TagGroupDeleteHandler(c *core.WebContext) (any, *errs.Error) {
|
||||
var tagGroupDeleteReq models.TransactionTagGroupDeleteRequest
|
||||
err := c.ShouldBindJSON(&tagGroupDeleteReq)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf(c, "[transaction_tag_groups.TagGroupDeleteHandler] parse request failed, because %s", err.Error())
|
||||
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||
}
|
||||
|
||||
uid := c.GetCurrentUid()
|
||||
err = a.tagGroups.DeleteTagGroup(c, uid, tagGroupDeleteReq.Id)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tag_groups.TagGroupDeleteHandler] failed to delete tag group \"id:%d\" for user \"uid:%d\", because %s", tagGroupDeleteReq.Id, uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
log.Infof(c, "[transaction_tag_groups.TagGroupDeleteHandler] user \"uid:%d\" has deleted tag group \"id:%d\"", uid, tagGroupDeleteReq.Id)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (a *TransactionTagGroupsApi) createNewTagGroupModel(uid int64, tagGroupCreateReq *models.TransactionTagGroupCreateRequest, order int32) *models.TransactionTagGroup {
|
||||
return &models.TransactionTagGroup{
|
||||
Uid: uid,
|
||||
Name: tagGroupCreateReq.Name,
|
||||
DisplayOrder: order,
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,7 @@ func (a *TransactionTagsApi) TagCreateHandler(c *core.WebContext) (any, *errs.Er
|
||||
|
||||
uid := c.GetCurrentUid()
|
||||
|
||||
maxOrderId, err := a.tags.GetMaxDisplayOrder(c, uid)
|
||||
maxOrderId, err := a.tags.GetMaxDisplayOrder(c, uid, tagCreateReq.GroupId)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tags.TagCreateHandler] failed to get max display order for user \"uid:%d\", because %s", uid, err.Error())
|
||||
@@ -111,9 +111,16 @@ func (a *TransactionTagsApi) TagCreateBatchHandler(c *core.WebContext) (any, *er
|
||||
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||
}
|
||||
|
||||
for i := 0; i < len(tagCreateBatchReq.Tags); i++ {
|
||||
if tagCreateBatchReq.Tags[i].GroupId != tagCreateBatchReq.GroupId {
|
||||
log.Warnf(c, "[transaction_tags.TagCreateBatchHandler] the group id \"%d\" of tag#%d is inconsistent with the batch group id \"%d\"", tagCreateBatchReq.Tags[i].GroupId, i, tagCreateBatchReq.GroupId)
|
||||
return nil, errs.ErrTransactionTagGroupIdInvalid
|
||||
}
|
||||
}
|
||||
|
||||
uid := c.GetCurrentUid()
|
||||
|
||||
maxOrderId, err := a.tags.GetMaxDisplayOrder(c, uid)
|
||||
maxOrderId, err := a.tags.GetMaxDisplayOrder(c, uid, tagCreateBatchReq.GroupId)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tags.TagCreateBatchHandler] failed to get max display order for user \"uid:%d\", because %s", uid, err.Error())
|
||||
@@ -161,16 +168,31 @@ func (a *TransactionTagsApi) TagModifyHandler(c *core.WebContext) (any, *errs.Er
|
||||
}
|
||||
|
||||
newTag := &models.TransactionTag{
|
||||
TagId: tag.TagId,
|
||||
Uid: uid,
|
||||
Name: tagModifyReq.Name,
|
||||
TagId: tag.TagId,
|
||||
Uid: uid,
|
||||
Name: tagModifyReq.Name,
|
||||
TagGroupId: tagModifyReq.GroupId,
|
||||
DisplayOrder: tag.DisplayOrder,
|
||||
}
|
||||
|
||||
if newTag.Name == tag.Name {
|
||||
tagNameChanged := newTag.Name != tag.Name
|
||||
|
||||
if !tagNameChanged && newTag.TagGroupId == tag.TagGroupId {
|
||||
return nil, errs.ErrNothingWillBeUpdated
|
||||
}
|
||||
|
||||
err = a.tags.ModifyTag(c, newTag)
|
||||
if newTag.TagGroupId != tag.TagGroupId {
|
||||
maxOrderId, err := a.tags.GetMaxDisplayOrder(c, uid, newTag.TagGroupId)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tags.TagModifyHandler] failed to get max display order for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
newTag.DisplayOrder = maxOrderId + 1
|
||||
}
|
||||
|
||||
err = a.tags.ModifyTag(c, newTag, tagNameChanged)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_tags.TagModifyHandler] failed to update tag \"id:%d\" for user \"uid:%d\", because %s", tagModifyReq.Id, uid, err.Error())
|
||||
@@ -180,6 +202,8 @@ func (a *TransactionTagsApi) TagModifyHandler(c *core.WebContext) (any, *errs.Er
|
||||
log.Infof(c, "[transaction_tags.TagModifyHandler] user \"uid:%d\" has updated tag \"id:%d\" successfully", uid, tagModifyReq.Id)
|
||||
|
||||
tag.Name = newTag.Name
|
||||
tag.TagGroupId = newTag.TagGroupId
|
||||
tag.DisplayOrder = newTag.DisplayOrder
|
||||
tagResp := tag.ToTransactionTagInfoResponse()
|
||||
|
||||
return tagResp, nil
|
||||
@@ -268,6 +292,7 @@ func (a *TransactionTagsApi) createNewTagModel(uid int64, tagCreateReq *models.T
|
||||
return &models.TransactionTag{
|
||||
Uid: uid,
|
||||
Name: tagCreateReq.Name,
|
||||
TagGroupId: tagCreateReq.GroupId,
|
||||
DisplayOrder: order,
|
||||
}
|
||||
}
|
||||
@@ -278,6 +303,7 @@ func (a *TransactionTagsApi) createNewTagModels(uid int64, tagCreateBatchReq *mo
|
||||
for i := 0; i < len(tagCreateBatchReq.Tags); i++ {
|
||||
tagCreateReq := tagCreateBatchReq.Tags[i]
|
||||
tag := a.createNewTagModel(uid, tagCreateReq, order+int32(i))
|
||||
tag.TagGroupId = tagCreateBatchReq.GroupId
|
||||
tags[i] = tag
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ const (
|
||||
NormalSubcategoryUserExternalAuth = 16
|
||||
NormalSubcategoryOAuth2 = 17
|
||||
NormalSubcategoryInsightsExplorer = 18
|
||||
NormalSubcategoryTagGroup = 19
|
||||
)
|
||||
|
||||
// Error represents the specific error returned to user
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package errs
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Error codes related to transaction tag groups
|
||||
var (
|
||||
ErrTransactionTagGroupIdInvalid = NewNormalError(NormalSubcategoryTagGroup, 0, http.StatusBadRequest, "transaction tag group id is invalid")
|
||||
ErrTransactionTagGroupNotFound = NewNormalError(NormalSubcategoryTagGroup, 1, http.StatusBadRequest, "transaction tag group not found")
|
||||
ErrTransactionTagGroupInUseCannotBeDeleted = NewNormalError(NormalSubcategoryTagGroup, 2, http.StatusBadRequest, "transaction tag group is in use and cannot be deleted")
|
||||
)
|
||||
@@ -3,10 +3,11 @@ package models
|
||||
// TransactionTag represents transaction tag data stored in database
|
||||
type TransactionTag struct {
|
||||
TagId int64 `xorm:"PK"`
|
||||
Uid int64 `xorm:"INDEX(IDX_tag_uid_deleted_order) NOT NULL"`
|
||||
Deleted bool `xorm:"INDEX(IDX_tag_uid_deleted_order) NOT NULL"`
|
||||
Uid int64 `xorm:"INDEX(IDX_tag_uid_deleted_group_order) NOT NULL"`
|
||||
Deleted bool `xorm:"INDEX(IDX_tag_uid_deleted_group_order) NOT NULL"`
|
||||
TagGroupId int64 `xorm:"INDEX(IDX_tag_uid_deleted_group_order) NOT NULL"`
|
||||
Name string `xorm:"VARCHAR(64) NOT NULL"`
|
||||
DisplayOrder int32 `xorm:"INDEX(IDX_tag_uid_deleted_order) NOT NULL"`
|
||||
DisplayOrder int32 `xorm:"INDEX(IDX_tag_uid_deleted_group_order) NOT NULL"`
|
||||
Hidden bool `xorm:"NOT NULL"`
|
||||
CreatedUnixTime int64
|
||||
UpdatedUnixTime int64
|
||||
@@ -20,19 +21,22 @@ type TransactionTagGetRequest struct {
|
||||
|
||||
// TransactionTagCreateRequest represents all parameters of transaction tag creation request
|
||||
type TransactionTagCreateRequest struct {
|
||||
Name string `json:"name" binding:"required,notBlank,max=64"`
|
||||
GroupId int64 `json:"groupId,string"`
|
||||
Name string `json:"name" binding:"required,notBlank,max=64"`
|
||||
}
|
||||
|
||||
// TransactionTagCreateBatchRequest represents all parameters of transaction tag batch creation request
|
||||
type TransactionTagCreateBatchRequest struct {
|
||||
Tags []*TransactionTagCreateRequest `json:"tags" binding:"required"`
|
||||
GroupId int64 `json:"groupId,string"`
|
||||
SkipExists bool `json:"skipExists"`
|
||||
}
|
||||
|
||||
// TransactionTagModifyRequest represents all parameters of transaction tag modification request
|
||||
type TransactionTagModifyRequest struct {
|
||||
Id int64 `json:"id,string" binding:"required,min=1"`
|
||||
Name string `json:"name" binding:"required,notBlank,max=64"`
|
||||
Id int64 `json:"id,string" binding:"required,min=1"`
|
||||
GroupId int64 `json:"groupId,string"`
|
||||
Name string `json:"name" binding:"required,notBlank,max=64"`
|
||||
}
|
||||
|
||||
// TransactionTagHideRequest represents all parameters of transaction tag hiding request
|
||||
@@ -61,6 +65,7 @@ type TransactionTagDeleteRequest struct {
|
||||
type TransactionTagInfoResponse struct {
|
||||
Id int64 `json:"id,string"`
|
||||
Name string `json:"name"`
|
||||
TagGroupId int64 `json:"groupId,string"`
|
||||
DisplayOrder int32 `json:"displayOrder"`
|
||||
Hidden bool `json:"hidden"`
|
||||
}
|
||||
@@ -71,6 +76,7 @@ func (t *TransactionTag) FillFromOtherTag(tag *TransactionTag) {
|
||||
t.Uid = tag.Uid
|
||||
t.Deleted = tag.Deleted
|
||||
t.Name = tag.Name
|
||||
t.TagGroupId = tag.TagGroupId
|
||||
t.DisplayOrder = tag.DisplayOrder
|
||||
t.Hidden = tag.Hidden
|
||||
t.CreatedUnixTime = tag.CreatedUnixTime
|
||||
@@ -83,6 +89,7 @@ func (t *TransactionTag) ToTransactionTagInfoResponse() *TransactionTagInfoRespo
|
||||
return &TransactionTagInfoResponse{
|
||||
Id: t.TagId,
|
||||
Name: t.Name,
|
||||
TagGroupId: t.TagGroupId,
|
||||
DisplayOrder: t.DisplayOrder,
|
||||
Hidden: t.Hidden,
|
||||
}
|
||||
@@ -103,5 +110,9 @@ func (s TransactionTagInfoResponseSlice) Swap(i, j int) {
|
||||
|
||||
// Less reports whether the first item is less than the second one
|
||||
func (s TransactionTagInfoResponseSlice) Less(i, j int) bool {
|
||||
if s[i].TagGroupId != s[j].TagGroupId {
|
||||
return s[i].TagGroupId < s[j].TagGroupId
|
||||
}
|
||||
|
||||
return s[i].DisplayOrder < s[j].DisplayOrder
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package models
|
||||
|
||||
// TransactionTagGroup represents transaction tag group data stored in database
|
||||
type TransactionTagGroup struct {
|
||||
TagGroupId int64 `xorm:"PK"`
|
||||
Uid int64 `xorm:"INDEX(IDX_tag_group_uid_deleted_order) NOT NULL"`
|
||||
Deleted bool `xorm:"INDEX(IDX_tag_group_uid_deleted_order) NOT NULL"`
|
||||
Name string `xorm:"VARCHAR(64) NOT NULL"`
|
||||
DisplayOrder int32 `xorm:"INDEX(IDX_tag_group_uid_deleted_order) NOT NULL"`
|
||||
CreatedUnixTime int64
|
||||
UpdatedUnixTime int64
|
||||
DeletedUnixTime int64
|
||||
}
|
||||
|
||||
// TransactionTagGroupGetRequest represents all parameters of transaction tag group getting request
|
||||
type TransactionTagGroupGetRequest struct {
|
||||
Id int64 `form:"id,string" binding:"required,min=1"`
|
||||
}
|
||||
|
||||
// TransactionTagGroupCreateRequest represents all parameters of transaction tag group creation request
|
||||
type TransactionTagGroupCreateRequest struct {
|
||||
Name string `json:"name" binding:"required,notBlank,max=64"`
|
||||
}
|
||||
|
||||
// TransactionTagGroupModifyRequest represents all parameters of transaction tag group modification request
|
||||
type TransactionTagGroupModifyRequest struct {
|
||||
Id int64 `json:"id,string" binding:"required,min=1"`
|
||||
Name string `json:"name" binding:"required,notBlank,max=64"`
|
||||
}
|
||||
|
||||
// TransactionTagGroupMoveRequest represents all parameters of transaction tag group moving request
|
||||
type TransactionTagGroupMoveRequest struct {
|
||||
NewDisplayOrders []*TransactionTagGroupNewDisplayOrderRequest `json:"newDisplayOrders" binding:"required,min=1"`
|
||||
}
|
||||
|
||||
// TransactionTagGroupNewDisplayOrderRequest represents a data pair of id and display order
|
||||
type TransactionTagGroupNewDisplayOrderRequest struct {
|
||||
Id int64 `json:"id,string" binding:"required,min=1"`
|
||||
DisplayOrder int32 `json:"displayOrder"`
|
||||
}
|
||||
|
||||
// TransactionTagGroupDeleteRequest represents all parameters of transaction tag group deleting request
|
||||
type TransactionTagGroupDeleteRequest struct {
|
||||
Id int64 `json:"id,string" binding:"required,min=1"`
|
||||
}
|
||||
|
||||
// TransactionTagGroupInfoResponse represents a view-object of transaction tag group
|
||||
type TransactionTagGroupInfoResponse struct {
|
||||
Id int64 `json:"id,string"`
|
||||
Name string `json:"name"`
|
||||
DisplayOrder int32 `json:"displayOrder"`
|
||||
}
|
||||
|
||||
// ToTransactionTagGroupInfoResponse returns a view-object according to database model
|
||||
func (t *TransactionTagGroup) ToTransactionTagGroupInfoResponse() *TransactionTagGroupInfoResponse {
|
||||
return &TransactionTagGroupInfoResponse{
|
||||
Id: t.TagGroupId,
|
||||
Name: t.Name,
|
||||
DisplayOrder: t.DisplayOrder,
|
||||
}
|
||||
}
|
||||
|
||||
// TransactionTagGroupInfoResponseSlice represents the slice data structure of TransactionTagGroupInfoResponse
|
||||
type TransactionTagGroupInfoResponseSlice []*TransactionTagGroupInfoResponse
|
||||
|
||||
// Len returns the count of items
|
||||
func (s TransactionTagGroupInfoResponseSlice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
// Swap swaps two items
|
||||
func (s TransactionTagGroupInfoResponseSlice) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
// Less reports whether the first item is less than the second one
|
||||
func (s TransactionTagGroupInfoResponseSlice) Less(i, j int) bool {
|
||||
return s[i].DisplayOrder < s[j].DisplayOrder
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTransactionTagGroupInfoResponseSliceLess(t *testing.T) {
|
||||
var transactionTagGroupRespSlice TransactionTagGroupInfoResponseSlice
|
||||
transactionTagGroupRespSlice = append(transactionTagGroupRespSlice, &TransactionTagGroupInfoResponse{
|
||||
Id: 1,
|
||||
DisplayOrder: 3,
|
||||
})
|
||||
transactionTagGroupRespSlice = append(transactionTagGroupRespSlice, &TransactionTagGroupInfoResponse{
|
||||
Id: 2,
|
||||
DisplayOrder: 1,
|
||||
})
|
||||
transactionTagGroupRespSlice = append(transactionTagGroupRespSlice, &TransactionTagGroupInfoResponse{
|
||||
Id: 3,
|
||||
DisplayOrder: 2,
|
||||
})
|
||||
|
||||
sort.Sort(transactionTagGroupRespSlice)
|
||||
|
||||
assert.Equal(t, int64(2), transactionTagGroupRespSlice[0].Id)
|
||||
assert.Equal(t, int64(3), transactionTagGroupRespSlice[1].Id)
|
||||
assert.Equal(t, int64(1), transactionTagGroupRespSlice[2].Id)
|
||||
}
|
||||
@@ -11,20 +11,41 @@ func TestTransactionTagInfoResponseSliceLess(t *testing.T) {
|
||||
var transactionTagRespSlice TransactionTagInfoResponseSlice
|
||||
transactionTagRespSlice = append(transactionTagRespSlice, &TransactionTagInfoResponse{
|
||||
Id: 1,
|
||||
TagGroupId: 0,
|
||||
DisplayOrder: 3,
|
||||
})
|
||||
transactionTagRespSlice = append(transactionTagRespSlice, &TransactionTagInfoResponse{
|
||||
Id: 2,
|
||||
DisplayOrder: 1,
|
||||
TagGroupId: 1,
|
||||
DisplayOrder: 2,
|
||||
})
|
||||
transactionTagRespSlice = append(transactionTagRespSlice, &TransactionTagInfoResponse{
|
||||
Id: 3,
|
||||
TagGroupId: 0,
|
||||
DisplayOrder: 1,
|
||||
})
|
||||
transactionTagRespSlice = append(transactionTagRespSlice, &TransactionTagInfoResponse{
|
||||
Id: 4,
|
||||
TagGroupId: 2,
|
||||
DisplayOrder: 1,
|
||||
})
|
||||
transactionTagRespSlice = append(transactionTagRespSlice, &TransactionTagInfoResponse{
|
||||
Id: 5,
|
||||
TagGroupId: 1,
|
||||
DisplayOrder: 1,
|
||||
})
|
||||
transactionTagRespSlice = append(transactionTagRespSlice, &TransactionTagInfoResponse{
|
||||
Id: 6,
|
||||
TagGroupId: 0,
|
||||
DisplayOrder: 2,
|
||||
})
|
||||
|
||||
sort.Sort(transactionTagRespSlice)
|
||||
|
||||
assert.Equal(t, int64(2), transactionTagRespSlice[0].Id)
|
||||
assert.Equal(t, int64(3), transactionTagRespSlice[1].Id)
|
||||
assert.Equal(t, int64(3), transactionTagRespSlice[0].Id)
|
||||
assert.Equal(t, int64(6), transactionTagRespSlice[1].Id)
|
||||
assert.Equal(t, int64(1), transactionTagRespSlice[2].Id)
|
||||
assert.Equal(t, int64(5), transactionTagRespSlice[3].Id)
|
||||
assert.Equal(t, int64(2), transactionTagRespSlice[4].Id)
|
||||
assert.Equal(t, int64(4), transactionTagRespSlice[5].Id)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/datastore"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/uuid"
|
||||
)
|
||||
|
||||
// TransactionTagGroupService represents transaction tag group service
|
||||
type TransactionTagGroupService struct {
|
||||
ServiceUsingDB
|
||||
ServiceUsingUuid
|
||||
}
|
||||
|
||||
// Initialize a transaction tag group service singleton instance
|
||||
var (
|
||||
TransactionTagGroups = &TransactionTagGroupService{
|
||||
ServiceUsingDB: ServiceUsingDB{
|
||||
container: datastore.Container,
|
||||
},
|
||||
ServiceUsingUuid: ServiceUsingUuid{
|
||||
container: uuid.Container,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// GetAllTagGroupsByUid returns all transaction tag group models of user
|
||||
func (s *TransactionTagGroupService) GetAllTagGroupsByUid(c core.Context, uid int64) ([]*models.TransactionTagGroup, error) {
|
||||
if uid <= 0 {
|
||||
return nil, errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
var tagGroups []*models.TransactionTagGroup
|
||||
err := s.UserDataDB(uid).NewSession(c).Where("uid=? AND deleted=?", uid, false).Find(&tagGroups)
|
||||
|
||||
return tagGroups, err
|
||||
}
|
||||
|
||||
// GetTagGroupByTagGroupId returns a transaction tag group model according to transaction tag group id
|
||||
func (s *TransactionTagGroupService) GetTagGroupByTagGroupId(c core.Context, uid int64, tagGroupId int64) (*models.TransactionTagGroup, error) {
|
||||
if uid <= 0 {
|
||||
return nil, errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
if tagGroupId <= 0 {
|
||||
return nil, errs.ErrTransactionTagGroupIdInvalid
|
||||
}
|
||||
|
||||
tagGroup := &models.TransactionTagGroup{}
|
||||
has, err := s.UserDataDB(uid).NewSession(c).ID(tagGroupId).Where("uid=? AND deleted=?", uid, false).Get(tagGroup)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, errs.ErrTransactionTagGroupNotFound
|
||||
}
|
||||
|
||||
return tagGroup, nil
|
||||
}
|
||||
|
||||
// GetMaxDisplayOrder returns the max display order
|
||||
func (s *TransactionTagGroupService) GetMaxDisplayOrder(c core.Context, uid int64) (int32, error) {
|
||||
if uid <= 0 {
|
||||
return 0, errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
tagGroup := &models.TransactionTagGroup{}
|
||||
has, err := s.UserDataDB(uid).NewSession(c).Cols("uid", "deleted", "display_order").Where("uid=? AND deleted=?", uid, false).OrderBy("display_order desc").Limit(1).Get(tagGroup)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if has {
|
||||
return tagGroup.DisplayOrder, nil
|
||||
} else {
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTagGroup saves a new transaction tag group model to database
|
||||
func (s *TransactionTagGroupService) CreateTagGroup(c core.Context, tagGroup *models.TransactionTagGroup) error {
|
||||
if tagGroup.Uid <= 0 {
|
||||
return errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
tagGroup.TagGroupId = s.GenerateUuid(uuid.UUID_TYPE_TAG_GROUP)
|
||||
|
||||
if tagGroup.TagGroupId < 1 {
|
||||
return errs.ErrSystemIsBusy
|
||||
}
|
||||
|
||||
tagGroup.Deleted = false
|
||||
tagGroup.CreatedUnixTime = time.Now().Unix()
|
||||
tagGroup.UpdatedUnixTime = time.Now().Unix()
|
||||
|
||||
return s.UserDataDB(tagGroup.Uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||
_, err := sess.Insert(tagGroup)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// ModifyTagGroup saves an existed transaction tag group model to database
|
||||
func (s *TransactionTagGroupService) ModifyTagGroup(c core.Context, tagGroup *models.TransactionTagGroup) error {
|
||||
if tagGroup.Uid <= 0 {
|
||||
return errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
tagGroup.UpdatedUnixTime = time.Now().Unix()
|
||||
|
||||
return s.UserDataDB(tagGroup.Uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||
updatedRows, err := sess.ID(tagGroup.TagGroupId).Cols("name", "updated_unix_time").Where("uid=? AND deleted=?", tagGroup.Uid, false).Update(tagGroup)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if updatedRows < 1 {
|
||||
return errs.ErrTransactionTagGroupNotFound
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// ModifyTagGroupDisplayOrders updates display order of given transaction tag groups
|
||||
func (s *TransactionTagGroupService) ModifyTagGroupDisplayOrders(c core.Context, uid int64, tagGroups []*models.TransactionTagGroup) error {
|
||||
if uid <= 0 {
|
||||
return errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
for i := 0; i < len(tagGroups); i++ {
|
||||
tagGroups[i].UpdatedUnixTime = time.Now().Unix()
|
||||
}
|
||||
|
||||
return s.UserDataDB(uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||
for i := 0; i < len(tagGroups); i++ {
|
||||
tagGroup := tagGroups[i]
|
||||
updatedRows, err := sess.ID(tagGroup.TagGroupId).Cols("display_order", "updated_unix_time").Where("uid=? AND deleted=?", uid, false).Update(tagGroup)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if updatedRows < 1 {
|
||||
return errs.ErrTransactionTagGroupNotFound
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteTagGroup deletes an existed transaction tag group from database
|
||||
func (s *TransactionTagGroupService) DeleteTagGroup(c core.Context, uid int64, tagGroupId int64) error {
|
||||
if uid <= 0 {
|
||||
return errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
|
||||
updateModel := &models.TransactionTagGroup{
|
||||
Deleted: true,
|
||||
DeletedUnixTime: now,
|
||||
}
|
||||
|
||||
return s.UserDataDB(uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||
exists, err := sess.Cols("uid", "deleted").Where("uid=? AND deleted=? AND tag_group_id=?", uid, false, tagGroupId).Limit(1).Exist(&models.TransactionTag{})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
return errs.ErrTransactionTagGroupInUseCannotBeDeleted
|
||||
}
|
||||
|
||||
deletedRows, err := sess.ID(tagGroupId).Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).Update(updateModel)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if deletedRows < 1 {
|
||||
return errs.ErrTransactionTagGroupNotFound
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteAllTagGroups deletes all existed transaction tag groups from database
|
||||
func (s *TransactionTagGroupService) DeleteAllTagGroups(c core.Context, uid int64) error {
|
||||
if uid <= 0 {
|
||||
return errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
|
||||
updateModel := &models.TransactionTagGroup{
|
||||
Deleted: true,
|
||||
DeletedUnixTime: now,
|
||||
}
|
||||
|
||||
return s.UserDataDB(uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||
exists, err := sess.Cols("uid", "deleted").Where("uid=? AND deleted=? AND tag_group_id>?", uid, false, 0).Limit(1).Exist(&models.TransactionTag{})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
return errs.ErrTransactionTagGroupInUseCannotBeDeleted
|
||||
}
|
||||
|
||||
_, err = sess.Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).Update(updateModel)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -101,13 +101,13 @@ func (s *TransactionTagService) GetTagsByTagIds(c core.Context, uid int64, tagId
|
||||
}
|
||||
|
||||
// GetMaxDisplayOrder returns the max display order
|
||||
func (s *TransactionTagService) GetMaxDisplayOrder(c core.Context, uid int64) (int32, error) {
|
||||
func (s *TransactionTagService) GetMaxDisplayOrder(c core.Context, uid int64, tagGroupId int64) (int32, error) {
|
||||
if uid <= 0 {
|
||||
return 0, errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
tag := &models.TransactionTag{}
|
||||
has, err := s.UserDataDB(uid).NewSession(c).Cols("uid", "deleted", "display_order").Where("uid=? AND deleted=?", uid, false).OrderBy("display_order desc").Limit(1).Get(tag)
|
||||
has, err := s.UserDataDB(uid).NewSession(c).Cols("uid", "deleted", "display_order").Where("uid=? AND deleted=? AND tag_group_id=?", uid, false, tagGroupId).OrderBy("display_order desc").Limit(1).Get(tag)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -294,23 +294,25 @@ func (s *TransactionTagService) CreateTags(c core.Context, uid int64, tags []*mo
|
||||
}
|
||||
|
||||
// ModifyTag saves an existed transaction tag model to database
|
||||
func (s *TransactionTagService) ModifyTag(c core.Context, tag *models.TransactionTag) error {
|
||||
func (s *TransactionTagService) ModifyTag(c core.Context, tag *models.TransactionTag, tagNameChanged bool) error {
|
||||
if tag.Uid <= 0 {
|
||||
return errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
exists, err := s.ExistsTagName(c, tag.Uid, tag.Name)
|
||||
if tagNameChanged {
|
||||
exists, err := s.ExistsTagName(c, tag.Uid, tag.Name)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
return errs.ErrTransactionTagNameAlreadyExists
|
||||
if err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
return errs.ErrTransactionTagNameAlreadyExists
|
||||
}
|
||||
}
|
||||
|
||||
tag.UpdatedUnixTime = time.Now().Unix()
|
||||
|
||||
return s.UserDataDB(tag.Uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||
updatedRows, err := sess.ID(tag.TagId).Cols("name", "updated_unix_time").Where("uid=? AND deleted=?", tag.Uid, false).Update(tag)
|
||||
updatedRows, err := sess.ID(tag.TagId).Cols("name", "tag_group_id", "display_order", "updated_unix_time").Where("uid=? AND deleted=?", tag.Uid, false).Update(tag)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -15,4 +15,5 @@ const (
|
||||
UUID_TYPE_TEMPLATE UuidType = 7
|
||||
UUID_TYPE_PICTURE UuidType = 8
|
||||
UUID_TYPE_EXPLORER UuidType = 9
|
||||
UUID_TYPE_TAG_GROUP UuidType = 10
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user