@@ -311,11 +311,27 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
311
311
return nil , errs .NewIncompleteOrIncorrectSubmissionError (err )
312
312
}
313
313
314
+ if accountModifyReq .Id <= 0 {
315
+ return nil , errs .ErrAccountIdInvalid
316
+ }
317
+
318
+ utcOffset , err := c .GetClientTimezoneOffset ()
319
+
320
+ if err != nil {
321
+ log .Warnf (c , "[accounts.AccountModifyHandler] cannot get client timezone offset, because %s" , err .Error ())
322
+ return nil , errs .ErrClientTimezoneOffsetInvalid
323
+ }
324
+
314
325
if accountModifyReq .Category < models .ACCOUNT_CATEGORY_CASH || accountModifyReq .Category > models .ACCOUNT_CATEGORY_CERTIFICATE_OF_DEPOSIT {
315
326
log .Warnf (c , "[accounts.AccountModifyHandler] account category invalid, category is %d" , accountModifyReq .Category )
316
327
return nil , errs .ErrAccountCategoryInvalid
317
328
}
318
329
330
+ if accountModifyReq .Category != models .ACCOUNT_CATEGORY_CREDIT_CARD && accountModifyReq .CreditCardStatementDate != 0 {
331
+ log .Warnf (c , "[accounts.AccountModifyHandler] cannot set statement date with category \" %d\" " , accountModifyReq .Category )
332
+ return nil , errs .ErrCannotSetStatementDateForNonCreditCard
333
+ }
334
+
319
335
uid := c .GetCurrentUid ()
320
336
accountAndSubAccounts , err := a .accounts .GetAccountAndSubAccountsByAccountId (c , uid , accountModifyReq .Id )
321
337
@@ -331,20 +347,81 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
331
347
return nil , errs .ErrAccountNotFound
332
348
}
333
349
334
- if len ( accountModifyReq .SubAccounts ) + 1 != len ( accountAndSubAccounts ) {
335
- return nil , errs .ErrCannotAddOrDeleteSubAccountsWhenModify
350
+ if accountModifyReq .Currency != nil && mainAccount . Currency != * accountModifyReq . Currency {
351
+ return nil , errs .ErrNotSupportedChangeCurrency
336
352
}
337
353
338
- if accountModifyReq .Category != models .ACCOUNT_CATEGORY_CREDIT_CARD && accountModifyReq .CreditCardStatementDate != 0 {
339
- log .Warnf (c , "[accounts.AccountModifyHandler] cannot set statement date with category \" %d\" " , accountModifyReq .Category )
340
- return nil , errs .ErrCannotSetStatementDateForNonCreditCard
354
+ if accountModifyReq .Balance != nil {
355
+ return nil , errs .ErrNotSupportedChangeBalance
356
+ }
357
+
358
+ if accountModifyReq .BalanceTime != nil {
359
+ return nil , errs .ErrNotSupportedChangeBalanceTime
341
360
}
342
361
343
- if mainAccount .Type == models .ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS {
362
+ if mainAccount .Type == models .ACCOUNT_TYPE_SINGLE_ACCOUNT {
363
+ if len (accountModifyReq .SubAccounts ) > 0 {
364
+ log .Warnf (c , "[accounts.AccountModifyHandler] account cannot have any sub-accounts" )
365
+ return nil , errs .ErrAccountCannotHaveSubAccounts
366
+ }
367
+ } else if mainAccount .Type == models .ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS {
368
+ if len (accountModifyReq .SubAccounts ) < 1 {
369
+ log .Warnf (c , "[accounts.AccountModifyHandler] account does not have any sub-accounts" )
370
+ return nil , errs .ErrAccountHaveNoSubAccount
371
+ }
372
+
344
373
for i := 0 ; i < len (accountModifyReq .SubAccounts ); i ++ {
345
- subAccount := accountModifyReq .SubAccounts [i ]
374
+ subAccountReq := accountModifyReq .SubAccounts [i ]
346
375
347
- if subAccount .CreditCardStatementDate != 0 {
376
+ if subAccountReq .Category != accountModifyReq .Category {
377
+ log .Warnf (c , "[accounts.AccountModifyHandler] category of sub-account#%d not equals to parent" , i )
378
+ return nil , errs .ErrSubAccountCategoryNotEqualsToParent
379
+ }
380
+
381
+ if subAccountReq .Id == 0 { // create new sub-account
382
+ if subAccountReq .Currency == nil {
383
+ log .Warnf (c , "[accounts.AccountModifyHandler] sub-account#%d not set currency" , i )
384
+ return nil , errs .ErrAccountCurrencyInvalid
385
+ } else if subAccountReq .Currency != nil && * subAccountReq .Currency == validators .ParentAccountCurrencyPlaceholder {
386
+ log .Warnf (c , "[accounts.AccountModifyHandler] sub-account#%d cannot set currency placeholder" , i )
387
+ return nil , errs .ErrAccountCurrencyInvalid
388
+ }
389
+
390
+ if subAccountReq .Balance == nil {
391
+ defaultBalance := int64 (0 )
392
+ subAccountReq .Balance = & defaultBalance
393
+ }
394
+
395
+ if * subAccountReq .Balance == 0 {
396
+ defaultBalanceTime := int64 (0 )
397
+ subAccountReq .BalanceTime = & defaultBalanceTime
398
+ }
399
+
400
+ if * subAccountReq .Balance != 0 && (subAccountReq .BalanceTime == nil || * subAccountReq .BalanceTime <= 0 ) {
401
+ log .Warnf (c , "[accounts.AccountModifyHandler] sub-account#%d balance time is not set" , i )
402
+ return nil , errs .ErrAccountBalanceTimeNotSet
403
+ }
404
+ } else { // modify existed sub-account
405
+ subAccount , exists := accountMap [subAccountReq .Id ]
406
+
407
+ if ! exists {
408
+ return nil , errs .ErrAccountNotFound
409
+ }
410
+
411
+ if subAccountReq .Currency != nil && subAccount .Currency != * subAccountReq .Currency {
412
+ return nil , errs .ErrNotSupportedChangeCurrency
413
+ }
414
+
415
+ if subAccountReq .Balance != nil {
416
+ return nil , errs .ErrNotSupportedChangeBalance
417
+ }
418
+
419
+ if subAccountReq .BalanceTime != nil {
420
+ return nil , errs .ErrNotSupportedChangeBalanceTime
421
+ }
422
+ }
423
+
424
+ if subAccountReq .CreditCardStatementDate != 0 {
348
425
log .Warnf (c , "[accounts.AccountModifyHandler] sub-account#%d cannot set statement date" , i )
349
426
return nil , errs .ErrCannotSetStatementDateForSubAccount
350
427
}
@@ -353,6 +430,9 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
353
430
354
431
anythingUpdate := false
355
432
var toUpdateAccounts []* models.Account
433
+ var toAddAccounts []* models.Account
434
+ var toAddAccountBalanceTimes []int64
435
+ var toDeleteAccountIds []int64
356
436
357
437
toUpdateAccount := a .getToUpdateAccount (uid , & accountModifyReq , mainAccount , false )
358
438
@@ -361,26 +441,87 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
361
441
toUpdateAccounts = append (toUpdateAccounts , toUpdateAccount )
362
442
}
363
443
364
- for i := 0 ; i < len (accountModifyReq .SubAccounts ); i ++ {
365
- subAccountReq := accountModifyReq .SubAccounts [i ]
444
+ toDeleteAccountIds = a .getToDeleteSubAccountIds (& accountModifyReq , mainAccount , accountAndSubAccounts )
366
445
367
- if _ , exists := accountMap [subAccountReq .Id ]; ! exists {
368
- return nil , errs .ErrAccountNotFound
446
+ if len (toDeleteAccountIds ) > 0 {
447
+ anythingUpdate = true
448
+ }
449
+
450
+ maxOrderId := int32 (0 )
451
+
452
+ for i := 0 ; i < len (accountAndSubAccounts ); i ++ {
453
+ account := accountAndSubAccounts [i ]
454
+
455
+ if account .AccountId != mainAccount .AccountId && account .DisplayOrder > maxOrderId {
456
+ maxOrderId = account .DisplayOrder
369
457
}
458
+ }
370
459
371
- toUpdateSubAccount := a .getToUpdateAccount (uid , subAccountReq , accountMap [subAccountReq .Id ], true )
460
+ for i := 0 ; i < len (accountModifyReq .SubAccounts ); i ++ {
461
+ subAccountReq := accountModifyReq .SubAccounts [i ]
372
462
373
- if toUpdateSubAccount != nil {
463
+ if _ , exists := accountMap [ subAccountReq . Id ]; ! exists {
374
464
anythingUpdate = true
375
- toUpdateAccounts = append (toUpdateAccounts , toUpdateSubAccount )
465
+ maxOrderId = maxOrderId + 1
466
+ newSubAccount := a .createNewSubAccountModelForModify (uid , mainAccount .Type , subAccountReq , maxOrderId )
467
+ toAddAccounts = append (toAddAccounts , newSubAccount )
468
+
469
+ if subAccountReq .BalanceTime != nil {
470
+ toAddAccountBalanceTimes = append (toAddAccountBalanceTimes , * subAccountReq .BalanceTime )
471
+ } else {
472
+ toAddAccountBalanceTimes = append (toAddAccountBalanceTimes , 0 )
473
+ }
474
+ } else {
475
+ toUpdateSubAccount := a .getToUpdateAccount (uid , subAccountReq , accountMap [subAccountReq .Id ], true )
476
+
477
+ if toUpdateSubAccount != nil {
478
+ anythingUpdate = true
479
+ toUpdateAccounts = append (toUpdateAccounts , toUpdateSubAccount )
480
+ }
376
481
}
377
482
}
378
483
379
484
if ! anythingUpdate {
380
485
return nil , errs .ErrNothingWillBeUpdated
381
486
}
382
487
383
- err = a .accounts .ModifyAccounts (c , uid , toUpdateAccounts )
488
+ if len (toAddAccounts ) > 0 && a .CurrentConfig ().EnableDuplicateSubmissionsCheck && accountModifyReq .ClientSessionId != "" {
489
+ found , remark := a .GetSubmissionRemark (duplicatechecker .DUPLICATE_CHECKER_TYPE_NEW_SUBACCOUNT , uid , accountModifyReq .ClientSessionId )
490
+
491
+ if found {
492
+ log .Infof (c , "[accounts.AccountModifyHandler] another account \" id:%s\" modification has been created for user \" uid:%d\" " , remark , uid )
493
+ accountId , err := utils .StringToInt64 (remark )
494
+
495
+ if err == nil {
496
+ accountAndSubAccounts , err := a .accounts .GetAccountAndSubAccountsByAccountId (c , uid , accountId )
497
+
498
+ if err != nil {
499
+ log .Errorf (c , "[accounts.AccountModifyHandler] failed to get existed account \" id:%d\" for user \" uid:%d\" , because %s" , accountId , uid , err .Error ())
500
+ return nil , errs .Or (err , errs .ErrOperationFailed )
501
+ }
502
+
503
+ accountMap := a .accounts .GetAccountMapByList (accountAndSubAccounts )
504
+ mainAccount , exists := accountMap [accountId ]
505
+
506
+ if ! exists {
507
+ return nil , errs .ErrOperationFailed
508
+ }
509
+
510
+ accountInfoResp := mainAccount .ToAccountInfoResponse ()
511
+
512
+ for i := 0 ; i < len (accountAndSubAccounts ); i ++ {
513
+ if accountAndSubAccounts [i ].ParentAccountId == mainAccount .AccountId {
514
+ subAccountResp := accountAndSubAccounts [i ].ToAccountInfoResponse ()
515
+ accountInfoResp .SubAccounts = append (accountInfoResp .SubAccounts , subAccountResp )
516
+ }
517
+ }
518
+
519
+ return accountInfoResp , nil
520
+ }
521
+ }
522
+ }
523
+
524
+ err = a .accounts .ModifyAccounts (c , mainAccount , toUpdateAccounts , toAddAccounts , toAddAccountBalanceTimes , toDeleteAccountIds , utcOffset )
384
525
385
526
if err != nil {
386
527
log .Errorf (c , "[accounts.AccountModifyHandler] failed to update account \" id:%d\" for user \" uid:%d\" , because %s" , accountModifyReq .Id , uid , err .Error ())
@@ -389,6 +530,10 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
389
530
390
531
log .Infof (c , "[accounts.AccountModifyHandler] user \" uid:%d\" has updated account \" id:%d\" successfully" , uid , accountModifyReq .Id )
391
532
533
+ if len (toAddAccounts ) > 0 {
534
+ a .SetSubmissionRemarkIfEnable (duplicatechecker .DUPLICATE_CHECKER_TYPE_NEW_SUBACCOUNT , uid , accountModifyReq .ClientSessionId , utils .Int64ToString (mainAccount .AccountId ))
535
+ }
536
+
392
537
accountRespMap := make (map [int64 ]* models.AccountInfoResponse )
393
538
394
539
for i := 0 ; i < len (toUpdateAccounts ); i ++ {
@@ -405,11 +550,23 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
405
550
accountRespMap [accountResp .Id ] = accountResp
406
551
}
407
552
553
+ for i := 0 ; i < len (toAddAccounts ); i ++ {
554
+ account := toAddAccounts [i ]
555
+ accountResp := account .ToAccountInfoResponse ()
556
+ accountRespMap [accountResp .Id ] = accountResp
557
+ }
558
+
559
+ deletedAccountIds := make (map [int64 ]bool )
560
+
561
+ for i := 0 ; i < len (toDeleteAccountIds ); i ++ {
562
+ deletedAccountIds [toDeleteAccountIds [i ]] = true
563
+ }
564
+
408
565
for i := 0 ; i < len (accountAndSubAccounts ); i ++ {
409
566
oldAccount := accountAndSubAccounts [i ]
410
567
_ , exists := accountRespMap [oldAccount .AccountId ]
411
568
412
- if ! exists {
569
+ if ! exists && ! deletedAccountIds [ oldAccount . AccountId ] {
413
570
oldAccountResp := oldAccount .ToAccountInfoResponse ()
414
571
accountRespMap [oldAccountResp .Id ] = oldAccountResp
415
572
}
@@ -418,8 +575,19 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
418
575
accountResp := accountRespMap [accountModifyReq .Id ]
419
576
420
577
for i := 0 ; i < len (accountAndSubAccounts ); i ++ {
421
- if accountAndSubAccounts [i ].ParentAccountId == accountResp .Id {
422
- subAccountResp := accountRespMap [accountAndSubAccounts [i ].AccountId ]
578
+ account := accountAndSubAccounts [i ]
579
+
580
+ if account .ParentAccountId == accountResp .Id && ! deletedAccountIds [account .AccountId ] {
581
+ subAccountResp := accountRespMap [account .AccountId ]
582
+ accountResp .SubAccounts = append (accountResp .SubAccounts , subAccountResp )
583
+ }
584
+ }
585
+
586
+ for i := 0 ; i < len (toAddAccounts ); i ++ {
587
+ account := toAddAccounts [i ]
588
+
589
+ if account .ParentAccountId == accountResp .Id {
590
+ subAccountResp := accountRespMap [account .AccountId ]
423
591
accountResp .SubAccounts = append (accountResp .SubAccounts , subAccountResp )
424
592
}
425
593
}
@@ -552,6 +720,24 @@ func (a *AccountsApi) createNewAccountModel(uid int64, accountCreateReq *models.
552
720
}
553
721
}
554
722
723
+ func (a * AccountsApi ) createNewSubAccountModelForModify (uid int64 , accountType models.AccountType , accountModifyReq * models.AccountModifyRequest , order int32 ) * models.Account {
724
+ accountExtend := & models.AccountExtend {}
725
+
726
+ return & models.Account {
727
+ Uid : uid ,
728
+ Name : accountModifyReq .Name ,
729
+ DisplayOrder : order ,
730
+ Category : accountModifyReq .Category ,
731
+ Type : accountType ,
732
+ Icon : accountModifyReq .Icon ,
733
+ Color : accountModifyReq .Color ,
734
+ Currency : * accountModifyReq .Currency ,
735
+ Balance : * accountModifyReq .Balance ,
736
+ Comment : accountModifyReq .Comment ,
737
+ Extend : accountExtend ,
738
+ }
739
+ }
740
+
555
741
func (a * AccountsApi ) createSubAccountModels (uid int64 , accountCreateReq * models.AccountCreateRequest ) ([]* models.Account , []int64 ) {
556
742
if len (accountCreateReq .SubAccounts ) <= 0 {
557
743
return nil , nil
@@ -609,3 +795,27 @@ func (a *AccountsApi) getToUpdateAccount(uid int64, accountModifyReq *models.Acc
609
795
610
796
return nil
611
797
}
798
+
799
+ func (a * AccountsApi ) getToDeleteSubAccountIds (accountModifyReq * models.AccountModifyRequest , mainAccount * models.Account , accountAndSubAccounts []* models.Account ) []int64 {
800
+ newSubAccountIds := make (map [int64 ]bool , len (accountModifyReq .SubAccounts ))
801
+
802
+ for i := 0 ; i < len (accountModifyReq .SubAccounts ); i ++ {
803
+ newSubAccountIds [accountModifyReq .SubAccounts [i ].Id ] = true
804
+ }
805
+
806
+ toDeleteAccountIds := make ([]int64 , 0 )
807
+
808
+ for i := 0 ; i < len (accountAndSubAccounts ); i ++ {
809
+ subAccount := accountAndSubAccounts [i ]
810
+
811
+ if subAccount .AccountId == mainAccount .AccountId {
812
+ continue
813
+ }
814
+
815
+ if _ , exists := newSubAccountIds [subAccount .AccountId ]; ! exists {
816
+ toDeleteAccountIds = append (toDeleteAccountIds , subAccount .AccountId )
817
+ }
818
+ }
819
+
820
+ return toDeleteAccountIds
821
+ }
0 commit comments