mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-19 01:04:25 +08:00
credit card account supports statement date
This commit is contained in:
+54
-2
@@ -174,6 +174,11 @@ func (a *AccountsApi) AccountCreateHandler(c *core.WebContext) (any, *errs.Error
|
||||
log.Warnf(c, "[accounts.AccountCreateHandler] account balance time is not set")
|
||||
return nil, errs.ErrAccountBalanceTimeNotSet
|
||||
}
|
||||
|
||||
if accountCreateReq.Category != models.ACCOUNT_CATEGORY_CREDIT_CARD && accountCreateReq.CreditCardStatementDate != 0 {
|
||||
log.Warnf(c, "[accounts.AccountCreateHandler] cannot set statement date with category \"%d\"", accountCreateReq.Category)
|
||||
return nil, errs.ErrCannotSetStatementDateForNonCreditCard
|
||||
}
|
||||
} else if accountCreateReq.Type == models.ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS {
|
||||
if len(accountCreateReq.SubAccounts) < 1 {
|
||||
log.Warnf(c, "[accounts.AccountCreateHandler] account does not have any sub-accounts")
|
||||
@@ -212,6 +217,11 @@ func (a *AccountsApi) AccountCreateHandler(c *core.WebContext) (any, *errs.Error
|
||||
log.Warnf(c, "[accounts.AccountCreateHandler] sub-account#%d balance time is not set", i)
|
||||
return nil, errs.ErrAccountBalanceTimeNotSet
|
||||
}
|
||||
|
||||
if subAccount.Category != models.ACCOUNT_CATEGORY_CREDIT_CARD && subAccount.CreditCardStatementDate != 0 {
|
||||
log.Warnf(c, "[accounts.AccountCreateHandler] sub-account#%d cannot set statement date with category \"%d\"", i, subAccount.Category)
|
||||
return nil, errs.ErrCannotSetStatementDateForNonCreditCard
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Warnf(c, "[accounts.AccountCreateHandler] account type invalid, type is %d", accountCreateReq.Type)
|
||||
@@ -312,8 +322,9 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
|
||||
}
|
||||
|
||||
accountMap := a.accounts.GetAccountMapByList(accountAndSubAccounts)
|
||||
mainAccount, exists := accountMap[accountModifyReq.Id]
|
||||
|
||||
if _, exists := accountMap[accountModifyReq.Id]; !exists {
|
||||
if !exists {
|
||||
return nil, errs.ErrAccountNotFound
|
||||
}
|
||||
|
||||
@@ -321,10 +332,26 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
|
||||
return nil, errs.ErrCannotAddOrDeleteSubAccountsWhenModify
|
||||
}
|
||||
|
||||
if mainAccount.Type == models.ACCOUNT_TYPE_SINGLE_ACCOUNT {
|
||||
if accountModifyReq.Category != models.ACCOUNT_CATEGORY_CREDIT_CARD && accountModifyReq.CreditCardStatementDate != 0 {
|
||||
log.Warnf(c, "[accounts.AccountModifyHandler] cannot set statement date with category \"%d\"", accountModifyReq.Category)
|
||||
return nil, errs.ErrCannotSetStatementDateForNonCreditCard
|
||||
}
|
||||
} else if mainAccount.Type == models.ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS {
|
||||
for i := 0; i < len(accountModifyReq.SubAccounts); i++ {
|
||||
subAccount := accountModifyReq.SubAccounts[i]
|
||||
|
||||
if subAccount.Category != models.ACCOUNT_CATEGORY_CREDIT_CARD && subAccount.CreditCardStatementDate != 0 {
|
||||
log.Warnf(c, "[accounts.AccountModifyHandler] sub-account#%d cannot set statement date with category \"%d\"", i, subAccount.Category)
|
||||
return nil, errs.ErrCannotSetStatementDateForNonCreditCard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anythingUpdate := false
|
||||
var toUpdateAccounts []*models.Account
|
||||
|
||||
toUpdateAccount := a.getToUpdateAccount(uid, &accountModifyReq, accountMap[accountModifyReq.Id])
|
||||
toUpdateAccount := a.getToUpdateAccount(uid, &accountModifyReq, mainAccount)
|
||||
|
||||
if toUpdateAccount != nil {
|
||||
anythingUpdate = true
|
||||
@@ -479,6 +506,12 @@ func (a *AccountsApi) AccountDeleteHandler(c *core.WebContext) (any, *errs.Error
|
||||
}
|
||||
|
||||
func (a *AccountsApi) createNewAccountModel(uid int64, accountCreateReq *models.AccountCreateRequest, order int32) *models.Account {
|
||||
accountExtend := &models.AccountExtend{}
|
||||
|
||||
if accountCreateReq.Category == models.ACCOUNT_CATEGORY_CREDIT_CARD {
|
||||
accountExtend.CreditCardStatementDate = &accountCreateReq.CreditCardStatementDate
|
||||
}
|
||||
|
||||
return &models.Account{
|
||||
Uid: uid,
|
||||
Name: accountCreateReq.Name,
|
||||
@@ -490,6 +523,7 @@ func (a *AccountsApi) createNewAccountModel(uid int64, accountCreateReq *models.
|
||||
Currency: accountCreateReq.Currency,
|
||||
Balance: accountCreateReq.Balance,
|
||||
Comment: accountCreateReq.Comment,
|
||||
Extend: accountExtend,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,6 +544,12 @@ func (a *AccountsApi) createSubAccountModels(uid int64, accountCreateReq *models
|
||||
}
|
||||
|
||||
func (a *AccountsApi) getToUpdateAccount(uid int64, accountModifyReq *models.AccountModifyRequest, oldAccount *models.Account) *models.Account {
|
||||
newAccountExtend := &models.AccountExtend{}
|
||||
|
||||
if accountModifyReq.Category == models.ACCOUNT_CATEGORY_CREDIT_CARD {
|
||||
newAccountExtend.CreditCardStatementDate = &accountModifyReq.CreditCardStatementDate
|
||||
}
|
||||
|
||||
newAccount := &models.Account{
|
||||
AccountId: oldAccount.AccountId,
|
||||
Uid: uid,
|
||||
@@ -518,6 +558,7 @@ func (a *AccountsApi) getToUpdateAccount(uid int64, accountModifyReq *models.Acc
|
||||
Icon: accountModifyReq.Icon,
|
||||
Color: accountModifyReq.Color,
|
||||
Comment: accountModifyReq.Comment,
|
||||
Extend: newAccountExtend,
|
||||
Hidden: accountModifyReq.Hidden,
|
||||
}
|
||||
|
||||
@@ -530,5 +571,16 @@ func (a *AccountsApi) getToUpdateAccount(uid int64, accountModifyReq *models.Acc
|
||||
return newAccount
|
||||
}
|
||||
|
||||
if (newAccount.Extend != nil && oldAccount.Extend == nil) ||
|
||||
(newAccount.Extend == nil && oldAccount.Extend != nil) {
|
||||
return newAccount
|
||||
}
|
||||
|
||||
oldAccountExtend := oldAccount.Extend
|
||||
|
||||
if newAccountExtend.CreditCardStatementDate != oldAccountExtend.CreditCardStatementDate {
|
||||
return newAccount
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,4 +20,5 @@ var (
|
||||
ErrAccountInUseCannotBeDeleted = NewNormalError(NormalSubcategoryAccount, 13, http.StatusBadRequest, "account is in use and cannot be deleted")
|
||||
ErrAccountCategoryInvalid = NewNormalError(NormalSubcategoryAccount, 14, http.StatusBadRequest, "account category is invalid")
|
||||
ErrAccountBalanceTimeNotSet = NewNormalError(NormalSubcategoryAccount, 15, http.StatusBadRequest, "account balance time is not set")
|
||||
ErrCannotSetStatementDateForNonCreditCard = NewNormalError(NormalSubcategoryAccount, 16, http.StatusBadRequest, "cannot set statement date for non credit card account")
|
||||
)
|
||||
|
||||
+83
-49
@@ -1,5 +1,7 @@
|
||||
package models
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// LevelOneAccountParentId represents the parent id of level-one account
|
||||
const LevelOneAccountParentId = 0
|
||||
|
||||
@@ -52,6 +54,8 @@ const (
|
||||
ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS AccountType = 2
|
||||
)
|
||||
|
||||
var defaultCreditCardAccountStatementDate = 0
|
||||
|
||||
// Account represents account data stored in database
|
||||
type Account struct {
|
||||
AccountId int64 `xorm:"PK"`
|
||||
@@ -67,37 +71,45 @@ type Account struct {
|
||||
Currency string `xorm:"VARCHAR(3) NOT NULL"`
|
||||
Balance int64 `xorm:"NOT NULL"`
|
||||
Comment string `xorm:"VARCHAR(255) NOT NULL"`
|
||||
Extend *AccountExtend `xorm:"BLOB"`
|
||||
Hidden bool `xorm:"NOT NULL"`
|
||||
CreatedUnixTime int64
|
||||
UpdatedUnixTime int64
|
||||
DeletedUnixTime int64
|
||||
}
|
||||
|
||||
// AccountExtend represents account extend data stored in database
|
||||
type AccountExtend struct {
|
||||
CreditCardStatementDate *int `json:"creditCardStatementDate"`
|
||||
}
|
||||
|
||||
// AccountCreateRequest represents all parameters of account creation request
|
||||
type AccountCreateRequest struct {
|
||||
Name string `json:"name" binding:"required,notBlank,max=32"`
|
||||
Category AccountCategory `json:"category" binding:"required"`
|
||||
Type AccountType `json:"type" binding:"required"`
|
||||
Icon int64 `json:"icon,string" binding:"required,min=1"`
|
||||
Color string `json:"color" binding:"required,len=6,validHexRGBColor"`
|
||||
Currency string `json:"currency" binding:"required,len=3,validCurrency"`
|
||||
Balance int64 `json:"balance"`
|
||||
BalanceTime int64 `json:"balanceTime"`
|
||||
Comment string `json:"comment" binding:"max=255"`
|
||||
SubAccounts []*AccountCreateRequest `json:"subAccounts" binding:"omitempty"`
|
||||
ClientSessionId string `json:"clientSessionId"`
|
||||
Name string `json:"name" binding:"required,notBlank,max=32"`
|
||||
Category AccountCategory `json:"category" binding:"required"`
|
||||
Type AccountType `json:"type" binding:"required"`
|
||||
Icon int64 `json:"icon,string" binding:"required,min=1"`
|
||||
Color string `json:"color" binding:"required,len=6,validHexRGBColor"`
|
||||
Currency string `json:"currency" binding:"required,len=3,validCurrency"`
|
||||
Balance int64 `json:"balance"`
|
||||
BalanceTime int64 `json:"balanceTime"`
|
||||
Comment string `json:"comment" binding:"max=255"`
|
||||
CreditCardStatementDate int `json:"creditCardStatementDate" binding:"min=0,max=28"`
|
||||
SubAccounts []*AccountCreateRequest `json:"subAccounts" binding:"omitempty"`
|
||||
ClientSessionId string `json:"clientSessionId"`
|
||||
}
|
||||
|
||||
// AccountModifyRequest represents all parameters of account modification request
|
||||
type AccountModifyRequest struct {
|
||||
Id int64 `json:"id,string" binding:"required,min=1"`
|
||||
Name string `json:"name" binding:"required,notBlank,max=32"`
|
||||
Category AccountCategory `json:"category" binding:"required"`
|
||||
Icon int64 `json:"icon,string" binding:"min=1"`
|
||||
Color string `json:"color" binding:"required,len=6,validHexRGBColor"`
|
||||
Comment string `json:"comment" binding:"max=255"`
|
||||
Hidden bool `json:"hidden"`
|
||||
SubAccounts []*AccountModifyRequest `json:"subAccounts" binding:"omitempty"`
|
||||
Id int64 `json:"id,string" binding:"required,min=1"`
|
||||
Name string `json:"name" binding:"required,notBlank,max=32"`
|
||||
Category AccountCategory `json:"category" binding:"required"`
|
||||
Icon int64 `json:"icon,string" binding:"min=1"`
|
||||
Color string `json:"color" binding:"required,len=6,validHexRGBColor"`
|
||||
Comment string `json:"comment" binding:"max=255"`
|
||||
CreditCardStatementDate int `json:"creditCardStatementDate" binding:"min=0,max=28"`
|
||||
Hidden bool `json:"hidden"`
|
||||
SubAccounts []*AccountModifyRequest `json:"subAccounts" binding:"omitempty"`
|
||||
}
|
||||
|
||||
// AccountListRequest represents all parameters of account listing request
|
||||
@@ -134,41 +146,63 @@ type AccountDeleteRequest struct {
|
||||
|
||||
// AccountInfoResponse represents a view-object of account
|
||||
type AccountInfoResponse struct {
|
||||
Id int64 `json:"id,string"`
|
||||
Name string `json:"name"`
|
||||
ParentId int64 `json:"parentId,string"`
|
||||
Category AccountCategory `json:"category"`
|
||||
Type AccountType `json:"type"`
|
||||
Icon int64 `json:"icon,string"`
|
||||
Color string `json:"color"`
|
||||
Currency string `json:"currency"`
|
||||
Balance int64 `json:"balance"`
|
||||
Comment string `json:"comment"`
|
||||
DisplayOrder int32 `json:"displayOrder"`
|
||||
IsAsset bool `json:"isAsset,omitempty"`
|
||||
IsLiability bool `json:"isLiability,omitempty"`
|
||||
Hidden bool `json:"hidden"`
|
||||
SubAccounts AccountInfoResponseSlice `json:"subAccounts,omitempty"`
|
||||
Id int64 `json:"id,string"`
|
||||
Name string `json:"name"`
|
||||
ParentId int64 `json:"parentId,string"`
|
||||
Category AccountCategory `json:"category"`
|
||||
Type AccountType `json:"type"`
|
||||
Icon int64 `json:"icon,string"`
|
||||
Color string `json:"color"`
|
||||
Currency string `json:"currency"`
|
||||
Balance int64 `json:"balance"`
|
||||
Comment string `json:"comment"`
|
||||
CreditCardStatementDate *int `json:"creditCardStatementDate,omitempty"`
|
||||
DisplayOrder int32 `json:"displayOrder"`
|
||||
IsAsset bool `json:"isAsset,omitempty"`
|
||||
IsLiability bool `json:"isLiability,omitempty"`
|
||||
Hidden bool `json:"hidden"`
|
||||
SubAccounts AccountInfoResponseSlice `json:"subAccounts,omitempty"`
|
||||
}
|
||||
|
||||
// ToAccountInfoResponse returns a view-object according to database model
|
||||
func (a *Account) ToAccountInfoResponse() *AccountInfoResponse {
|
||||
return &AccountInfoResponse{
|
||||
Id: a.AccountId,
|
||||
Name: a.Name,
|
||||
ParentId: a.ParentAccountId,
|
||||
Category: a.Category,
|
||||
Type: a.Type,
|
||||
Icon: a.Icon,
|
||||
Color: a.Color,
|
||||
Currency: a.Currency,
|
||||
Balance: a.Balance,
|
||||
Comment: a.Comment,
|
||||
DisplayOrder: a.DisplayOrder,
|
||||
IsAsset: assetAccountCategory[a.Category],
|
||||
IsLiability: liabilityAccountCategory[a.Category],
|
||||
Hidden: a.Hidden,
|
||||
var creditCardStatementDate *int
|
||||
|
||||
if a.Category == ACCOUNT_CATEGORY_CREDIT_CARD {
|
||||
if a.Extend != nil {
|
||||
creditCardStatementDate = a.Extend.CreditCardStatementDate
|
||||
} else {
|
||||
creditCardStatementDate = &defaultCreditCardAccountStatementDate
|
||||
}
|
||||
}
|
||||
|
||||
return &AccountInfoResponse{
|
||||
Id: a.AccountId,
|
||||
Name: a.Name,
|
||||
ParentId: a.ParentAccountId,
|
||||
Category: a.Category,
|
||||
Type: a.Type,
|
||||
Icon: a.Icon,
|
||||
Color: a.Color,
|
||||
Currency: a.Currency,
|
||||
Balance: a.Balance,
|
||||
Comment: a.Comment,
|
||||
CreditCardStatementDate: creditCardStatementDate,
|
||||
DisplayOrder: a.DisplayOrder,
|
||||
IsAsset: assetAccountCategory[a.Category],
|
||||
IsLiability: liabilityAccountCategory[a.Category],
|
||||
Hidden: a.Hidden,
|
||||
}
|
||||
}
|
||||
|
||||
// FromDB fills the fields from the data stored in database
|
||||
func (a *AccountExtend) FromDB(data []byte) error {
|
||||
return json.Unmarshal(data, a)
|
||||
}
|
||||
|
||||
// ToDB returns the actual stored data in database
|
||||
func (a *AccountExtend) ToDB() ([]byte, error) {
|
||||
return json.Marshal(a)
|
||||
}
|
||||
|
||||
// AccountInfoResponseSlice represents the slice data structure of AccountInfoResponse
|
||||
|
||||
@@ -329,7 +329,7 @@ func (s *AccountService) ModifyAccounts(c core.Context, uid int64, accounts []*m
|
||||
return s.UserDataDB(uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||
for i := 0; i < len(accounts); i++ {
|
||||
account := accounts[i]
|
||||
updatedRows, err := sess.ID(account.AccountId).Cols("name", "category", "icon", "color", "comment", "hidden", "updated_unix_time").Where("uid=? AND deleted=?", uid, false).Update(account)
|
||||
updatedRows, err := sess.ID(account.AccountId).Cols("name", "category", "icon", "color", "comment", "extend", "hidden", "updated_unix_time").Where("uid=? AND deleted=?", uid, false).Update(account)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user