Coverage Summary for Class: RecalculateAccountBalanceUseCase (com.georgeci.moneysurfer.domain.usecase)

Class Method, % Branch, % Line, % Instruction, %
RecalculateAccountBalanceUseCase 100% (2/2) 100% (4/4) 100% (11/11) 100% (86/86)
RecalculateAccountBalanceUseCase$invoke$1
Total 100% (2/2) 100% (4/4) 100% (11/11) 100% (86/86)


 package com.georgeci.moneysurfer.domain.usecase
 
 import com.georgeci.moneysurfer.domain.model.balanceImpact
 import com.georgeci.moneysurfer.domain.primitives.AccountId
 import com.georgeci.moneysurfer.domain.primitives.Money
 import com.georgeci.moneysurfer.domain.repositories.AccountRepository
 import com.georgeci.moneysurfer.domain.repositories.TransactionRepository
 import kotlinx.coroutines.flow.first
 import org.koin.core.annotation.Single
 
 /**
  * Repair: recompute `Account.balance` from authoritative transaction history. Used after
  * migration, manual repair, or when a divergence detector fires.
  *
  * Should only run when the outbox is empty for the workspace, otherwise a parallel
  * `applyDelta` race produces inconsistent state. The caller (sync coordinator / repair UI)
  * is responsible for that gate; this use case is intentionally simple.
  */
 @Single
 class RecalculateAccountBalanceUseCase(
     private val transactionRepository: TransactionRepository,
     private val accountRepository: AccountRepository,
 ) {
 
     suspend operator fun invoke(accountId: AccountId): Money {
         val all = transactionRepository.getByAccountId(accountId).first()
         var sumMinor = 0L
         for (tx in all) {
             val impact = tx.balanceImpact()[accountId] ?: continue
             sumMinor += impact.minor
         }
         val balance = Money.fromMinor(sumMinor)
         accountRepository.setBalance(accountId, balance)
         return balance
     }
 }