mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-14 06:57:35 +08:00
support last reconciled time for account
This commit is contained in:
@@ -953,6 +953,7 @@ func printUserInfo(user *models.User) {
|
||||
fmt.Printf("[Password] %s\n", user.Password)
|
||||
fmt.Printf("[Salt] %s\n", user.Salt)
|
||||
fmt.Printf("[DefaultAccountId] %d\n", user.DefaultAccountId)
|
||||
fmt.Printf("[UseLastReconciledTime] %t\n", user.UseLastReconciledTime)
|
||||
fmt.Printf("[TransactionEditScope] %s (%d)\n", user.TransactionEditScope, user.TransactionEditScope)
|
||||
fmt.Printf("[Language] %s\n", user.Language)
|
||||
fmt.Printf("[DefaultCurrency] %s\n", user.DefaultCurrency)
|
||||
|
||||
+9
-5
@@ -766,6 +766,7 @@ func (a *AccountsApi) createSubAccountModels(uid int64, accountCreateReq *models
|
||||
|
||||
func (a *AccountsApi) getToUpdateAccount(uid int64, accountModifyReq *models.AccountModifyRequest, oldAccount *models.Account, isSubAccount bool) *models.Account {
|
||||
newAccountExtend := &models.AccountExtend{}
|
||||
newAccountExtend.LastReconciledTime = accountModifyReq.LastReconciledTime
|
||||
|
||||
if !isSubAccount && accountModifyReq.Category == models.ACCOUNT_CATEGORY_CREDIT_CARD {
|
||||
newAccountExtend.CreditCardStatementDate = &accountModifyReq.CreditCardStatementDate
|
||||
@@ -793,14 +794,17 @@ func (a *AccountsApi) getToUpdateAccount(uid int64, accountModifyReq *models.Acc
|
||||
return newAccount
|
||||
}
|
||||
|
||||
if (newAccount.Extend != nil && oldAccount.Extend == nil) ||
|
||||
(newAccount.Extend == nil && oldAccount.Extend != nil) {
|
||||
oldAccountExtend := oldAccount.Extend
|
||||
|
||||
if (newAccountExtend.LastReconciledTime != nil && (oldAccountExtend == nil || oldAccountExtend.LastReconciledTime == nil)) ||
|
||||
(newAccountExtend.LastReconciledTime == nil && oldAccountExtend != nil && oldAccountExtend.LastReconciledTime != nil) ||
|
||||
(newAccountExtend.LastReconciledTime != nil && oldAccountExtend != nil && oldAccountExtend.LastReconciledTime != nil && *newAccountExtend.LastReconciledTime != *oldAccountExtend.LastReconciledTime) {
|
||||
return newAccount
|
||||
}
|
||||
|
||||
oldAccountExtend := oldAccount.Extend
|
||||
|
||||
if newAccountExtend.CreditCardStatementDate != oldAccountExtend.CreditCardStatementDate {
|
||||
if (newAccountExtend.CreditCardStatementDate != nil && (oldAccountExtend == nil || oldAccountExtend.CreditCardStatementDate == nil)) ||
|
||||
(newAccountExtend.CreditCardStatementDate == nil && oldAccountExtend != nil && oldAccountExtend.CreditCardStatementDate != nil) ||
|
||||
(newAccountExtend.CreditCardStatementDate != nil && oldAccountExtend != nil && oldAccountExtend.CreditCardStatementDate != nil && *newAccountExtend.CreditCardStatementDate != *oldAccountExtend.CreditCardStatementDate) {
|
||||
return newAccount
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ func (a *ForgetPasswordsApi) UserResetPasswordHandler(c *core.WebContext) (any,
|
||||
Password: request.Password,
|
||||
}
|
||||
|
||||
_, _, err = a.users.UpdateUser(c, userNew, false)
|
||||
_, _, err = a.users.UpdateUser(c, userNew, false, false)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[forget_passwords.UserResetPasswordHandler] failed to update user \"uid:%d\", because %s", user.Uid, err.Error())
|
||||
|
||||
+129
-16
@@ -1075,7 +1075,15 @@ func (a *TransactionsApi) TransactionCreateHandler(c *core.WebContext) (any, *er
|
||||
}
|
||||
|
||||
transaction := a.createNewTransactionModel(uid, &transactionCreateReq, c.ClientIP())
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
|
||||
allUsedAccounts, err := a.getTransactionUsedAccounts(c, uid, []*models.Transaction{transaction})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionCreateHandler] failed to get transaction used accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, allUsedAccounts[transaction.AccountId], allUsedAccounts[transaction.RelatedAccountId])
|
||||
|
||||
if !transactionEditable {
|
||||
return nil, errs.ErrCannotCreateTransactionWithThisTransactionTime
|
||||
@@ -1268,8 +1276,15 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.WebContext) (any, *er
|
||||
return nil, errs.ErrNothingWillBeUpdated
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
newTransactionEditable := user.CanEditTransactionByTransactionTime(newTransaction.TransactionTime, clientTimezone)
|
||||
allUsedAccounts, err := a.getTransactionUsedAccounts(c, uid, []*models.Transaction{transaction, newTransaction})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionModifyHandler] failed to get transaction used accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, allUsedAccounts[transaction.AccountId], allUsedAccounts[transaction.RelatedAccountId])
|
||||
newTransactionEditable := user.CanEditTransactionByTransactionTime(newTransaction.TransactionTime, clientTimezone, allUsedAccounts[newTransaction.AccountId], allUsedAccounts[newTransaction.RelatedAccountId])
|
||||
|
||||
if !transactionEditable || !newTransactionEditable {
|
||||
return nil, errs.ErrCannotModifyTransactionWithThisTransactionTime
|
||||
@@ -1402,6 +1417,13 @@ func (a *TransactionsApi) TransactionBatchUpdateCategoriesHandler(c *core.WebCon
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
allUsedAccounts, err := a.getTransactionUsedAccounts(c, uid, transactions)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] failed to get transaction used accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
allTransactionIds := make([]int64, 0, len(transactions))
|
||||
|
||||
for i := 0; i < len(transactions); i++ {
|
||||
@@ -1412,7 +1434,7 @@ func (a *TransactionsApi) TransactionBatchUpdateCategoriesHandler(c *core.WebCon
|
||||
return nil, errs.ErrTransactionTypeInvalid
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, allUsedAccounts[transaction.AccountId], allUsedAccounts[transaction.RelatedAccountId])
|
||||
|
||||
if !transactionEditable {
|
||||
log.Warnf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] transaction \"id:%d\" is not editable for user \"uid:%d\"", transaction.TransactionId, uid)
|
||||
@@ -1548,9 +1570,19 @@ func (a *TransactionsApi) TransactionBatchUpdateAccountsHandler(c *core.WebConte
|
||||
return nil, errs.ErrCannotMoveTransactionBetweenAccountsWithDifferentCurrencies
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
newSourceAccount := accountMap[transaction.AccountId]
|
||||
newDestinationAccount := accountMap[transaction.RelatedAccountId]
|
||||
|
||||
if !transactionEditable {
|
||||
if !transactionBatchUpdateReq.IsDestinationAccount && transaction.AccountId != account.AccountId {
|
||||
newSourceAccount = account
|
||||
} else if transactionBatchUpdateReq.IsDestinationAccount && transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT && transaction.RelatedAccountId != account.AccountId {
|
||||
newDestinationAccount = account
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, accountMap[transaction.AccountId], accountMap[transaction.RelatedAccountId])
|
||||
newTransactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, newSourceAccount, newDestinationAccount)
|
||||
|
||||
if !transactionEditable || !newTransactionEditable {
|
||||
log.Warnf(c, "[transactions.TransactionBatchUpdateAccountsHandler] transaction \"id:%d\" is not editable for user \"uid:%d\"", transaction.TransactionId, uid)
|
||||
return nil, errs.ErrCannotModifyTransactionWithThisTransactionTime
|
||||
}
|
||||
@@ -1651,6 +1683,13 @@ func (a *TransactionsApi) TransactionBatchAddTagsHandler(c *core.WebContext) (an
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
allUsedAccounts, err := a.getTransactionUsedAccounts(c, uid, transactions)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionBatchAddTagsHandler] failed to get transaction used accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
transactionTagIndexes, err := a.transactionTags.GetAllTagIdsOfTransactions(c, uid, transactionIds)
|
||||
|
||||
if err != nil {
|
||||
@@ -1668,7 +1707,7 @@ func (a *TransactionsApi) TransactionBatchAddTagsHandler(c *core.WebContext) (an
|
||||
return nil, errs.ErrTransactionTypeInvalid
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, allUsedAccounts[transaction.AccountId], allUsedAccounts[transaction.RelatedAccountId])
|
||||
|
||||
if !transactionEditable {
|
||||
log.Warnf(c, "[transactions.TransactionBatchAddTagsHandler] transaction \"id:%d\" is not editable for user \"uid:%d\"", transaction.TransactionId, uid)
|
||||
@@ -1769,6 +1808,13 @@ func (a *TransactionsApi) TransactionBatchRemoveTagsHandler(c *core.WebContext)
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
allUsedAccounts, err := a.getTransactionUsedAccounts(c, uid, transactions)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionBatchRemoveTagsHandler] failed to get transaction used accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
allTransactionIds := make([]int64, 0, len(transactions))
|
||||
|
||||
for i := 0; i < len(transactions); i++ {
|
||||
@@ -1779,7 +1825,7 @@ func (a *TransactionsApi) TransactionBatchRemoveTagsHandler(c *core.WebContext)
|
||||
return nil, errs.ErrTransactionTypeInvalid
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, allUsedAccounts[transaction.AccountId], allUsedAccounts[transaction.RelatedAccountId])
|
||||
|
||||
if !transactionEditable {
|
||||
log.Warnf(c, "[transactions.TransactionBatchRemoveTagsHandler] transaction \"id:%d\" is not editable for user \"uid:%d\"", transaction.TransactionId, uid)
|
||||
@@ -1842,6 +1888,13 @@ func (a *TransactionsApi) TransactionBatchClearTagsHandler(c *core.WebContext) (
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
allUsedAccounts, err := a.getTransactionUsedAccounts(c, uid, transactions)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionBatchClearTagsHandler] failed to get transaction used accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
allTransactionIds := make([]int64, 0, len(transactions))
|
||||
|
||||
for i := 0; i < len(transactions); i++ {
|
||||
@@ -1852,7 +1905,7 @@ func (a *TransactionsApi) TransactionBatchClearTagsHandler(c *core.WebContext) (
|
||||
return nil, errs.ErrTransactionTypeInvalid
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, allUsedAccounts[transaction.AccountId], allUsedAccounts[transaction.RelatedAccountId])
|
||||
|
||||
if !transactionEditable {
|
||||
log.Warnf(c, "[transactions.TransactionBatchClearTagsHandler] transaction \"id:%d\" is not editable for user \"uid:%d\"", transaction.TransactionId, uid)
|
||||
@@ -1970,7 +2023,14 @@ func (a *TransactionsApi) TransactionDeleteHandler(c *core.WebContext) (any, *er
|
||||
return nil, errs.ErrTransactionTypeInvalid
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
allUsedAccounts, err := a.getTransactionUsedAccounts(c, uid, []*models.Transaction{transaction})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionDeleteHandler] failed to get transaction used accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, allUsedAccounts[transaction.AccountId], allUsedAccounts[transaction.RelatedAccountId])
|
||||
|
||||
if !transactionEditable {
|
||||
return nil, errs.ErrCannotDeleteTransactionWithThisTransactionTime
|
||||
@@ -2033,13 +2093,20 @@ func (a *TransactionsApi) TransactionBatchDeleteHandler(c *core.WebContext) (any
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
allUsedAccounts, err := a.getTransactionUsedAccounts(c, uid, transactions)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionBatchDeleteHandler] failed to get transaction used accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
for i := 0; i < len(transactions); i++ {
|
||||
transaction := transactions[i]
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, allUsedAccounts[transaction.AccountId], allUsedAccounts[transaction.RelatedAccountId])
|
||||
|
||||
if !transactionEditable {
|
||||
log.Warnf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] transaction \"id:%d\" is not editable for user \"uid:%d\"", transaction.TransactionId, uid)
|
||||
return nil, errs.ErrCannotModifyTransactionWithThisTransactionTime
|
||||
log.Warnf(c, "[transactions.TransactionBatchDeleteHandler] transaction \"id:%d\" is not editable for user \"uid:%d\"", transaction.TransactionId, uid)
|
||||
return nil, errs.ErrCannotDeleteTransactionWithThisTransactionTime
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2470,13 +2537,24 @@ func (a *TransactionsApi) TransactionImportHandler(c *core.WebContext) (any, *er
|
||||
for i := 0; i < len(transactionImportReq.Transactions); i++ {
|
||||
transactionCreateReq := transactionImportReq.Transactions[i]
|
||||
transaction := a.createNewTransactionModel(uid, transactionCreateReq, c.ClientIP())
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
newTransactions[i] = transaction
|
||||
}
|
||||
|
||||
allUsedAccounts, err := a.getTransactionUsedAccounts(c, uid, newTransactions)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionImportHandler] failed to get transaction used accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
for i := 0; i < len(newTransactions); i++ {
|
||||
transaction := newTransactions[i]
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone, allUsedAccounts[transaction.AccountId], allUsedAccounts[transaction.RelatedAccountId])
|
||||
|
||||
if !transactionEditable {
|
||||
log.Warnf(c, "[transactions.TransactionImportHandler] transaction \"index:%d\" is not editable for user \"uid:%d\"", i, uid)
|
||||
return nil, errs.ErrCannotCreateTransactionWithThisTransactionTime
|
||||
}
|
||||
|
||||
newTransactions[i] = transaction
|
||||
}
|
||||
|
||||
err = a.transactions.BatchCreateTransactions(c, user.Uid, newTransactions, newTransactionTagIdsMap, func(currentProcess float64) {
|
||||
@@ -2708,6 +2786,41 @@ func (a *TransactionsApi) getTransactionEssentialDataByTransactionIds(c *core.We
|
||||
return accountMap, categoryMap, tagMap, allTransactionTagIds, pictureInfoMap, nil
|
||||
}
|
||||
|
||||
func (a *TransactionsApi) getTransactionUsedAccounts(c *core.WebContext, uid int64, transactions []*models.Transaction) (map[int64]*models.Account, error) {
|
||||
accountIds := make([]int64, 0, len(transactions)*2)
|
||||
|
||||
for i := 0; i < len(transactions); i++ {
|
||||
accountIds = append(accountIds, transactions[i].AccountId)
|
||||
|
||||
if transactions[i].Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN || transactions[i].Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
|
||||
accountIds = append(accountIds, transactions[i].RelatedAccountId)
|
||||
}
|
||||
}
|
||||
|
||||
accountMap, err := a.accounts.GetAccountsByAccountIds(c, uid, utils.ToUniqueInt64Slice(accountIds))
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.getTransactionUsedAccounts] failed to get accounts for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
for i := 0; i < len(transactions); i++ {
|
||||
if _, exists := accountMap[transactions[i].AccountId]; !exists {
|
||||
log.Warnf(c, "[transactions.getTransactionUsedAccounts] account of transaction \"id:%d\" does not exist for user \"uid:%d\"", transactions[i].TransactionId, uid)
|
||||
return nil, errs.ErrSourceAccountNotFound
|
||||
}
|
||||
|
||||
if transactions[i].Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN || transactions[i].Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
|
||||
if _, exists := accountMap[transactions[i].RelatedAccountId]; !exists {
|
||||
log.Warnf(c, "[transactions.getTransactionUsedAccounts] related account of transaction \"id:%d\" does not exist for user \"uid:%d\"", transactions[i].TransactionId, uid)
|
||||
return nil, errs.ErrDestinationAccountNotFound
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return accountMap, nil
|
||||
}
|
||||
|
||||
func (a *TransactionsApi) getTransactionResponseListResult(c *core.WebContext, user *models.User, transactions []*models.Transaction, allAccounts map[int64]*models.Account, categoryMap map[int64]*models.TransactionCategory, tagMap map[int64]*models.TransactionTag, allTransactionTagIds map[int64][]int64, pictureInfoMap map[int64][]*models.TransactionPictureInfo, clientTimezone *time.Location, withPictures bool, trimAccount bool, trimCategory bool, trimTag bool) (models.TransactionInfoResponseSlice, error) {
|
||||
result := make(models.TransactionInfoResponseSlice, len(transactions))
|
||||
|
||||
|
||||
+12
-1
@@ -256,6 +256,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
userUpdateReq.Nickname = strings.TrimSpace(userUpdateReq.Nickname)
|
||||
|
||||
modifyProfileBasicInfo := false
|
||||
modifyUseLastReconciledTime := false
|
||||
anythingUpdate := false
|
||||
userNew := &models.User{
|
||||
Uid: user.Uid,
|
||||
@@ -317,6 +318,16 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
anythingUpdate = true
|
||||
}
|
||||
|
||||
if userUpdateReq.UseLastReconciledTime != nil && *userUpdateReq.UseLastReconciledTime != user.UseLastReconciledTime {
|
||||
user.UseLastReconciledTime = *userUpdateReq.UseLastReconciledTime
|
||||
userNew.UseLastReconciledTime = *userUpdateReq.UseLastReconciledTime
|
||||
modifyProfileBasicInfo = true
|
||||
modifyUseLastReconciledTime = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
modifyUseLastReconciledTime = false
|
||||
}
|
||||
|
||||
if userUpdateReq.TransactionEditScope != nil && *userUpdateReq.TransactionEditScope != user.TransactionEditScope {
|
||||
user.TransactionEditScope = *userUpdateReq.TransactionEditScope
|
||||
userNew.TransactionEditScope = *userUpdateReq.TransactionEditScope
|
||||
@@ -531,7 +542,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
return nil, errs.ErrNothingWillBeUpdated
|
||||
}
|
||||
|
||||
keyProfileUpdated, emailSetToUnverified, err := a.users.UpdateUser(c, userNew, modifyUserLanguage)
|
||||
keyProfileUpdated, emailSetToUnverified, err := a.users.UpdateUser(c, userNew, modifyUserLanguage, modifyUseLastReconciledTime)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[users.UserUpdateProfileHandler] failed to update user \"uid:%d\", because %s", user.Uid, err.Error())
|
||||
|
||||
@@ -178,7 +178,7 @@ func (h *mcpAddTransactionToolHandler) Handle(c *core.WebContext, callToolReq *M
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, time.FixedZone("Transaction Timezone", int(transaction.TimezoneUtcOffset)*60))
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, time.FixedZone("Transaction Timezone", int(transaction.TimezoneUtcOffset)*60), sourceAccount, destinationAccount)
|
||||
|
||||
if !transactionEditable {
|
||||
return nil, nil, errs.ErrCannotCreateTransactionWithThisTransactionTime
|
||||
|
||||
+19
-1
@@ -90,7 +90,8 @@ type Account struct {
|
||||
|
||||
// AccountExtend represents account extend data stored in database
|
||||
type AccountExtend struct {
|
||||
CreditCardStatementDate *int `json:"creditCardStatementDate"`
|
||||
LastReconciledTime *int64 `json:"lastReconciledTime"`
|
||||
CreditCardStatementDate *int `json:"creditCardStatementDate"`
|
||||
}
|
||||
|
||||
// AccountCreateRequest represents all parameters of account creation request
|
||||
@@ -119,6 +120,7 @@ type AccountModifyRequest struct {
|
||||
Currency *string `json:"currency" binding:"omitempty,len=3,validCurrency"`
|
||||
Balance *int64 `json:"balance" binding:"omitempty"`
|
||||
BalanceTime *int64 `json:"balanceTime" binding:"omitempty"`
|
||||
LastReconciledTime *int64 `json:"lastReconciledTime" binding:"omitempty"`
|
||||
Comment string `json:"comment" binding:"max=255"`
|
||||
CreditCardStatementDate int `json:"creditCardStatementDate" binding:"min=0,max=28"`
|
||||
Hidden bool `json:"hidden"`
|
||||
@@ -169,6 +171,7 @@ type AccountInfoResponse struct {
|
||||
Color string `json:"color"`
|
||||
Currency string `json:"currency"`
|
||||
Balance int64 `json:"balance"`
|
||||
LastReconciledTime *int64 `json:"lastReconciledTime,omitempty"`
|
||||
Comment string `json:"comment"`
|
||||
CreditCardStatementDate *int `json:"creditCardStatementDate,omitempty"`
|
||||
DisplayOrder int32 `json:"displayOrder"`
|
||||
@@ -178,10 +181,24 @@ type AccountInfoResponse struct {
|
||||
SubAccounts AccountInfoResponseSlice `json:"subAccounts,omitempty"`
|
||||
}
|
||||
|
||||
// GetLastReconciledTime returns the last reconciled time of the account
|
||||
func (a *Account) GetLastReconciledTime() int64 {
|
||||
if a.Extend != nil && a.Extend.LastReconciledTime != nil {
|
||||
return *a.Extend.LastReconciledTime
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// ToAccountInfoResponse returns a view-object according to database model
|
||||
func (a *Account) ToAccountInfoResponse() *AccountInfoResponse {
|
||||
var lastReconciledTime *int64
|
||||
var creditCardStatementDate *int
|
||||
|
||||
if a.Extend != nil {
|
||||
lastReconciledTime = a.Extend.LastReconciledTime
|
||||
}
|
||||
|
||||
if a.ParentAccountId == LevelOneAccountParentId && a.Category == ACCOUNT_CATEGORY_CREDIT_CARD {
|
||||
if a.Extend != nil {
|
||||
creditCardStatementDate = a.Extend.CreditCardStatementDate
|
||||
@@ -201,6 +218,7 @@ func (a *Account) ToAccountInfoResponse() *AccountInfoResponse {
|
||||
Currency: a.Currency,
|
||||
Balance: a.Balance,
|
||||
Comment: a.Comment,
|
||||
LastReconciledTime: lastReconciledTime,
|
||||
CreditCardStatementDate: creditCardStatementDate,
|
||||
DisplayOrder: a.DisplayOrder,
|
||||
IsAsset: assetAccountCategory[a.Category],
|
||||
|
||||
@@ -549,10 +549,6 @@ func ParseTransactionTagFilter(tagFilterStr string) ([]*TransactionTagFilter, er
|
||||
|
||||
// IsEditable returns whether this transaction can be edited
|
||||
func (t *Transaction) IsEditable(currentUser *User, clientTimezone *time.Location, account *Account, relatedAccount *Account) bool {
|
||||
if currentUser == nil || !currentUser.CanEditTransactionByTransactionTime(t.TransactionTime, clientTimezone) {
|
||||
return false
|
||||
}
|
||||
|
||||
if account == nil || account.Hidden {
|
||||
return false
|
||||
}
|
||||
@@ -563,6 +559,10 @@ func (t *Transaction) IsEditable(currentUser *User, clientTimezone *time.Locatio
|
||||
}
|
||||
}
|
||||
|
||||
if currentUser == nil || !currentUser.CanEditTransactionByTransactionTime(t.TransactionTime, clientTimezone, account, relatedAccount) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+38
-15
@@ -13,14 +13,15 @@ type TransactionEditScope byte
|
||||
|
||||
// Editable Transaction Ranges
|
||||
const (
|
||||
TRANSACTION_EDIT_SCOPE_NONE TransactionEditScope = 0
|
||||
TRANSACTION_EDIT_SCOPE_ALL TransactionEditScope = 1
|
||||
TRANSACTION_EDIT_SCOPE_TODAY_OR_LATER TransactionEditScope = 2
|
||||
TRANSACTION_EDIT_SCOPE_LAST_24H_OR_LATER TransactionEditScope = 3
|
||||
TRANSACTION_EDIT_SCOPE_THIS_WEEK_OR_LATER TransactionEditScope = 4
|
||||
TRANSACTION_EDIT_SCOPE_THIS_MONTH_OR_LATER TransactionEditScope = 5
|
||||
TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER TransactionEditScope = 6
|
||||
TRANSACTION_EDIT_SCOPE_INVALID TransactionEditScope = 255
|
||||
TRANSACTION_EDIT_SCOPE_NONE TransactionEditScope = 0
|
||||
TRANSACTION_EDIT_SCOPE_ALL TransactionEditScope = 1
|
||||
TRANSACTION_EDIT_SCOPE_TODAY_OR_LATER TransactionEditScope = 2
|
||||
TRANSACTION_EDIT_SCOPE_LAST_24H_OR_LATER TransactionEditScope = 3
|
||||
TRANSACTION_EDIT_SCOPE_THIS_WEEK_OR_LATER TransactionEditScope = 4
|
||||
TRANSACTION_EDIT_SCOPE_THIS_MONTH_OR_LATER TransactionEditScope = 5
|
||||
TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER TransactionEditScope = 6
|
||||
TRANSACTION_EDIT_SCOPE_LAST_RECONCILED_TIME_OR_LATER TransactionEditScope = 7
|
||||
TRANSACTION_EDIT_SCOPE_INVALID TransactionEditScope = 255
|
||||
)
|
||||
|
||||
// String returns a textual representation of the editable transaction ranges enum
|
||||
@@ -40,6 +41,8 @@ func (s TransactionEditScope) String() string {
|
||||
return "ThisMonthOrLater"
|
||||
case TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER:
|
||||
return "ThisYearOrLater"
|
||||
case TRANSACTION_EDIT_SCOPE_LAST_RECONCILED_TIME_OR_LATER:
|
||||
return "LastReconciledTimeOrLater"
|
||||
case TRANSACTION_EDIT_SCOPE_INVALID:
|
||||
return "Invalid"
|
||||
default:
|
||||
@@ -90,6 +93,7 @@ type User struct {
|
||||
Salt string `xorm:"VARCHAR(10) NOT NULL"`
|
||||
CustomAvatarType string `xorm:"VARCHAR(10)"`
|
||||
DefaultAccountId int64
|
||||
UseLastReconciledTime bool
|
||||
TransactionEditScope TransactionEditScope `xorm:"TINYINT NOT NULL"`
|
||||
Language string `xorm:"VARCHAR(10)"`
|
||||
DefaultCurrency string `xorm:"VARCHAR(3) NOT NULL"`
|
||||
@@ -128,6 +132,7 @@ type UserBasicInfo struct {
|
||||
AvatarUrl string `json:"avatar"`
|
||||
AvatarProvider string `json:"avatarProvider,omitempty"`
|
||||
DefaultAccountId int64 `json:"defaultAccountId,string"`
|
||||
UseLastReconciledTime bool `json:"useLastReconciledTime"`
|
||||
TransactionEditScope TransactionEditScope `json:"transactionEditScope"`
|
||||
Language string `json:"language"`
|
||||
DefaultCurrency string `json:"defaultCurrency"`
|
||||
@@ -194,7 +199,8 @@ type UserProfileUpdateRequest struct {
|
||||
Password string `json:"password" binding:"omitempty,min=6,max=128"`
|
||||
OldPassword string `json:"oldPassword" binding:"omitempty,min=6,max=128"`
|
||||
DefaultAccountId int64 `json:"defaultAccountId,string" binding:"omitempty,min=1"`
|
||||
TransactionEditScope *TransactionEditScope `json:"transactionEditScope" binding:"omitempty,min=0,max=6"`
|
||||
UseLastReconciledTime *bool `json:"useLastReconciledTime" binding:"omitempty"`
|
||||
TransactionEditScope *TransactionEditScope `json:"transactionEditScope" binding:"omitempty,min=0,max=7"`
|
||||
Language string `json:"language" binding:"omitempty,min=2,max=16"`
|
||||
DefaultCurrency string `json:"defaultCurrency" binding:"omitempty,len=3,validCurrency"`
|
||||
FirstDayOfWeek *core.WeekDay `json:"firstDayOfWeek" binding:"omitempty,min=0,max=6"`
|
||||
@@ -230,7 +236,7 @@ type UserProfileResponse struct {
|
||||
}
|
||||
|
||||
// CanEditTransactionByTransactionTime returns whether this user can edit transaction with specified transaction time
|
||||
func (u *User) CanEditTransactionByTransactionTime(transactionTime int64, clientTimezone *time.Location) bool {
|
||||
func (u *User) CanEditTransactionByTransactionTime(transactionTime int64, clientTimezone *time.Location, account *Account, destinationAccount *Account) bool {
|
||||
if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_NONE {
|
||||
return false
|
||||
} else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_ALL {
|
||||
@@ -242,14 +248,14 @@ func (u *User) CanEditTransactionByTransactionTime(transactionTime int64, client
|
||||
transactionUnixTime := utils.GetUnixTimeFromTransactionTime(transactionTime)
|
||||
|
||||
if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_LAST_24H_OR_LATER {
|
||||
return transactionUnixTime >= now.Add(-24*time.Hour).Unix()
|
||||
return transactionUnixTime > now.Add(-24*time.Hour).Unix()
|
||||
}
|
||||
|
||||
clientNow := now.In(clientTimezone)
|
||||
clientTodayStartTime := utils.GetStartOfDay(clientNow)
|
||||
|
||||
if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_TODAY_OR_LATER {
|
||||
return transactionUnixTime >= clientTodayStartTime.Unix()
|
||||
return transactionUnixTime > clientTodayStartTime.Unix()
|
||||
} else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_THIS_WEEK_OR_LATER {
|
||||
dayOfWeek := int(now.Weekday()) - int(u.FirstDayOfWeek)
|
||||
|
||||
@@ -258,13 +264,29 @@ func (u *User) CanEditTransactionByTransactionTime(transactionTime int64, client
|
||||
}
|
||||
|
||||
clientWeekStartTime := clientTodayStartTime.AddDate(0, 0, -dayOfWeek)
|
||||
return transactionUnixTime >= clientWeekStartTime.Unix()
|
||||
return transactionUnixTime > clientWeekStartTime.Unix()
|
||||
} else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_THIS_MONTH_OR_LATER {
|
||||
clientMonthStartTime := clientTodayStartTime.AddDate(0, 0, -(now.Day() - 1))
|
||||
return transactionUnixTime >= clientMonthStartTime.Unix()
|
||||
return transactionUnixTime > clientMonthStartTime.Unix()
|
||||
} else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER {
|
||||
clientYearStartTime := clientTodayStartTime.AddDate(0, 0, -(now.YearDay() - 1))
|
||||
return transactionUnixTime >= clientYearStartTime.Unix()
|
||||
return transactionUnixTime > clientYearStartTime.Unix()
|
||||
} else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_LAST_RECONCILED_TIME_OR_LATER && u.UseLastReconciledTime {
|
||||
minAccountLastReconciledTime := int64(0)
|
||||
|
||||
if account != nil {
|
||||
minAccountLastReconciledTime = account.GetLastReconciledTime()
|
||||
}
|
||||
|
||||
if destinationAccount != nil {
|
||||
destinationAccountLastReconciledTime := destinationAccount.GetLastReconciledTime()
|
||||
|
||||
if destinationAccountLastReconciledTime > minAccountLastReconciledTime {
|
||||
minAccountLastReconciledTime = destinationAccountLastReconciledTime
|
||||
}
|
||||
}
|
||||
|
||||
return transactionUnixTime > minAccountLastReconciledTime
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -285,6 +307,7 @@ func (u *User) ToUserBasicInfo(avatarProvider core.UserAvatarProviderType, avata
|
||||
AvatarUrl: avatarUrl,
|
||||
AvatarProvider: string(avatarProvider),
|
||||
DefaultAccountId: u.DefaultAccountId,
|
||||
UseLastReconciledTime: u.UseLastReconciledTime,
|
||||
TransactionEditScope: u.TransactionEditScope,
|
||||
Language: u.Language,
|
||||
DefaultCurrency: u.DefaultCurrency,
|
||||
|
||||
+85
-16
@@ -16,7 +16,7 @@ func TestUserCanEditTransactionByTransactionTime_ScopeIsNone(t *testing.T) {
|
||||
}
|
||||
|
||||
timezone := time.FixedZone("Timezone", int(utils.GetServerTimezoneOffsetMinutes())*60)
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(time.Now().Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(time.Now().Unix()), timezone, nil, nil))
|
||||
}
|
||||
|
||||
func TestUserCanEditTransactionByTransactionTime_ScopeIsAll(t *testing.T) {
|
||||
@@ -25,7 +25,7 @@ func TestUserCanEditTransactionByTransactionTime_ScopeIsAll(t *testing.T) {
|
||||
}
|
||||
|
||||
timezone := time.FixedZone("Timezone", int(utils.GetServerTimezoneOffsetMinutes())*60)
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(time.Now().Unix()), timezone))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(time.Now().Unix()), timezone, nil, nil))
|
||||
}
|
||||
|
||||
func TestUserCanEditTransactionByTransactionTime_ScopeIsTodayOrLater(t *testing.T) {
|
||||
@@ -39,9 +39,10 @@ func TestUserCanEditTransactionByTransactionTime_ScopeIsTodayOrLater(t *testing.
|
||||
yesterdayLastDatetime := todayFirstDatetime.Add(-1 * time.Second)
|
||||
todayLastDatetime := yesterdayLastDatetime.Add(24 * time.Hour)
|
||||
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(todayFirstDatetime.Unix()), timezone))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(todayLastDatetime.Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(yesterdayLastDatetime.Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(todayFirstDatetime.Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(todayFirstDatetime.Add(1*time.Second).Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(todayLastDatetime.Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(yesterdayLastDatetime.Unix()), timezone, nil, nil))
|
||||
}
|
||||
|
||||
func TestUserCanEditTransactionByTransactionTime_ScopeIsLast24HourOrLater(t *testing.T) {
|
||||
@@ -53,8 +54,9 @@ func TestUserCanEditTransactionByTransactionTime_ScopeIsLast24HourOrLater(t *tes
|
||||
timezone := time.FixedZone("Timezone", int(utils.GetServerTimezoneOffsetMinutes())*60)
|
||||
twentyfourHourBeforeDatetime := now.Add(-24 * time.Hour).Add(-1 * time.Second)
|
||||
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(twentyfourHourBeforeDatetime.Unix()), timezone))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(twentyfourHourBeforeDatetime.Add(1*time.Second).Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(twentyfourHourBeforeDatetime.Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(twentyfourHourBeforeDatetime.Add(1*time.Second).Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(twentyfourHourBeforeDatetime.Add(2*time.Second).Unix()), timezone, nil, nil))
|
||||
}
|
||||
|
||||
func TestUserCanEditTransactionByTransactionTime_ScopeIsThisWeekOrLater(t *testing.T) {
|
||||
@@ -76,9 +78,10 @@ func TestUserCanEditTransactionByTransactionTime_ScopeIsThisWeekOrLater(t *testi
|
||||
lastWeekLastDatetime := thisWeekFirstDatetime.Add(-1 * time.Second)
|
||||
thisWeekLastDatetime := lastWeekLastDatetime.Add(24 * time.Hour)
|
||||
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisWeekFirstDatetime.Unix()), timezone))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisWeekLastDatetime.Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(lastWeekLastDatetime.Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisWeekFirstDatetime.Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisWeekFirstDatetime.Add(1*time.Second).Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisWeekLastDatetime.Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(lastWeekLastDatetime.Unix()), timezone, nil, nil))
|
||||
}
|
||||
|
||||
func TestUserCanEditTransactionByTransactionTime_ScopeIsThisMonthOrLater(t *testing.T) {
|
||||
@@ -92,9 +95,10 @@ func TestUserCanEditTransactionByTransactionTime_ScopeIsThisMonthOrLater(t *test
|
||||
lastMonthLastDatetime := thisMonthFirstDatetime.Add(-1 * time.Second)
|
||||
thisMonthLastDatetime := lastMonthLastDatetime.Add(24 * time.Hour)
|
||||
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisMonthFirstDatetime.Unix()), timezone))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisMonthLastDatetime.Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(lastMonthLastDatetime.Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisMonthFirstDatetime.Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisMonthFirstDatetime.Add(1*time.Second).Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisMonthLastDatetime.Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(lastMonthLastDatetime.Unix()), timezone, nil, nil))
|
||||
}
|
||||
|
||||
func TestUserCanEditTransactionByTransactionTime_ScopeIsThisYearOrLater(t *testing.T) {
|
||||
@@ -108,7 +112,72 @@ func TestUserCanEditTransactionByTransactionTime_ScopeIsThisYearOrLater(t *testi
|
||||
lastYearLastDatetime := thisYearFirstDatetime.Add(-1 * time.Second)
|
||||
thisYearLastDatetime := lastYearLastDatetime.Add(24 * time.Hour)
|
||||
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisYearFirstDatetime.Unix()), timezone))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisYearLastDatetime.Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(lastYearLastDatetime.Unix()), timezone))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisYearFirstDatetime.Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisYearFirstDatetime.Add(1*time.Second).Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(thisYearLastDatetime.Unix()), timezone, nil, nil))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(lastYearLastDatetime.Unix()), timezone, nil, nil))
|
||||
}
|
||||
|
||||
func TestUserCanEditTransactionByTransactionTime_ScopeIsLastReconciledTimeOrLater(t *testing.T) {
|
||||
user := &User{
|
||||
TransactionEditScope: TRANSACTION_EDIT_SCOPE_LAST_RECONCILED_TIME_OR_LATER,
|
||||
UseLastReconciledTime: true,
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
timezone := time.FixedZone("Timezone", int(utils.GetServerTimezoneOffsetMinutes())*60)
|
||||
sourceAccountLastReconciledTime := now.Add(-24 * time.Hour)
|
||||
sourceAccountLastRecondiledUnixTime := sourceAccountLastReconciledTime.Unix()
|
||||
sourceAccount := &Account{
|
||||
Extend: &AccountExtend{
|
||||
LastReconciledTime: &sourceAccountLastRecondiledUnixTime,
|
||||
},
|
||||
}
|
||||
destinationAccountLastReconciledTime := now.Add(-20 * time.Hour)
|
||||
destinationAccountLastReconciledUnixTime := destinationAccountLastReconciledTime.Unix()
|
||||
destinationAccount := &Account{
|
||||
Extend: &AccountExtend{
|
||||
LastReconciledTime: &destinationAccountLastReconciledUnixTime,
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(sourceAccountLastReconciledTime.Add(-1*time.Second).Unix()), timezone, sourceAccount, nil))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(sourceAccountLastReconciledTime.Unix()), timezone, sourceAccount, nil))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(sourceAccountLastReconciledTime.Add(1*time.Second).Unix()), timezone, sourceAccount, nil))
|
||||
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(destinationAccountLastReconciledTime.Add(-1*time.Second).Unix()), timezone, sourceAccount, destinationAccount))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(destinationAccountLastReconciledTime.Unix()), timezone, sourceAccount, destinationAccount))
|
||||
assert.Equal(t, true, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(destinationAccountLastReconciledTime.Add(1*time.Second).Unix()), timezone, sourceAccount, destinationAccount))
|
||||
}
|
||||
|
||||
func TestUserCanEditTransactionByTransactionTime_ScopeIsLastReconciledTimeOrLaterButUserDoesNotUseLastReconciledTime(t *testing.T) {
|
||||
user := &User{
|
||||
TransactionEditScope: TRANSACTION_EDIT_SCOPE_LAST_RECONCILED_TIME_OR_LATER,
|
||||
UseLastReconciledTime: false,
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
timezone := time.FixedZone("Timezone", int(utils.GetServerTimezoneOffsetMinutes())*60)
|
||||
sourceAccountLastReconciledTime := now.Add(-24 * time.Hour)
|
||||
sourceAccountLastRecondiledUnixTime := sourceAccountLastReconciledTime.Unix()
|
||||
sourceAccount := &Account{
|
||||
Extend: &AccountExtend{
|
||||
LastReconciledTime: &sourceAccountLastRecondiledUnixTime,
|
||||
},
|
||||
}
|
||||
destinationAccountLastReconciledTime := now.Add(-20 * time.Hour)
|
||||
destinationAccountLastReconciledUnixTime := destinationAccountLastReconciledTime.Unix()
|
||||
destinationAccount := &Account{
|
||||
Extend: &AccountExtend{
|
||||
LastReconciledTime: &destinationAccountLastReconciledUnixTime,
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(sourceAccountLastReconciledTime.Add(-1*time.Second).Unix()), timezone, sourceAccount, nil))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(sourceAccountLastReconciledTime.Unix()), timezone, sourceAccount, nil))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(sourceAccountLastReconciledTime.Add(1*time.Second).Unix()), timezone, sourceAccount, nil))
|
||||
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(destinationAccountLastReconciledTime.Add(-1*time.Second).Unix()), timezone, sourceAccount, destinationAccount))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(destinationAccountLastReconciledTime.Unix()), timezone, sourceAccount, destinationAccount))
|
||||
assert.Equal(t, false, user.CanEditTransactionByTransactionTime(utils.GetMinTransactionTimeFromUnixTime(destinationAccountLastReconciledTime.Add(1*time.Second).Unix()), timezone, sourceAccount, destinationAccount))
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ func (s *UserService) CreateUser(c core.Context, user *models.User, noPassword b
|
||||
}
|
||||
|
||||
// UpdateUser saves an existed user model to database
|
||||
func (s *UserService) UpdateUser(c core.Context, user *models.User, modifyUserLanguage bool) (keyProfileUpdated bool, emailSetToUnverified bool, err error) {
|
||||
func (s *UserService) UpdateUser(c core.Context, user *models.User, modifyUserLanguage bool, modifyUseLastReconciledTime bool) (keyProfileUpdated bool, emailSetToUnverified bool, err error) {
|
||||
if user.Uid <= 0 {
|
||||
return false, false, errs.ErrUserIdInvalid
|
||||
}
|
||||
@@ -277,7 +277,11 @@ func (s *UserService) UpdateUser(c core.Context, user *models.User, modifyUserLa
|
||||
updateCols = append(updateCols, "default_account_id")
|
||||
}
|
||||
|
||||
if models.TRANSACTION_EDIT_SCOPE_NONE <= user.TransactionEditScope && user.TransactionEditScope <= models.TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER {
|
||||
if modifyUseLastReconciledTime {
|
||||
updateCols = append(updateCols, "use_last_reconciled_time")
|
||||
}
|
||||
|
||||
if models.TRANSACTION_EDIT_SCOPE_NONE <= user.TransactionEditScope && user.TransactionEditScope <= models.TRANSACTION_EDIT_SCOPE_LAST_RECONCILED_TIME_OR_LATER {
|
||||
updateCols = append(updateCols, "transaction_edit_scope")
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
persistent-placeholder
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
:clearable="!emptyValue ? clearable : false"
|
||||
:label="label"
|
||||
:menu-props="{ contentClass: 'date-time-select-menu' }"
|
||||
v-model="dateTime"
|
||||
@@ -107,13 +108,16 @@ import { setChildInputFocus } from '@/lib/ui/desktop.ts';
|
||||
const props = defineProps<{
|
||||
modelValue: number;
|
||||
timezoneUtcOffset: number;
|
||||
emptyValue?: boolean;
|
||||
disabled?: boolean;
|
||||
readonly?: boolean;
|
||||
clearable?: boolean;
|
||||
label?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: number): void;
|
||||
(e: 'clear:modelValue'): void;
|
||||
(e: 'error', message: string): void;
|
||||
}>();
|
||||
|
||||
@@ -154,7 +158,12 @@ const dateTime = computed<Date>({
|
||||
get: () => {
|
||||
return getLocalDatetimeFromSameDateTimeOfUnixTime(props.modelValue, props.timezoneUtcOffset);
|
||||
},
|
||||
set: (value: Date) => {
|
||||
set: (value: Date | null) => {
|
||||
if (!value) {
|
||||
emit('clear:modelValue');
|
||||
return;
|
||||
}
|
||||
|
||||
const unixTime = getUnixTimeFromSameDateTimeOfLocalDatetime(value, props.timezoneUtcOffset);
|
||||
|
||||
if (unixTime < 0) {
|
||||
@@ -166,7 +175,7 @@ const dateTime = computed<Date>({
|
||||
}
|
||||
});
|
||||
|
||||
const displayTime = computed<string>(() => formatDateTimeToLongDateTime(parseDateTimeFromUnixTimeWithTimezoneOffset(props.modelValue, props.timezoneUtcOffset)));
|
||||
const displayTime = computed<string>(() => props.emptyValue ? tt('None') : formatDateTimeToLongDateTime(parseDateTimeFromUnixTimeWithTimezoneOffset(props.modelValue, props.timezoneUtcOffset)));
|
||||
|
||||
const hourItems = computed<TimePickerValue[]>(() => generateAllHours(1, isHourTwoDigits.value));
|
||||
const minuteItems = computed<TimePickerValue[]>(() => generateAllMinutesOrSeconds(1, isMinuteTwoDigits.value));
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
<f7-toolbar class="toolbar-with-swipe-handler">
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="left">
|
||||
<f7-link :text="tt('Now')" @click="setCurrentTime"></f7-link>
|
||||
<f7-link :text="tt('Clear')" @click="clear" v-if="clearable"></f7-link>
|
||||
<f7-link :text="tt('Now')" @click="setCurrentTime" v-if="!clearable"></f7-link>
|
||||
</div>
|
||||
<div class="right">
|
||||
<f7-link :icon-f7="mode === 'time' ? 'calendar' : 'clock'" @click="switchMode"></f7-link>
|
||||
@@ -122,11 +123,13 @@ const props = defineProps<{
|
||||
modelValue: number;
|
||||
timezoneUtcOffset: number;
|
||||
initMode?: string;
|
||||
clearable?: boolean;
|
||||
show: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: number): void;
|
||||
(e: 'clear:modelValue'): void;
|
||||
(e: 'update:show', value: boolean): void;
|
||||
}>();
|
||||
|
||||
@@ -221,6 +224,11 @@ function setCurrentTime(): void {
|
||||
}
|
||||
}
|
||||
|
||||
function clear(): void {
|
||||
emit('clear:modelValue');
|
||||
emit('update:show', false);
|
||||
}
|
||||
|
||||
function confirm(): void {
|
||||
if (!dateTime.value) {
|
||||
return;
|
||||
|
||||
+29
-10
@@ -14,27 +14,46 @@ export enum TransactionRelatedAccountType {
|
||||
|
||||
export class TransactionEditScopeType implements TypeAndName {
|
||||
private static readonly allInstances: TransactionEditScopeType[] = [];
|
||||
private static readonly allInstancesWithoutReconciledTime: TransactionEditScopeType[] = [];
|
||||
private static readonly allInstancesByType: Record<number, TransactionEditScopeType> = {};
|
||||
|
||||
public static readonly None = new TransactionEditScopeType(0, 'None');
|
||||
public static readonly All = new TransactionEditScopeType(1, 'All');
|
||||
public static readonly TodayOrLater = new TransactionEditScopeType(2, 'Today or later');
|
||||
public static readonly Recent24HoursOrLater = new TransactionEditScopeType(3, 'Recent 24 hours or later');
|
||||
public static readonly ThisWeekOrLater = new TransactionEditScopeType(4, 'This week or later');
|
||||
public static readonly ThisMonthOrLater = new TransactionEditScopeType(5, 'This month or later');
|
||||
public static readonly ThisYearOrLater = new TransactionEditScopeType(6, 'This year or later');
|
||||
public static readonly None = new TransactionEditScopeType(0, 'None', false);
|
||||
public static readonly All = new TransactionEditScopeType(1, 'All', false);
|
||||
public static readonly TodayOrLater = new TransactionEditScopeType(2, 'Today or later', false);
|
||||
public static readonly Recent24HoursOrLater = new TransactionEditScopeType(3, 'Recent 24 hours or later', false);
|
||||
public static readonly ThisWeekOrLater = new TransactionEditScopeType(4, 'This week or later', false);
|
||||
public static readonly ThisMonthOrLater = new TransactionEditScopeType(5, 'This month or later', false);
|
||||
public static readonly ThisYearOrLater = new TransactionEditScopeType(6, 'This year or later', false);
|
||||
public static readonly LastReconciledTimeOrlater = new TransactionEditScopeType(7, 'Last reconciled time or later', true);
|
||||
|
||||
public readonly type: number;
|
||||
public readonly name: string;
|
||||
public readonly needLastReconciledTime: boolean;
|
||||
|
||||
private constructor(type: number, name: string) {
|
||||
private constructor(type: number, name: string, needLastReconciledTime: boolean) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.needLastReconciledTime = needLastReconciledTime;
|
||||
|
||||
TransactionEditScopeType.allInstances.push(this);
|
||||
|
||||
if (!needLastReconciledTime) {
|
||||
TransactionEditScopeType.allInstancesWithoutReconciledTime.push(this);
|
||||
}
|
||||
|
||||
TransactionEditScopeType.allInstancesByType[type] = this;
|
||||
}
|
||||
|
||||
public static values(): TransactionEditScopeType[] {
|
||||
return TransactionEditScopeType.allInstances;
|
||||
public static values(useLastReconciledTime: boolean): TransactionEditScopeType[] {
|
||||
if (useLastReconciledTime) {
|
||||
return TransactionEditScopeType.allInstances;
|
||||
} else {
|
||||
return TransactionEditScopeType.allInstancesWithoutReconciledTime;
|
||||
}
|
||||
}
|
||||
|
||||
public static valueOf(type: number): TransactionEditScopeType | undefined {
|
||||
return TransactionEditScopeType.allInstancesByType[type];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Dezimaltrennzeichen",
|
||||
"Digit Grouping Symbol": "Zifferngruppierungssymbol",
|
||||
"Digit Grouping": "Zifferngruppierung",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Bearbeitbarer Transaktionsbereich",
|
||||
"Today or later": "Heute oder später",
|
||||
"Recent 24 hours or later": "Letzte 24 Stunden oder später",
|
||||
"This week or later": "Diese Woche oder später",
|
||||
"This month or later": "Dieser Monat oder später",
|
||||
"This year or later": "Dieses Jahr oder später",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Anmelden",
|
||||
"Log in with OAuth 2.0": "Mit OAuth 2.0 anmelden",
|
||||
"Log in with Connect ID": "Mit Connect ID anmelden",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Ausstehender Teilkontostand",
|
||||
"Balance Time": "Saldozeit",
|
||||
"Sub-account Balance Time": "Teilkontosaldozeit",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Abrechnungsdatum",
|
||||
"Description": "Beschreibung",
|
||||
"Your account description (optional)": "Ihre Kontobeschreibung (optional)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Decimal Separator",
|
||||
"Digit Grouping Symbol": "Digit Grouping Symbol",
|
||||
"Digit Grouping": "Digit Grouping",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Editable Transaction Range",
|
||||
"Today or later": "Today or later",
|
||||
"Recent 24 hours or later": "Recent 24 hours or later",
|
||||
"This week or later": "This week or later",
|
||||
"This month or later": "This month or later",
|
||||
"This year or later": "This year or later",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Log In",
|
||||
"Log in with OAuth 2.0": "Log in with OAuth 2.0",
|
||||
"Log in with Connect ID": "Log in with Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Sub-account Outstanding Balance",
|
||||
"Balance Time": "Balance Time",
|
||||
"Sub-account Balance Time": "Sub-account Balance Time",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Statement Date",
|
||||
"Description": "Description",
|
||||
"Your account description (optional)": "Your account description (optional)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Separador Decimal",
|
||||
"Digit Grouping Symbol": "Símbolo de Agrupación de Dígitos",
|
||||
"Digit Grouping": "Agrupación de Dígitos",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Rango de Transacciones Editables",
|
||||
"Today or later": "Hoy o más tarde",
|
||||
"Recent 24 hours or later": "Últimas 24 horas o más",
|
||||
"This week or later": "Esta semana o más tarde",
|
||||
"This month or later": "Este mes o más tarde",
|
||||
"This year or later": "Este año o más tarde",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Acceso",
|
||||
"Log in with OAuth 2.0": "Iniciar sesión con OAuth 2.0",
|
||||
"Log in with Connect ID": "Inicie sesión con Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Saldo pendiente de la Subcuenta",
|
||||
"Balance Time": "Fecha del Saldo",
|
||||
"Sub-account Balance Time": "Fecha del Saldo de la Subcuenta",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Fecha del Extracto",
|
||||
"Description": "Descripción",
|
||||
"Your account description (optional)": "Descripción de tu cuenta (opcional)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Séparateur décimal",
|
||||
"Digit Grouping Symbol": "Symbole de regroupement des chiffres",
|
||||
"Digit Grouping": "Regroupement des chiffres",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Plage de transactions modifiables",
|
||||
"Today or later": "Aujourd'hui ou plus tard",
|
||||
"Recent 24 hours or later": "24 dernières heures ou plus tard",
|
||||
"This week or later": "Cette semaine ou plus tard",
|
||||
"This month or later": "Ce mois ou plus tard",
|
||||
"This year or later": "Cette année ou plus tard",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Se connecter",
|
||||
"Log in with OAuth 2.0": "Log in with OAuth 2.0",
|
||||
"Log in with Connect ID": "Log in with Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Solde impayé du sous-compte",
|
||||
"Balance Time": "Heure du solde",
|
||||
"Sub-account Balance Time": "Heure du solde du sous-compte",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Date de relevé",
|
||||
"Description": "Description",
|
||||
"Your account description (optional)": "Description de votre compte (optionnel)",
|
||||
|
||||
@@ -2564,7 +2564,7 @@ export function useI18n() {
|
||||
getAllStatisticsSortingTypes: (useAlternativeName?: boolean) => getLocalizedDisplayNameAndType(ChartSortingType.values(), useAlternativeName),
|
||||
getAllStatisticsDateAggregationTypes: (analysisType: StatisticsAnalysisType, includeBillingCycle: boolean) => getLocalizedChartDateAggregationTypeAndDisplayName(analysisType, true, includeBillingCycle),
|
||||
getAllStatisticsDateAggregationTypesWithShortName: (analysisType: StatisticsAnalysisType, includeBillingCycle: boolean) => getLocalizedChartDateAggregationTypeAndDisplayName(analysisType, false, includeBillingCycle),
|
||||
getAllTransactionEditScopeTypes: () => getLocalizedDisplayNameAndType(TransactionEditScopeType.values()),
|
||||
getAllTransactionEditScopeTypes: (useLastReconciledTime: boolean) => getLocalizedDisplayNameAndType(TransactionEditScopeType.values(useLastReconciledTime)),
|
||||
getAllTransactionQuickSaveButtonStyles: () => getLocalizedDisplayNameAndType(TransactionQuickSaveButtonStyle.values()),
|
||||
getAllTransactionQuickAddButtonActionTypes: () => getLocalizedDisplayNameAndType(TransactionQuickAddButtonActionType.values()),
|
||||
getAllTransactionScheduledFrequencyTypes: () => getLocalizedDisplayNameAndType(ScheduledTemplateFrequencyType.values()),
|
||||
@@ -2579,6 +2579,7 @@ export function useI18n() {
|
||||
getAllTransactionExplorerChartTypes: (operators?: TransactionExplorerChartType[]) => getLocalizedNameValue(operators ?? TransactionExplorerChartType.values()),
|
||||
// get localized info
|
||||
getLanguageInfo,
|
||||
getEnableDisableOption: (value: boolean) => t(value ? 'Enabled' : 'Disabled'),
|
||||
getMonthShortName,
|
||||
getMonthLongName,
|
||||
getMonthdayOrdinal,
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Separatore decimale",
|
||||
"Digit Grouping Symbol": "Simbolo di raggruppamento cifre",
|
||||
"Digit Grouping": "Raggruppamento cifre",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Intervallo di modifica transazioni",
|
||||
"Today or later": "Oggi o successivo",
|
||||
"Recent 24 hours or later": "Ultime 24 ore o successivo",
|
||||
"This week or later": "Questa settimana o successiva",
|
||||
"This month or later": "Questo mese o successivo",
|
||||
"This year or later": "Quest'anno o successivo",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Accedi",
|
||||
"Log in with OAuth 2.0": "Log in with OAuth 2.0",
|
||||
"Log in with Connect ID": "Log in with Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Saldo residuo sotto-account",
|
||||
"Balance Time": "Ora saldo",
|
||||
"Sub-account Balance Time": "Ora saldo sotto-account",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Data estratto conto",
|
||||
"Description": "Descrizione",
|
||||
"Your account description (optional)": "La descrizione del tuo account (opzionale)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "小数点",
|
||||
"Digit Grouping Symbol": "桁区切り記号",
|
||||
"Digit Grouping": "桁区切り位置",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "編集可能な取引範囲",
|
||||
"Today or later": "今日以降",
|
||||
"Recent 24 hours or later": "直近24時間以降",
|
||||
"This week or later": "今週以降",
|
||||
"This month or later": "今月以降",
|
||||
"This year or later": "今年以降",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "ログイン",
|
||||
"Log in with OAuth 2.0": "Log in with OAuth 2.0",
|
||||
"Log in with Connect ID": "Log in with Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "サブ口座の未払い残高",
|
||||
"Balance Time": "残高時間",
|
||||
"Sub-account Balance Time": "サブ口座残高時間",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "明細日",
|
||||
"Description": "説明",
|
||||
"Your account description (optional)": "口座の説明(オプション)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "ದಶಾಂಶ ವಿಭಜಕ",
|
||||
"Digit Grouping Symbol": "ಅಂಕ ವಿಂಗಡಣ ಚಿಹ್ನೆ",
|
||||
"Digit Grouping": "ಅಂಕ ವಿಂಗಡಣೆ",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "ತಿದ್ದುಪಡಿ ಮಾಡಬಹುದಾದ ವಹಿವಾಟಿನ ವ್ಯಾಪ್ತಿ",
|
||||
"Today or later": "ಇಂದು ಅಥವಾ ನಂತರ",
|
||||
"Recent 24 hours or later": "ಕಳೆದ 24 ಗಂಟೆಗಳು ಅಥವಾ ನಂತರ",
|
||||
"This week or later": "ಈ ವಾರ ಅಥವಾ ನಂತರ",
|
||||
"This month or later": "ಈ ತಿಂಗಳು ಅಥವಾ ನಂತರ",
|
||||
"This year or later": "ಈ ವರ್ಷ ಅಥವಾ ನಂತರ",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "ಲಾಗ್ ಇನ್",
|
||||
"Log in with OAuth 2.0": "OAuth 2.0 ಮೂಲಕ ಲಾಗ್ ಇನ್ ಆಗಿ",
|
||||
"Log in with Connect ID": "Connect ID ಮೂಲಕ ಲಾಗ್ ಇನ್ ಆಗಿ",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "ಉಪ-ಖಾತೆ ಬಾಕಿ ಶೇಷ",
|
||||
"Balance Time": "ಶೇಷ ಸಮಯ",
|
||||
"Sub-account Balance Time": "ಉಪ-ಖಾತೆ ಶೇಷ ಸಮಯ",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "ಸ್ಟೇಟ್ಮೆಂಟ್ ದಿನಾಂಕ",
|
||||
"Description": "ವಿವರಣೆ",
|
||||
"Your account description (optional)": "ನಿಮ್ಮ ಖಾತೆ ವಿವರಣೆ (ಐಚ್ಛಿಕ)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "소수점 구분자",
|
||||
"Digit Grouping Symbol": "자리 구분 기호",
|
||||
"Digit Grouping": "자리 구분",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "편집 가능한 거래 범위",
|
||||
"Today or later": "오늘 이후",
|
||||
"Recent 24 hours or later": "최근 24시간 이후",
|
||||
"This week or later": "이번 주 이후",
|
||||
"This month or later": "이번 달 이후",
|
||||
"This year or later": "올해 이후",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "로그인",
|
||||
"Log in with OAuth 2.0": "OAuth 2.0으로 로그인",
|
||||
"Log in with Connect ID": "Connect ID로 로그인",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "하위계좌 미결제 잔액",
|
||||
"Balance Time": "잔액 시간",
|
||||
"Sub-account Balance Time": "하위계좌 잔액 시간",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "명세서 날짜",
|
||||
"Description": "설명",
|
||||
"Your account description (optional)": "계좌 설명 (선택 사항)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Decimaalteken",
|
||||
"Digit Grouping Symbol": "Scheidingsteken voor duizendtallen",
|
||||
"Digit Grouping": "Groeperen van cijfers",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Bewerkbare transactiebereik",
|
||||
"Today or later": "Vandaag of later",
|
||||
"Recent 24 hours or later": "Afgelopen 24 uur of later",
|
||||
"This week or later": "Deze week of later",
|
||||
"This month or later": "Deze maand of later",
|
||||
"This year or later": "Dit jaar of later",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Inloggen",
|
||||
"Log in with OAuth 2.0": "Log in with OAuth 2.0",
|
||||
"Log in with Connect ID": "Log in with Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Openstaand saldo subrekening",
|
||||
"Balance Time": "Saldo-tijdstip",
|
||||
"Sub-account Balance Time": "Saldo-tijdstip subrekening",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Afsluitdatum",
|
||||
"Description": "Beschrijving",
|
||||
"Your account description (optional)": "Je rekeningbeschrijving (optioneel)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Separador Decimal",
|
||||
"Digit Grouping Symbol": "Símbolo de Agrupamento de Dígitos",
|
||||
"Digit Grouping": "Agrupamento de Dígitos",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Período Editável de Transações",
|
||||
"Today or later": "A partir de hoje",
|
||||
"Recent 24 hours or later": "A partir das últimas 24 horas",
|
||||
"This week or later": "A partir desta semana",
|
||||
"This month or later": "A partir deste mês",
|
||||
"This year or later": "A partir deste ano",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Fazer Login",
|
||||
"Log in with OAuth 2.0": "Entrar com OAuth 2.0",
|
||||
"Log in with Connect ID": "Entrar com Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Saldo em Aberto da Subconta",
|
||||
"Balance Time": "Hora do Saldo",
|
||||
"Sub-account Balance Time": "Hora do Saldo da Subconta",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Data do Extrato",
|
||||
"Description": "Descrição",
|
||||
"Your account description (optional)": "Descrição da sua conta (opcional)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Разделитель десятичных",
|
||||
"Digit Grouping Symbol": "Символ группировки цифр",
|
||||
"Digit Grouping": "Группировка цифр",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Диапазон редактируемых транзакций",
|
||||
"Today or later": "Сегодня или позже",
|
||||
"Recent 24 hours or later": "Последние 24 часа или позже",
|
||||
"This week or later": "На этой неделе или позже",
|
||||
"This month or later": "В этом месяце или позже",
|
||||
"This year or later": "В этом году или позже",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Войти",
|
||||
"Log in with OAuth 2.0": "Войти с OAuth 2.0",
|
||||
"Log in with Connect ID": "Войти с Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Невыплаченные остаток субсчета",
|
||||
"Balance Time": "Время баланса",
|
||||
"Sub-account Balance Time": "Время баланса субсчета",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Дата выписки",
|
||||
"Description": "Описание",
|
||||
"Your account description (optional)": "Описание вашего счета (необязательно)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Decimalno ločilo",
|
||||
"Digit Grouping Symbol": "Ločilo tisočic",
|
||||
"Digit Grouping": "Združevanje števil",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Obseg urejanja transakcij",
|
||||
"Today or later": "Danes ali pozneje",
|
||||
"Recent 24 hours or later": "Zadnjih 24 ur ali pozneje",
|
||||
"This week or later": "Ta teden ali pozneje",
|
||||
"This month or later": "Ta mesec ali pozneje",
|
||||
"This year or later": "Letos ali pozneje",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Prijava",
|
||||
"Log in with OAuth 2.0": "Prijava z OAuth 2.0",
|
||||
"Log in with Connect ID": "Prijava s Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Neporavnano stanje na podračunu",
|
||||
"Balance Time": "Čas stanja",
|
||||
"Sub-account Balance Time": "Čas stanja na podračunu",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Datum izpiska",
|
||||
"Description": "Opis",
|
||||
"Your account description (optional)": "Opis vašega računa (neobvezno)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "தசம பிரிப்பான்",
|
||||
"Digit Grouping Symbol": "இலக்க குழு குறியீடு",
|
||||
"Digit Grouping": "இலக்க குழுவாக்கம்",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "திருத்துபடி செய்யக்கூடிய பரிவர்த்தனையின் வரம்பு",
|
||||
"Today or later": "இன்று அல்லது பின்பு",
|
||||
"Recent 24 hours or later": "கடந்த 24 மணி நேரம் அல்லது பின்பு",
|
||||
"This week or later": "இந்த வாரம் அல்லது பின்பு",
|
||||
"This month or later": "இந்த மாதம் அல்லது பின்பு",
|
||||
"This year or later": "இந்த வருடம் அல்லது பின்பு",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "உள்நுழை",
|
||||
"Log in with OAuth 2.0": "OAuth 2.0 மூலக உள்நுழை ஆக",
|
||||
"Log in with Connect ID": "Connect ID மூலக உள்நுழை ஆக",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "துணை-கணக்கு நிலுவை இருப்பு",
|
||||
"Balance Time": "இருப்பு நேரம்",
|
||||
"Sub-account Balance Time": "துணை-கணக்கு இருப்பு நேரம்",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "அறிக்கை தேதி",
|
||||
"Description": "விளக்கம்",
|
||||
"Your account description (optional)": "உங்கள் கணக்கு விளக்கம் (விருப்பமான)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "ตัวคั่นทศนิยม",
|
||||
"Digit Grouping Symbol": "สัญลักษณ์จัดกลุ่มตัวเลข",
|
||||
"Digit Grouping": "จัดกลุ่มตัวเลข",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "ช่วงรายการที่แก้ไขได้",
|
||||
"Today or later": "วันนี้หรือหลังจากนี้",
|
||||
"Recent 24 hours or later": "24 ชั่วโมงที่ผ่านมา หรือหลังจากนี้",
|
||||
"This week or later": "สัปดาห์นี้หรือหลังจากนี้",
|
||||
"This month or later": "เดือนนี้หรือหลังจากนี้",
|
||||
"This year or later": "ปีนี้หรือหลังจากนี้",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "เข้าสู่ระบบ",
|
||||
"Log in with OAuth 2.0": "Log in with OAuth 2.0",
|
||||
"Log in with Connect ID": "Log in with Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "ยอดค้างชำระบัญชีย่อย",
|
||||
"Balance Time": "เวลายอดคงเหลือ",
|
||||
"Sub-account Balance Time": "เวลายอดคงเหลือบัญชีย่อย",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "วันรายการ",
|
||||
"Description": "รายละเอียด",
|
||||
"Your account description (optional)": "รายละเอียดบัญชีของคุณ (ไม่บังคับ)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Ondalık Ayırıcı",
|
||||
"Digit Grouping Symbol": "Basamak Gruplama Sembolü",
|
||||
"Digit Grouping": "Basamak Gruplama",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Düzenlenebilir İşlem Aralığı",
|
||||
"Today or later": "Bugün veya sonrası",
|
||||
"Recent 24 hours or later": "Son 24 saat veya sonrası",
|
||||
"This week or later": "Bu hafta veya sonrası",
|
||||
"This month or later": "Bu ay veya sonrası",
|
||||
"This year or later": "Bu yıl veya sonrası",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Giriş Yap",
|
||||
"Log in with OAuth 2.0": "OAuth 2.0 ile giriş yap",
|
||||
"Log in with Connect ID": "Connect ID ile giriş yap",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Alt Hesap Kalan Borç Bakiyesi",
|
||||
"Balance Time": "Bakiye Zamanı",
|
||||
"Sub-account Balance Time": "Alt Hesap Bakiye Zamanı",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Ekstre Tarihi",
|
||||
"Description": "Açıklama",
|
||||
"Your account description (optional)": "Hesap açıklamanız (isteğe bağlı)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Десятковий роздільник",
|
||||
"Digit Grouping Symbol": "Символ групування цифр",
|
||||
"Digit Grouping": "Групування цифр",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Діапазон редагованих транзакцій",
|
||||
"Today or later": "Сьогодні або пізніше",
|
||||
"Recent 24 hours or later": "Останні 24 години або пізніше",
|
||||
"This week or later": "Цього тижня або пізніше",
|
||||
"This month or later": "Цього місяця або пізніше",
|
||||
"This year or later": "Цього року або пізніше",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Увійти",
|
||||
"Log in with OAuth 2.0": "Log in with OAuth 2.0",
|
||||
"Log in with Connect ID": "Log in with Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Несплачений баланс субрахунку",
|
||||
"Balance Time": "Час балансу",
|
||||
"Sub-account Balance Time": "Час балансу субрахунку",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Дата виписки",
|
||||
"Description": "Опис",
|
||||
"Your account description (optional)": "Опис вашого рахунку (необов'язково)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "Dấu phân cách thập phân",
|
||||
"Digit Grouping Symbol": "Ký hiệu nhóm chữ số",
|
||||
"Digit Grouping": "Nhóm chữ số",
|
||||
"Use Last Reconciled Time": "Use Last Reconciled Time",
|
||||
"Editable Transaction Range": "Phạm vi giao dịch có thể chỉnh sửa",
|
||||
"Today or later": "Hôm nay trở đi",
|
||||
"Recent 24 hours or later": "24 giờ gần đây trở đi",
|
||||
"This week or later": "Tuần này trở đi",
|
||||
"This month or later": "Tháng này trở đi",
|
||||
"This year or later": "Năm nay trở đi",
|
||||
"Last reconciled time or later": "Last reconciled time or later",
|
||||
"Log In": "Đăng nhập",
|
||||
"Log in with OAuth 2.0": "Log in with OAuth 2.0",
|
||||
"Log in with Connect ID": "Log in with Connect ID",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "Sub-account Outstanding Balance",
|
||||
"Balance Time": "Thời gian số dư",
|
||||
"Sub-account Balance Time": "Thời gian số dư tài khoản phụ",
|
||||
"Last Reconciled Time": "Last Reconciled Time",
|
||||
"Sub-account Last Reconciled Time": "Sub-account Last Reconciled Time",
|
||||
"Statement Date": "Statement Date",
|
||||
"Description": "Mô tả",
|
||||
"Your account description (optional)": "Mô tả tài khoản của bạn (tùy chọn)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "小数点",
|
||||
"Digit Grouping Symbol": "数字分组符号",
|
||||
"Digit Grouping": "数字分组",
|
||||
"Use Last Reconciled Time": "使用最后对账时间",
|
||||
"Editable Transaction Range": "可编辑交易范围",
|
||||
"Today or later": "今天或更晚",
|
||||
"Recent 24 hours or later": "最近24小时或更晚",
|
||||
"This week or later": "本周或更晚",
|
||||
"This month or later": "本月或更晚",
|
||||
"This year or later": "今年或更晚",
|
||||
"Last reconciled time or later": "最后对账时间或更晚",
|
||||
"Log In": "登录",
|
||||
"Log in with OAuth 2.0": "使用 OAuth 2.0 登录",
|
||||
"Log in with Connect ID": "使用 Connect ID 登录",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "子账户未清余额",
|
||||
"Balance Time": "余额时间",
|
||||
"Sub-account Balance Time": "子账户余额时间",
|
||||
"Last Reconciled Time": "最后对账时间",
|
||||
"Sub-account Last Reconciled Time": "子账户最后对账时间",
|
||||
"Statement Date": "账单日",
|
||||
"Description": "描述",
|
||||
"Your account description (optional)": "你的账户描述 (可选)",
|
||||
|
||||
@@ -1683,12 +1683,14 @@
|
||||
"Decimal Separator": "小數點",
|
||||
"Digit Grouping Symbol": "數字分組符號",
|
||||
"Digit Grouping": "數字分組",
|
||||
"Use Last Reconciled Time": "使用最後對帳時間",
|
||||
"Editable Transaction Range": "可編輯交易範圍",
|
||||
"Today or later": "今天或更晚",
|
||||
"Recent 24 hours or later": "最近24小時或更晚",
|
||||
"This week or later": "本週或更晚",
|
||||
"This month or later": "本月或更晚",
|
||||
"This year or later": "今年或更晚",
|
||||
"Last reconciled time or later": "最後對帳時間或更晚",
|
||||
"Log In": "登入",
|
||||
"Log in with OAuth 2.0": "使用 OAuth 2.0 登入",
|
||||
"Log in with Connect ID": "使用 Connect ID 登入",
|
||||
@@ -1922,6 +1924,8 @@
|
||||
"Sub-account Outstanding Balance": "子帳戶未清餘額",
|
||||
"Balance Time": "餘額時間",
|
||||
"Sub-account Balance Time": "子帳戶餘額時間",
|
||||
"Last Reconciled Time": "最後對帳時間",
|
||||
"Sub-account Last Reconciled Time": "子帳戶最後對帳時間",
|
||||
"Statement Date": "帳單日",
|
||||
"Description": "描述",
|
||||
"Your account description (optional)": "您的帳戶描述 (選填)",
|
||||
|
||||
+14
-1
@@ -15,6 +15,7 @@ export class Account implements AccountInfoResponse {
|
||||
public currency: string;
|
||||
public balance: number;
|
||||
public balanceTime?: number;
|
||||
public lastReconciledTime?: number;
|
||||
public comment: string;
|
||||
public creditCardStatementDate?: number;
|
||||
public displayOrder: number;
|
||||
@@ -24,7 +25,7 @@ export class Account implements AccountInfoResponse {
|
||||
private readonly _isAsset?: boolean;
|
||||
private readonly _isLiability?: boolean;
|
||||
|
||||
protected constructor(id: string, name: string, parentId: string, category: number, type: number, icon: string, color: string, currency: string, balance: number, comment: string, displayOrder: number, visible: boolean, balanceTime?: number, creditCardStatementDate?: number, isAsset?: boolean, isLiability?: boolean, subAccounts?: Account[]) {
|
||||
protected constructor(id: string, name: string, parentId: string, category: number, type: number, icon: string, color: string, currency: string, balance: number, comment: string, displayOrder: number, visible: boolean, balanceTime?: number, lastReconciledTime?: number, creditCardStatementDate?: number, isAsset?: boolean, isLiability?: boolean, subAccounts?: Account[]) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.parentId = parentId;
|
||||
@@ -35,6 +36,7 @@ export class Account implements AccountInfoResponse {
|
||||
this.currency = currency;
|
||||
this.balance = balance;
|
||||
this.balanceTime = balanceTime;
|
||||
this.lastReconciledTime = lastReconciledTime;
|
||||
this.comment = comment;
|
||||
this.displayOrder = displayOrder;
|
||||
this.visible = visible;
|
||||
@@ -92,6 +94,7 @@ export class Account implements AccountInfoResponse {
|
||||
this.currency === other.currency &&
|
||||
this.balance === other.balance &&
|
||||
this.balanceTime === other.balanceTime &&
|
||||
this.lastReconciledTime === other.lastReconciledTime &&
|
||||
this.comment === other.comment &&
|
||||
this.displayOrder === other.displayOrder &&
|
||||
this.visible === other.visible &&
|
||||
@@ -128,6 +131,7 @@ export class Account implements AccountInfoResponse {
|
||||
this.currency = other.currency;
|
||||
this.balance = other.balance;
|
||||
this.balanceTime = other.balanceTime;
|
||||
this.lastReconciledTime = other.lastReconciledTime;
|
||||
this.comment = other.comment;
|
||||
this.creditCardStatementDate = other.creditCardStatementDate;
|
||||
this.visible = other.visible;
|
||||
@@ -212,6 +216,7 @@ export class Account implements AccountInfoResponse {
|
||||
currency: parentAccount && (!this.id || this.id === '0') ? this.currency : undefined,
|
||||
balance: parentAccount && (!this.id || this.id === '0') ? this.balance : undefined,
|
||||
balanceTime: parentAccount && (!this.id || this.id === '0') ? this.balanceTime : undefined,
|
||||
lastReconciledTime: this.lastReconciledTime,
|
||||
comment: this.comment,
|
||||
creditCardStatementDate: !parentAccount && this.category === AccountCategory.CreditCard.type ? this.creditCardStatementDate : undefined,
|
||||
hidden: !this.visible,
|
||||
@@ -363,6 +368,7 @@ export class Account implements AccountInfoResponse {
|
||||
this.displayOrder,
|
||||
this.visible,
|
||||
this.balanceTime,
|
||||
this.lastReconciledTime,
|
||||
this.creditCardStatementDate,
|
||||
this.isAsset,
|
||||
this.isLiability
|
||||
@@ -384,6 +390,7 @@ export class Account implements AccountInfoResponse {
|
||||
this.displayOrder,
|
||||
this.visible,
|
||||
this.balanceTime,
|
||||
this.lastReconciledTime,
|
||||
this.creditCardStatementDate,
|
||||
this.isAsset,
|
||||
this.isLiability,
|
||||
@@ -405,6 +412,7 @@ export class Account implements AccountInfoResponse {
|
||||
0, // displayOrder
|
||||
true, // visible
|
||||
balanceTime, // balanceTime
|
||||
undefined, // lastReconciledTime
|
||||
0 // creditCardStatementDate
|
||||
);
|
||||
}
|
||||
@@ -424,6 +432,7 @@ export class Account implements AccountInfoResponse {
|
||||
0, // displayOrder
|
||||
true, // visible
|
||||
balanceTime, // balanceTime
|
||||
undefined, // lastReconciledTime
|
||||
0 // creditCardStatementDate
|
||||
);
|
||||
}
|
||||
@@ -443,6 +452,7 @@ export class Account implements AccountInfoResponse {
|
||||
accountResponse.displayOrder,
|
||||
!accountResponse.hidden,
|
||||
undefined,
|
||||
accountResponse.lastReconciledTime,
|
||||
accountResponse.creditCardStatementDate,
|
||||
accountResponse.isAsset,
|
||||
accountResponse.isLiability,
|
||||
@@ -557,6 +567,7 @@ export class AccountWithDisplayBalance extends Account {
|
||||
account.displayOrder,
|
||||
account.visible,
|
||||
account.balanceTime,
|
||||
account.lastReconciledTime,
|
||||
account.creditCardStatementDate,
|
||||
account.isAsset,
|
||||
account.isLiability,
|
||||
@@ -595,6 +606,7 @@ export interface AccountModifyRequest {
|
||||
readonly currency?: string;
|
||||
readonly balance?: number;
|
||||
readonly balanceTime?: number;
|
||||
readonly lastReconciledTime?: number;
|
||||
readonly comment: string;
|
||||
readonly creditCardStatementDate?: number;
|
||||
readonly hidden: boolean;
|
||||
@@ -612,6 +624,7 @@ export interface AccountInfoResponse {
|
||||
readonly color: string;
|
||||
readonly currency: string;
|
||||
readonly balance: number;
|
||||
readonly lastReconciledTime?: number;
|
||||
readonly comment: string;
|
||||
readonly creditCardStatementDate?: number;
|
||||
readonly displayOrder: number;
|
||||
|
||||
@@ -19,6 +19,7 @@ export class User {
|
||||
public firstDayOfWeek: number;
|
||||
|
||||
public defaultAccountId: string = EMPTY_USER_BASIC_INFO.defaultAccountId;
|
||||
public useLastReconciledTime: boolean = EMPTY_USER_BASIC_INFO.useLastReconciledTime;
|
||||
public transactionEditScope: number = EMPTY_USER_BASIC_INFO.transactionEditScope;
|
||||
public fiscalYearStart: number = EMPTY_USER_BASIC_INFO.fiscalYearStart;
|
||||
public calendarDisplayType: number = EMPTY_USER_BASIC_INFO.calendarDisplayType;
|
||||
@@ -48,6 +49,7 @@ export class User {
|
||||
this.email = user.email;
|
||||
this.nickname = user.nickname;
|
||||
this.defaultAccountId = user.defaultAccountId;
|
||||
this.useLastReconciledTime = user.useLastReconciledTime;
|
||||
this.transactionEditScope = user.transactionEditScope;
|
||||
this.language = user.language;
|
||||
this.defaultCurrency = user.defaultCurrency;
|
||||
@@ -90,6 +92,7 @@ export class User {
|
||||
password: this.password,
|
||||
oldPassword: currentPassword,
|
||||
defaultAccountId: this.defaultAccountId,
|
||||
useLastReconciledTime: this.useLastReconciledTime,
|
||||
transactionEditScope: this.transactionEditScope,
|
||||
language: this.language,
|
||||
defaultCurrency: this.defaultCurrency,
|
||||
@@ -116,6 +119,7 @@ export class User {
|
||||
public static of(userInfo: UserBasicInfo): User {
|
||||
const user = new User(userInfo.language, userInfo.defaultCurrency, userInfo.firstDayOfWeek);
|
||||
user.defaultAccountId = userInfo.defaultAccountId;
|
||||
user.useLastReconciledTime = userInfo.useLastReconciledTime;
|
||||
user.transactionEditScope = userInfo.transactionEditScope;
|
||||
user.fiscalYearStart = userInfo.fiscalYearStart;
|
||||
user.calendarDisplayType = userInfo.calendarDisplayType;
|
||||
@@ -149,6 +153,7 @@ export interface UserBasicInfo {
|
||||
readonly avatar: string;
|
||||
readonly avatarProvider?: string;
|
||||
readonly defaultAccountId: string;
|
||||
readonly useLastReconciledTime: boolean;
|
||||
readonly transactionEditScope: number;
|
||||
readonly language: string;
|
||||
readonly defaultCurrency: string;
|
||||
@@ -205,6 +210,7 @@ export interface UserProfileUpdateRequest {
|
||||
readonly password?: string;
|
||||
readonly oldPassword?: string;
|
||||
readonly defaultAccountId?: string;
|
||||
readonly useLastReconciledTime?: boolean;
|
||||
readonly transactionEditScope?: number;
|
||||
readonly language?: string;
|
||||
readonly defaultCurrency?: string;
|
||||
@@ -244,6 +250,7 @@ export const EMPTY_USER_BASIC_INFO: UserBasicInfo = {
|
||||
avatar: '',
|
||||
avatarProvider: undefined,
|
||||
defaultAccountId: '',
|
||||
useLastReconciledTime: false,
|
||||
transactionEditScope: TransactionEditScopeType.All.type,
|
||||
language: '',
|
||||
defaultCurrency: '',
|
||||
|
||||
@@ -66,6 +66,11 @@ export const useUserStore = defineStore('user', () => {
|
||||
return userInfo.defaultCurrency || settingsStore.localeDefaultSettings.currency;
|
||||
});
|
||||
|
||||
const currentUserUseLastReconciledTime = computed<boolean>(() => {
|
||||
const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO;
|
||||
return userInfo.useLastReconciledTime ?? false;
|
||||
});
|
||||
|
||||
const currentUserFirstDayOfWeek = computed<WeekDayValue>(() => {
|
||||
const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO;
|
||||
return isNumber(userInfo.firstDayOfWeek) && WeekDay.valueOf(userInfo.firstDayOfWeek) ? userInfo.firstDayOfWeek as WeekDayValue : settingsStore.localeDefaultSettings.firstDayOfWeek;
|
||||
@@ -443,6 +448,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
currentUserDefaultAccountId,
|
||||
currentUserLanguage,
|
||||
currentUserDefaultCurrency,
|
||||
currentUserUseLastReconciledTime,
|
||||
currentUserFirstDayOfWeek,
|
||||
currentUserFiscalYearStart,
|
||||
currentUserCalendarDisplayType,
|
||||
|
||||
@@ -38,6 +38,8 @@ export function useAccountEditPageBase() {
|
||||
const account = ref<Account>(Account.createNewAccount(defaultAccountCategory, userStore.currentUserDefaultCurrency, getCurrentUnixTimeForNewAccount()));
|
||||
const subAccounts = ref<Account[]>([]);
|
||||
|
||||
const useLastReconciledTime = computed(() => userStore.currentUserUseLastReconciledTime);
|
||||
|
||||
const title = computed<string>(() => {
|
||||
if (!editAccountId.value) {
|
||||
return 'Add Account';
|
||||
@@ -97,12 +99,12 @@ export function useAccountEditPageBase() {
|
||||
return getSameDateTimeWithCurrentTimezone(parseDateTimeFromUnixTimeWithBrowserTimezone(getCurrentUnixTime())).getUnixTime();
|
||||
}
|
||||
|
||||
function getDefaultTimezoneOffsetMinutes(account: Account): number {
|
||||
if (!account.balanceTime) {
|
||||
return 0;
|
||||
function getDefaultTimezoneOffsetMinutes(unixTime?: number): number {
|
||||
if (!unixTime) {
|
||||
return getTimezoneOffsetMinutes(getCurrentUnixTime());
|
||||
}
|
||||
|
||||
return getTimezoneOffsetMinutes(account.balanceTime);
|
||||
return getTimezoneOffsetMinutes(unixTime);
|
||||
}
|
||||
|
||||
function getAccountCreditCardStatementDate(statementDate?: number): string | null {
|
||||
@@ -132,6 +134,23 @@ export function useAccountEditPageBase() {
|
||||
account.balanceTime = balanceTime - (newUtcOffset - oldUtcOffset) * 60;
|
||||
}
|
||||
|
||||
function updateAccountLastReconciledTime(account: Account, lastReconciledTime: number): void {
|
||||
if (!isDefined(account.lastReconciledTime)) {
|
||||
account.lastReconciledTime = lastReconciledTime;
|
||||
return;
|
||||
}
|
||||
|
||||
const oldUtcOffset = getTimezoneOffsetMinutes(account.lastReconciledTime);
|
||||
const newUtcOffset = getTimezoneOffsetMinutes(lastReconciledTime);
|
||||
|
||||
if (oldUtcOffset === newUtcOffset) {
|
||||
account.lastReconciledTime = lastReconciledTime;
|
||||
return;
|
||||
}
|
||||
|
||||
account.lastReconciledTime = lastReconciledTime - (newUtcOffset - oldUtcOffset) * 60;
|
||||
}
|
||||
|
||||
function getInputEmptyProblemMessage(account: Account, isSubAccount: boolean): string | null {
|
||||
if (!isSubAccount && !account.category) {
|
||||
return 'Account category cannot be blank';
|
||||
@@ -189,6 +208,7 @@ export function useAccountEditPageBase() {
|
||||
account,
|
||||
subAccounts,
|
||||
// computed states
|
||||
useLastReconciledTime,
|
||||
title,
|
||||
saveButtonTitle,
|
||||
inputEmptyProblemMessage,
|
||||
@@ -202,6 +222,7 @@ export function useAccountEditPageBase() {
|
||||
getDefaultTimezoneOffsetMinutes,
|
||||
getAccountCreditCardStatementDate,
|
||||
updateAccountBalanceTime,
|
||||
updateAccountLastReconciledTime,
|
||||
isNewAccount,
|
||||
addSubAccount,
|
||||
setAccount
|
||||
|
||||
@@ -6,10 +6,11 @@ import { useSettingsStore } from '@/stores/setting.ts';
|
||||
import { useAccountsStore } from '@/stores/account.ts';
|
||||
import { useOverviewStore } from '@/stores/overview.ts';
|
||||
|
||||
import type { TypeAndDisplayName } from '@/core/base.ts';
|
||||
import type { TypeAndDisplayName, LocalizedSwitchOption } from '@/core/base.ts';
|
||||
import { DateDisplayType } from '@/core/calendar.ts';
|
||||
import { WeekDay } from '@/core/datetime.ts';
|
||||
import { type LocalizedDigitGroupingType, NumeralSystem, DecimalSeparator, DigitGroupingSymbol } from '@/core/numeral.ts';
|
||||
import { TransactionEditScopeType } from '@/core/transaction.ts';
|
||||
|
||||
import { type UserBasicInfo, User } from '@/models/user.ts';
|
||||
import { type CategorizedAccount, Account} from '@/models/account.ts';
|
||||
@@ -22,6 +23,7 @@ export function useUserProfilePageBase() {
|
||||
tt,
|
||||
getDefaultCurrency,
|
||||
getDefaultFirstDayOfWeek,
|
||||
getAllEnableDisableOptions,
|
||||
getAllWeekDays,
|
||||
getAllCalendarDisplayTypes,
|
||||
getAllDateDisplayTypes,
|
||||
@@ -85,7 +87,8 @@ export function useUserProfilePageBase() {
|
||||
const allCoordinateDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCoordinateDisplayTypes());
|
||||
const allExpenseAmountColorTypes = computed<TypeAndDisplayName[]>(() => getAllExpenseAmountColors());
|
||||
const allIncomeAmountColorTypes = computed<TypeAndDisplayName[]>(() => getAllIncomeAmountColors());
|
||||
const allTransactionEditScopeTypes = computed<TypeAndDisplayName[]>(() => getAllTransactionEditScopeTypes());
|
||||
const allTransactionEditScopeTypes = computed<TypeAndDisplayName[]>(() => getAllTransactionEditScopeTypes(newProfile.value.useLastReconciledTime || (TransactionEditScopeType.valueOf(newProfile.value.transactionEditScope)?.needLastReconciledTime ?? false)));
|
||||
const enableDisableOptions = computed<LocalizedSwitchOption[]>(() => getAllEnableDisableOptions());
|
||||
|
||||
const languageTitle = computed<string>(() => {
|
||||
const languageInCurrentLanguage = tt('Language');
|
||||
@@ -114,6 +117,7 @@ export function useUserProfilePageBase() {
|
||||
newProfile.value.email === oldProfile.value.email &&
|
||||
newProfile.value.nickname === oldProfile.value.nickname &&
|
||||
newProfile.value.defaultAccountId === oldProfile.value.defaultAccountId &&
|
||||
newProfile.value.useLastReconciledTime === oldProfile.value.useLastReconciledTime &&
|
||||
newProfile.value.transactionEditScope === oldProfile.value.transactionEditScope &&
|
||||
newProfile.value.language === oldProfile.value.language &&
|
||||
newProfile.value.defaultCurrency === oldProfile.value.defaultCurrency &&
|
||||
@@ -229,6 +233,7 @@ export function useUserProfilePageBase() {
|
||||
allExpenseAmountColorTypes,
|
||||
allIncomeAmountColorTypes,
|
||||
allTransactionEditScopeTypes,
|
||||
enableDisableOptions,
|
||||
languageTitle,
|
||||
supportDigitGroupingSymbol,
|
||||
inputIsNotChangedProblemMessage,
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
v-model="account.creditCardStatementDate"
|
||||
></v-autocomplete>
|
||||
</v-col>
|
||||
<v-col cols="12" :md="(!editAccountId || isNewAccount(selectedAccount)) && selectedAccount.balance ? 6 : 12"
|
||||
<v-col cols="12" :md="((canShowBalanceTime && selectedAccount.balance) || canShowLastReconciledTime) ? 6 : 12"
|
||||
v-if="account.type === AccountType.SingleAccount.type || currentAccountIndex >= 0">
|
||||
<amount-input :disabled="loading || submitting || (!!editAccountId && !isNewAccount(selectedAccount))"
|
||||
:persistent-placeholder="true"
|
||||
@@ -140,16 +140,27 @@
|
||||
:placeholder="accountAmountTitle"
|
||||
v-model="selectedAccount.balance"/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6" v-show="selectedAccount.balance"
|
||||
v-if="(!editAccountId || isNewAccount(selectedAccount)) && (account.type === AccountType.SingleAccount.type || currentAccountIndex >= 0)">
|
||||
<v-col cols="12" md="6" v-show="selectedAccount.balance" v-if="canShowBalanceTime">
|
||||
<date-time-select
|
||||
:disabled="loading || submitting"
|
||||
:label="tt('Balance Time')"
|
||||
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(selectedAccount)"
|
||||
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(selectedAccount.balanceTime)"
|
||||
:model-value="selectedAccount.balanceTime"
|
||||
@update:model-value="updateAccountBalanceTime(selectedAccount, $event)"
|
||||
@error="onShowDateTimeError" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6" v-if="canShowLastReconciledTime">
|
||||
<date-time-select
|
||||
:disabled="loading || submitting"
|
||||
:clearable="true"
|
||||
:label="tt('Last Reconciled Time')"
|
||||
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(selectedAccount.lastReconciledTime)"
|
||||
:model-value="selectedAccount.lastReconciledTime ?? getCurrentUnixTime()"
|
||||
:empty-value="!selectedAccount.lastReconciledTime"
|
||||
@update:model-value="updateAccountLastReconciledTime(selectedAccount, $event)"
|
||||
@clear:model-value="selectedAccount.lastReconciledTime = undefined"
|
||||
@error="onShowDateTimeError" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="12">
|
||||
<v-textarea
|
||||
type="text"
|
||||
@@ -212,6 +223,7 @@ import { ALL_ACCOUNT_COLORS } from '@/consts/color.ts';
|
||||
import { Account } from '@/models/account.ts';
|
||||
|
||||
import { isNumber } from '@/lib/common.ts';
|
||||
import { getCurrentUnixTime } from '@/lib/datetime.ts';
|
||||
import { generateRandomUUID } from '@/lib/misc.ts';
|
||||
|
||||
import {
|
||||
@@ -236,6 +248,7 @@ const {
|
||||
submitting,
|
||||
account,
|
||||
subAccounts,
|
||||
useLastReconciledTime,
|
||||
title,
|
||||
saveButtonTitle,
|
||||
inputEmptyProblemMessage,
|
||||
@@ -247,6 +260,7 @@ const {
|
||||
getCurrentUnixTimeForNewAccount,
|
||||
getDefaultTimezoneOffsetMinutes,
|
||||
updateAccountBalanceTime,
|
||||
updateAccountLastReconciledTime,
|
||||
isNewAccount,
|
||||
addSubAccount,
|
||||
setAccount
|
||||
@@ -262,6 +276,9 @@ const showState = ref<boolean>(false);
|
||||
const activeTab = ref<string>('account');
|
||||
const currentAccountIndex = ref<number>(-1);
|
||||
|
||||
const canShowBalanceTime = computed<boolean>(() => (!editAccountId.value || isNewAccount(selectedAccount.value)) && (account.value.type === AccountType.SingleAccount.type || currentAccountIndex.value >= 0));
|
||||
const canShowLastReconciledTime = computed<boolean>(() => useLastReconciledTime.value && !!editAccountId.value && !isNewAccount(selectedAccount.value) && (account.value.type === AccountType.SingleAccount.type || currentAccountIndex.value >= 0));
|
||||
|
||||
const selectedAccount = computed<Account>(() => {
|
||||
if (currentAccountIndex.value < 0) {
|
||||
return account.value;
|
||||
|
||||
@@ -96,6 +96,27 @@
|
||||
</two-column-select>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
item-title="displayName"
|
||||
item-value="value"
|
||||
persistent-placeholder
|
||||
:disabled="loading || saving"
|
||||
:label="tt('Use Last Reconciled Time')"
|
||||
:placeholder="tt('Use Last Reconciled Time')"
|
||||
:items="enableDisableOptions"
|
||||
v-model="newProfile.useLastReconciledTime"
|
||||
>
|
||||
<template #item="{ props, item }">
|
||||
<v-list-item :disabled="!item.raw.value && (TransactionEditScopeType.valueOf(newProfile.transactionEditScope)?.needLastReconciledTime ?? false)" v-bind="props">
|
||||
<template #title>
|
||||
<div class="text-truncate">{{ item.raw.displayName }}</div>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-select>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
item-title="displayName"
|
||||
@@ -408,6 +429,7 @@ import { useRootStore } from '@/stores/index.ts';
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
import { useAccountsStore } from '@/stores/account.ts';
|
||||
|
||||
import { TransactionEditScopeType } from '@/core/transaction.ts';
|
||||
import { SUPPORTED_IMAGE_EXTENSIONS } from '@/consts/file.ts';
|
||||
import type { UserProfileResponse } from '@/models/user.ts';
|
||||
import { Account } from '@/models/account.ts';
|
||||
@@ -452,6 +474,7 @@ const {
|
||||
allExpenseAmountColorTypes,
|
||||
allIncomeAmountColorTypes,
|
||||
allTransactionEditScopeTypes,
|
||||
enableDisableOptions,
|
||||
languageTitle,
|
||||
supportDigitGroupingSymbol,
|
||||
inputIsNotChangedProblemMessage,
|
||||
|
||||
@@ -219,27 +219,53 @@
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
class="account-edit-balancetime list-item-with-header-and-title"
|
||||
class="account-edit-datetime list-item-with-header-and-title"
|
||||
link="#" no-chevron
|
||||
v-show="account.balance"
|
||||
v-if="!editAccountId"
|
||||
>
|
||||
<template #header>
|
||||
<div class="account-edit-balancetime-header" @click="showDateTimeDialog(accountContext, 'time')">{{ tt('Balance Time') }}</div>
|
||||
<div class="account-edit-datetime-header" @click="showBalanceDateTimeDialog(accountContext, 'time')">{{ tt('Balance Time') }}</div>
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="account-edit-balancetime-title">
|
||||
<div @click="showDateTimeDialog(accountContext, 'date')">{{ formatAccountBalanceDate(account) }}</div> <div class="account-edit-balancetime-time" @click="showDateTimeDialog(accountContext, 'time')">{{ formatAccountBalanceTime(account) }}</div>
|
||||
<div class="account-edit-datetime-title">
|
||||
<div @click="showBalanceDateTimeDialog(accountContext, 'date')">{{ formatDate(account.balanceTime) }}</div> <div class="account-edit-datetime-time" @click="showBalanceDateTimeDialog(accountContext, 'time')">{{ formatTime(account.balanceTime) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<date-time-selection-sheet :init-mode="accountContext.balanceDateTimeSheetMode"
|
||||
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(account)"
|
||||
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(account.balanceTime)"
|
||||
:model-value="account.balanceTime"
|
||||
v-model:show="accountContext.showBalanceDateTimeSheet"
|
||||
@update:model-value="updateAccountBalanceTime(account, $event)">
|
||||
</date-time-selection-sheet>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
class="account-edit-datetime list-item-with-header-and-title"
|
||||
link="#" no-chevron
|
||||
v-if="editAccountId && useLastReconciledTime"
|
||||
>
|
||||
<template #header>
|
||||
<div class="account-edit-datetime-header" @click="showLastReconciledDateTimeDialog(accountContext, 'time')">{{ tt('Last Reconciled Time') }}</div>
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="account-edit-datetime-title" v-if="account.lastReconciledTime">
|
||||
<div @click="showLastReconciledDateTimeDialog(accountContext, 'date')">{{ formatDate(account.lastReconciledTime) }}</div> <div class="account-edit-datetime-time" @click="showLastReconciledDateTimeDialog(accountContext, 'time')">{{ formatTime(account.lastReconciledTime) }}</div>
|
||||
</div>
|
||||
<div class="account-edit-datetime-title" v-else>
|
||||
<div class="account-edit-datetime-time" @click="showLastReconciledDateTimeDialog(accountContext, 'date')">{{ tt('None') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<date-time-selection-sheet :init-mode="accountContext.lastReconciledDateTimeSheetMode"
|
||||
:clearable="true"
|
||||
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(account.lastReconciledTime)"
|
||||
:model-value="account.lastReconciledTime ?? getCurrentUnixTime()"
|
||||
v-model:show="accountContext.showLastReconciledTimeSheet"
|
||||
@update:model-value="updateAccountLastReconciledTime(account, $event)"
|
||||
@clear:model-value="account.lastReconciledTime = undefined">
|
||||
</date-time-selection-sheet>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item :title="tt('Visible')" v-if="editAccountId">
|
||||
<f7-toggle :checked="account.visible" @toggle:change="account.visible = $event"></f7-toggle>
|
||||
</f7-list-item>
|
||||
@@ -463,27 +489,53 @@
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
class="account-edit-balancetime list-item-with-header-and-title"
|
||||
class="account-edit-datetime list-item-with-header-and-title"
|
||||
link="#" no-chevron
|
||||
v-show="subAccount.balance"
|
||||
v-if="!editAccountId || isNewAccount(subAccount)"
|
||||
>
|
||||
<template #header>
|
||||
<div class="account-edit-balancetime-header" @click="showDateTimeDialog(subAccountContexts[idx] as AccountContext, 'time')">{{ tt('Sub-account Balance Time') }}</div>
|
||||
<div class="account-edit-datetime-header" @click="showBalanceDateTimeDialog(subAccountContexts[idx] as AccountContext, 'time')">{{ tt('Sub-account Balance Time') }}</div>
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="account-edit-balancetime-title">
|
||||
<div @click="showDateTimeDialog(subAccountContexts[idx] as AccountContext, 'date')">{{ formatAccountBalanceDate(subAccount) }}</div> <div class="account-edit-balancetime-time" @click="showDateTimeDialog(subAccountContexts[idx] as AccountContext, 'time')">{{ formatAccountBalanceTime(subAccount) }}</div>
|
||||
<div class="account-edit-datetime-title">
|
||||
<div @click="showBalanceDateTimeDialog(subAccountContexts[idx] as AccountContext, 'date')">{{ formatDate(subAccount.balanceTime) }}</div> <div class="account-edit-datetime-time" @click="showBalanceDateTimeDialog(subAccountContexts[idx] as AccountContext, 'time')">{{ formatTime(subAccount.balanceTime) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<date-time-selection-sheet :init-mode="subAccountContexts[idx]!.balanceDateTimeSheetMode"
|
||||
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(subAccount)"
|
||||
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(subAccount.balanceTime)"
|
||||
:model-value="subAccount.balanceTime"
|
||||
v-model:show="subAccountContexts[idx]!.showBalanceDateTimeSheet"
|
||||
@update:model-value="updateAccountBalanceTime(subAccount, $event)">
|
||||
</date-time-selection-sheet>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
class="account-edit-datetime list-item-with-header-and-title"
|
||||
link="#" no-chevron
|
||||
v-if="editAccountId && !isNewAccount(subAccount) && useLastReconciledTime"
|
||||
>
|
||||
<template #header>
|
||||
<div class="account-edit-datetime-header" @click="showLastReconciledDateTimeDialog(subAccountContexts[idx] as AccountContext, 'time')">{{ tt('Sub-account Last Reconciled Time') }}</div>
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="account-edit-datetime-title" v-if="subAccount.lastReconciledTime">
|
||||
<div @click="showLastReconciledDateTimeDialog(subAccountContexts[idx] as AccountContext, 'date')">{{ formatDate(subAccount.lastReconciledTime) }}</div> <div class="account-edit-datetime-time" @click="showLastReconciledDateTimeDialog(subAccountContexts[idx] as AccountContext, 'time')">{{ formatTime(subAccount.lastReconciledTime) }}</div>
|
||||
</div>
|
||||
<div class="account-edit-datetime-title" v-else>
|
||||
<div class="account-edit-datetime-time" @click="showLastReconciledDateTimeDialog(subAccountContexts[idx] as AccountContext, 'date')">{{ tt('None') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<date-time-selection-sheet :init-mode="subAccountContexts[idx]!.lastReconciledDateTimeSheetMode"
|
||||
:clearable="true"
|
||||
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(subAccount.lastReconciledTime)"
|
||||
:model-value="subAccount.lastReconciledTime ?? getCurrentUnixTime()"
|
||||
v-model:show="subAccountContexts[idx]!.showLastReconciledTimeSheet"
|
||||
@update:model-value="updateAccountLastReconciledTime(subAccount, $event)"
|
||||
@clear:model-value="subAccount.lastReconciledTime = undefined">
|
||||
</date-time-selection-sheet>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item :title="tt('Visible')" v-if="editAccountId && !isNewAccount(subAccount)">
|
||||
<f7-toggle :checked="subAccount.visible" @toggle:change="subAccount.visible = $event"></f7-toggle>
|
||||
</f7-list-item>
|
||||
@@ -542,6 +594,7 @@ import { isDefined, findDisplayNameByType } from '@/lib/common.ts';
|
||||
import { generateRandomUUID } from '@/lib/misc.ts';
|
||||
import {
|
||||
getTimezoneOffsetMinutes,
|
||||
getCurrentUnixTime,
|
||||
parseDateTimeFromUnixTimeWithTimezoneOffset
|
||||
} from '@/lib/datetime.ts';
|
||||
|
||||
@@ -552,7 +605,9 @@ interface AccountContext {
|
||||
showCreditCardStatementDatePopup: boolean;
|
||||
showBalanceSheet: boolean;
|
||||
showBalanceDateTimeSheet: boolean;
|
||||
showLastReconciledTimeSheet: boolean;
|
||||
balanceDateTimeSheetMode: string;
|
||||
lastReconciledDateTimeSheetMode: string;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -578,6 +633,7 @@ const {
|
||||
submitting,
|
||||
account,
|
||||
subAccounts,
|
||||
useLastReconciledTime,
|
||||
title,
|
||||
inputEmptyProblemMessage,
|
||||
inputIsEmpty,
|
||||
@@ -588,6 +644,7 @@ const {
|
||||
getDefaultTimezoneOffsetMinutes,
|
||||
getAccountCreditCardStatementDate,
|
||||
updateAccountBalanceTime,
|
||||
updateAccountLastReconciledTime,
|
||||
isNewAccount,
|
||||
addSubAccount,
|
||||
setAccount
|
||||
@@ -602,7 +659,9 @@ const DEFAULT_ACCOUNT_CONTEXT: AccountContext = {
|
||||
showCreditCardStatementDatePopup: false,
|
||||
showBalanceSheet: false,
|
||||
showBalanceDateTimeSheet: false,
|
||||
balanceDateTimeSheetMode: 'time'
|
||||
showLastReconciledTimeSheet: false,
|
||||
balanceDateTimeSheetMode: 'time',
|
||||
lastReconciledDateTimeSheetMode: 'time'
|
||||
};
|
||||
|
||||
const accountContext = ref<AccountContext>(Object.assign({}, DEFAULT_ACCOUNT_CONTEXT));
|
||||
@@ -621,21 +680,21 @@ function formatAccountDisplayBalance(selectedAccount: Account): string {
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(balance, selectedAccount.currency);
|
||||
}
|
||||
|
||||
function formatAccountBalanceDate(account: Account): string {
|
||||
if (!isDefined(account.balanceTime)) {
|
||||
function formatDate(unixTime?: number): string {
|
||||
if (!isDefined(unixTime)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(account.balanceTime, getTimezoneOffsetMinutes(account.balanceTime));
|
||||
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(unixTime, getTimezoneOffsetMinutes(unixTime));
|
||||
return formatDateTimeToLongDate(dateTime);
|
||||
}
|
||||
|
||||
function formatAccountBalanceTime(account: Account): string {
|
||||
if (!isDefined(account.balanceTime)) {
|
||||
function formatTime(unixTime?: number): string {
|
||||
if (!isDefined(unixTime)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(account.balanceTime, getTimezoneOffsetMinutes(account.balanceTime));
|
||||
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(unixTime, getTimezoneOffsetMinutes(unixTime));
|
||||
return formatDateTimeToLongTime(dateTime);
|
||||
}
|
||||
|
||||
@@ -739,11 +798,16 @@ function removeSubAccount(currentSubAccount: Account | null, confirm: boolean):
|
||||
}
|
||||
}
|
||||
|
||||
function showDateTimeDialog(accountContext: AccountContext, sheetMode: string): void {
|
||||
function showBalanceDateTimeDialog(accountContext: AccountContext, sheetMode: string): void {
|
||||
accountContext.balanceDateTimeSheetMode = sheetMode;
|
||||
accountContext.showBalanceDateTimeSheet = true;
|
||||
}
|
||||
|
||||
function showLastReconciledDateTimeDialog(accountContext: AccountContext, sheetMode: string): void {
|
||||
accountContext.lastReconciledDateTimeSheetMode = sheetMode;
|
||||
accountContext.showLastReconciledTimeSheet = true;
|
||||
}
|
||||
|
||||
function onPageAfterIn(): void {
|
||||
routeBackOnError(props.f7router, loadingError);
|
||||
}
|
||||
@@ -758,22 +822,21 @@ init();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.account-edit-balancetime .item-title {
|
||||
.account-edit-datetime .item-title {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.account-edit-balancetime .item-title > .item-header > .account-edit-balancetime-header {
|
||||
.account-edit-datetime .item-title > .item-header > .account-edit-datetime-header {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.account-edit-balancetime .item-title > .account-edit-balancetime-title {
|
||||
.account-edit-datetime .item-title > .account-edit-datetime-title {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.account-edit-balancetime .item-title > .account-edit-balancetime-title > .account-edit-balancetime-time {
|
||||
.account-edit-datetime .item-title > .account-edit-datetime-title > .account-edit-datetime-time {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading">
|
||||
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Default Account" title="Unspecified"></f7-list-item>
|
||||
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Use Last Reconciled Time" title="Disabled" link="#"></f7-list-item>
|
||||
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Editable Transaction Range" title="All" link="#"></f7-list-item>
|
||||
</f7-list>
|
||||
|
||||
@@ -118,6 +119,29 @@
|
||||
</two-column-list-item-selection-sheet>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
link="#"
|
||||
class="list-item-with-header-and-title list-item-no-item-after"
|
||||
popover-open=".use-last-reconciled-time-popover-menu"
|
||||
:header="tt('Use Last Reconciled Time')"
|
||||
:title="getEnableDisableOption(newProfile.useLastReconciledTime)"
|
||||
>
|
||||
<f7-popover class="use-last-reconciled-time-popover-menu">
|
||||
<f7-list dividers>
|
||||
<f7-list-item link="#" no-chevron popover-close
|
||||
:title="option.displayName"
|
||||
:class="{ 'list-item-selected': newProfile.useLastReconciledTime === option.value, 'disabled': !option.value && (TransactionEditScopeType.valueOf(newProfile.transactionEditScope)?.needLastReconciledTime ?? false) }"
|
||||
:key="option.value"
|
||||
v-for="option in enableDisableOptions"
|
||||
@click="newProfile.useLastReconciledTime = option.value">
|
||||
<template #after>
|
||||
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="newProfile.useLastReconciledTime === option.value"></f7-icon>
|
||||
</template>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-popover>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
link="#"
|
||||
class="list-item-with-header-and-title list-item-no-item-after"
|
||||
@@ -572,6 +596,7 @@ import { useAccountsStore } from '@/stores/account.ts';
|
||||
import { TextDirection } from '@/core/text.ts';
|
||||
import { NumeralSystem } from '@/core/numeral.ts';
|
||||
import type { LocalizedCurrencyInfo } from '@/core/currency.ts';
|
||||
import { TransactionEditScopeType } from '@/core/transaction.ts';
|
||||
|
||||
import type { UserProfileResponse } from '@/models/user.ts';
|
||||
import { Account } from '@/models/account.ts';
|
||||
@@ -588,6 +613,7 @@ const {
|
||||
getCurrentLanguageTextDirection,
|
||||
getAllLanguageOptions,
|
||||
getAllCurrencies,
|
||||
getEnableDisableOption,
|
||||
getCurrencyName,
|
||||
formatFiscalYearStartToGregorianLikeLongMonth
|
||||
} = useI18n();
|
||||
@@ -620,6 +646,7 @@ const {
|
||||
allExpenseAmountColorTypes,
|
||||
allIncomeAmountColorTypes,
|
||||
allTransactionEditScopeTypes,
|
||||
enableDisableOptions,
|
||||
languageTitle,
|
||||
supportDigitGroupingSymbol,
|
||||
inputIsNotChangedProblemMessage,
|
||||
|
||||
Reference in New Issue
Block a user