namespace MyOffice.Services.Account; using MyOffice.Core; using MyOffice.Data.Models.Accounts; using MyOffice.Services.Account.Domain; public partial class AccountService { public async Task> GetAllCategoriesAsync(Guid userId, CancellationToken cancellationToken = default) { var categories = await _accountCategoryRepository.GetAllAsync(userId, cancellationToken); return _mapper.Map>(categories); } public async Task> GetCategoryAsync( Guid userId, Guid id, CancellationToken cancellationToken = default) { var result = new Exec(GeneralExecStatus.success); var category = await _accountCategoryRepository.GetAsync(userId, id, cancellationToken); if (category == null) { return result.Set(GeneralExecStatus.not_found); } return result.Set(_mapper.Map(category)); } public async Task> CategoryAddAsync( Guid userId, AccountCategoryDto input, CancellationToken cancellationToken = default) { if (input == null) throw new ArgumentNullException(nameof(input)); var result = new Exec(GeneralExecStatus.success); var category = new AccountCategory { Id = Guid.NewGuid(), UserId = userId, Name = input.Name, }; if (!await _accountCategoryRepository.AddAsync(category, cancellationToken)) { return result.Set(GeneralExecStatus.failure); } return result.Set(_mapper.Map(category)); } public async Task> CategoryUpdateAsync( Guid userId, Guid id, AccountCategoryDto input, CancellationToken cancellationToken = default) { if (input == null) throw new ArgumentNullException(nameof(input)); var result = new Exec(GeneralExecStatus.success); var exists = await _accountCategoryRepository.GetAsync(userId, id, cancellationToken); if (exists == null) { return result.Set(GeneralExecStatus.not_found); } exists.Name = input.Name; if (!await _accountCategoryRepository.UpdateAsync(exists, cancellationToken)) { return result.Set(GeneralExecStatus.failure); } return result.Set(_mapper.Map(exists)); } public async Task> CategoryRemoveAsync( Guid userId, Guid id, CancellationToken cancellationToken = default) { var result = new Exec(AccountCategoryRemoveResult.success); var exists = await _accountCategoryRepository.GetAsync(userId, id, cancellationToken); if (exists == null) { return result.Set(AccountCategoryRemoveResult.not_found); } if (exists.Accounts?.Any() == true) { return result.Set(AccountCategoryRemoveResult.accounts_exists); } if (!await _accountCategoryRepository.RemoveAsync(exists, cancellationToken)) { return result.Set(AccountCategoryRemoveResult.failure); } return result.Set(_mapper.Map(exists)); } public async Task> AccountCategoryRemoveAsync( Guid userId, Guid accountId, Guid categoryId, CancellationToken cancellationToken = default) { var result = new Exec(GeneralExecStatus.success); var account = await _accountRepository.GetAsync(userId, accountId, cancellationToken); if (account == null) { return result.Set(GeneralExecStatus.not_found); } if (!CanManage(account, userId)) { return result.Set(GeneralExecStatus.forbidden); } var links = await _accountAccountCategoryRepository.GetAsync(userId, accountId, categoryId, cancellationToken); if (links.Count == 0) { return result.Set(GeneralExecStatus.not_found); } foreach (var link in links) { await _accountAccountCategoryRepository.RemoveAsync(link, cancellationToken); } // Account stays tracked after Remove; filter in-memory so the response is not stale. account.Categories = account.Categories? .Where(c => c.CategoryId != categoryId) .ToList(); return result.Set(account.ToDto(_mapper)); } }