namespace BankOperationsUpdate.WorkerService.OperationsUpdate; public class UpdateOperations { private IRepositoryWrapper _repositoryWrapper; private readonly ILogger _logger; private readonly IServiceProvider _provider; public UpdateOperations(ILogger logger, IServiceProvider provider) { _logger = logger; _provider = provider; } public void WhenStart() { using (var scope = _provider.CreateScope()) { _repositoryWrapper = scope.ServiceProvider.GetRequiredService(); SetTransactionsInitial(); } } public void Execute() { using (var scope = _provider.CreateScope()) { _repositoryWrapper = scope.ServiceProvider.GetRequiredService(); AddConfirmedOperations(); } using (var scope = _provider.CreateScope()) { _repositoryWrapper = scope.ServiceProvider.GetRequiredService(); UpdateConfirmedTransactions(); } } #region Different Get methods public IQueryable GetAllOperations() => _repositoryWrapper.BankOperation.GetAll(); public IQueryable GetAllConfirmedOperations() => _repositoryWrapper.BankOperation.GetAllConfirmed(Guid.Empty, Guid.Empty); public IQueryable GetAllConfirmedOperations(Guid accountId, Guid businessId) => _repositoryWrapper.BankOperation.GetAllConfirmed(accountId, businessId); public IQueryable GetAllNewOperations() => _repositoryWrapper.BankOperation.GetAllNew(Guid.Empty, Guid.Empty); public IQueryable GetAllNewOperations(Guid accountId, Guid businessId) => _repositoryWrapper.BankOperation.GetAllNew(accountId, businessId); public IQueryable GetAllBankBalances() => _repositoryWrapper.BankAccountBalance.FindAll(); public BankAccountBalance GetAccountBalanceByBusinessId(Guid accountId, Guid businessId) => _repositoryWrapper.BankAccountBalance.GetByBankAccountId(accountId, businessId).FirstOrDefault(); public IQueryable GetTransactionsByAccountId(Guid accountId, Guid businessId) => _repositoryWrapper.Transaction.GetByAccountId(accountId, businessId); public IQueryable GetAllTransactions() => _repositoryWrapper.Transaction.FindAll(); public Transaction GetTransactionByOperationId(Guid operationId) => _repositoryWrapper.Transaction.GetByOperationId(operationId); #endregion void SetTransactionsInitial() { var bankBalances = GetAllBankBalances().ToList(); decimal? currentBalance; for(int i = 0; i < bankBalances.Count; i++) { currentBalance = bankBalances[i].Amount; _logger.LogDebug("Process for account {0}", bankBalances[i].Id); SetTransactionsForAccount(currentBalance, bankBalances[i].BankAccountId.Value, bankBalances[i].BusinessId.Value); } } void AddConfirmedOperations() { var operations = GetAllConfirmedOperations().OrderBy(x => x.DocDate).ThenBy(x => x.CreatedDate).ToList(); var newOperations = GetAllNewOperations().OrderBy(x => x.DocDate).ThenBy(x => x.CreatedDate).ToList(); var transactiondHashSet = GetAllTransactions().Select(x => x.BankOperationId).ToHashSet(); BankAccountBalance accountBalance; Transaction transaction; foreach (var item in operations) { if (!transactiondHashSet.Contains(item.Id)) { accountBalance = GetAccountBalanceByBusinessId(item.BankAccountId.Value, item.BusinessId.Value); accountBalance.Amount = accountBalance.Amount!.Value + item.IncomeAmount!.Value - item.OutcomeAmount!.Value; transaction = new Transaction { Id = Guid.NewGuid(), BankOperationId = item.Id, IncomeAmount = item.IncomeAmount, OutcomeAmount = item.OutcomeAmount, BalanceAmount = item.IncomeAmount!.Value - item.OutcomeAmount!.Value, ModifiedDate = item.DocDate, BusinessId = item.BusinessId.Value, BankAccountId = item.BankAccountId.Value, CreateDate = DateTime.Now, OperationCreateDate = item.CreatedDate!.Value, IsChanged = true, }; _logger.LogInformation(Environment.NewLine + "Created new Transaction {0}", transaction.Id); _repositoryWrapper.Transaction.Create(transaction); _repositoryWrapper.BankAccountBalance.Update(accountBalance); _repositoryWrapper.Save(); _repositoryWrapper.Transaction.Detach(transaction); _repositoryWrapper.BankAccountBalance.Detach(accountBalance); } else if(transactiondHashSet.Contains(item.Id) && item.IsChanged == true) { UpdateChangedOperations(item, true); } } foreach (var item in newOperations) { if (transactiondHashSet.Contains(item.Id)) { UpdateChangedOperations(item, false); } } } void UpdateChangedOperations(BankOperation operation, bool IsChanged) { Transaction transaction = GetTransactionByOperationId(operation.Id); var accountBalance = GetAccountBalanceByBusinessId(operation.BankAccountId.Value, operation.BusinessId.Value); decimal incomeDifference, outcomeDifference; if (!IsChanged) { incomeDifference = -1 * transaction.IncomeAmount.Value; outcomeDifference = -1 * transaction.OutcomeAmount.Value; _repositoryWrapper.Transaction.Delete(transaction); } else { incomeDifference = operation.IncomeAmount.Value - transaction.IncomeAmount.Value; outcomeDifference = operation.OutcomeAmount.Value - transaction.OutcomeAmount.Value; transaction.IncomeAmount += incomeDifference; transaction.OutcomeAmount += outcomeDifference; operation.IsChanged = false; _logger.LogInformation("Updated transaction with id: {0}", transaction.Id); _repositoryWrapper.Transaction.Update(transaction); _repositoryWrapper.BankOperation.Update(operation); } accountBalance.Amount = accountBalance.Amount + incomeDifference - outcomeDifference; _repositoryWrapper.BankAccountBalance.Update(accountBalance); _repositoryWrapper.Save(); _repositoryWrapper.Transaction.Detach(transaction); var transactionsList = GetTransactionsByAccountId(operation.BankAccountId.Value, operation.BusinessId.Value).Where(x => x.BusinessId == operation.BusinessId && x.BankAccountId == operation.BankAccountId && DateTime.Compare(x.ModifiedDate.Value, transaction.ModifiedDate.Value) >= 0).OrderBy(x => x.ModifiedDate).ThenBy(x => x.OperationCreateDate).ToList(); foreach(var item in transactionsList) { item.BalanceAmount = item.BalanceAmount + incomeDifference - outcomeDifference; _logger.LogInformation("Updated transaction with id: {0}", transaction.Id); _repositoryWrapper.Transaction.Update(item); _repositoryWrapper.Save(); _repositoryWrapper.Transaction.Detach(item); } } void UpdateConfirmedTransactions() { var bankAccounts = GetAllBankBalances().ToList(); List transactions; decimal newValue = 0M; foreach (var account in bankAccounts) { transactions = GetTransactionsByAccountId(account.BankAccountId.Value, account.BusinessId.Value).OrderBy(x => x.ModifiedDate).ThenBy(x => x.OperationCreateDate).ToList(); for (int i = 1; i < transactions.Count; i++) { if (transactions[i].IsChanged == true) { transactions[i].BalanceAmount += transactions[i - 1].BalanceAmount; newValue += transactions[i].IncomeAmount.Value - transactions[i].OutcomeAmount.Value; transactions[i].IsChanged = false; } else { transactions[i].BalanceAmount += newValue; } _repositoryWrapper.Transaction.Update(transactions[i]); _repositoryWrapper.Save(); } } } void SetTransactionsForAccount(decimal? balance, Guid accountId, Guid businessId) { var operations = GetAllConfirmedOperations(accountId, businessId).OrderBy(x => x.DocDate).ToList(); var transactionsHashSet = GetTransactionsByAccountId(accountId, businessId).Select(x => x.BankOperationId).ToHashSet(); Transaction transaction = new Transaction(); var currentBalance = GetTransactionsByAccountId(accountId, businessId).Sum(x => (x.IncomeAmount - x.OutcomeAmount)); for (int i = 0; i < operations.Count; i++) { if (!transactionsHashSet.Contains(operations[i].Id)) { currentBalance = currentBalance + operations[i].IncomeAmount!.Value - operations[i].OutcomeAmount!.Value; transaction.Id = Guid.NewGuid(); transaction.IncomeAmount = operations[i].IncomeAmount; transaction.OutcomeAmount = operations[i].OutcomeAmount; transaction.BankOperationId = operations[i].Id; transaction.IsChanged = false; transaction.ModifiedDate = operations[i].DocDate; transaction.BusinessId = businessId; transaction.BankAccountId = accountId; transaction.BalanceAmount = currentBalance??0; _repositoryWrapper.Transaction.Create(transaction); _repositoryWrapper.Save(); } } _logger.LogInformation($"{operations.Count} count records was written"); } }