diff --git a/app/src/main/java/dev/achmad/ledgerr/di/DomainModule.kt b/app/src/main/java/dev/achmad/ledgerr/di/DomainModule.kt index 756a20a..7166688 100644 --- a/app/src/main/java/dev/achmad/ledgerr/di/DomainModule.kt +++ b/app/src/main/java/dev/achmad/ledgerr/di/DomainModule.kt @@ -10,6 +10,10 @@ import dev.achmad.ledgerr.domain.expense.interactor.GetExpenses import dev.achmad.ledgerr.domain.expense.interactor.InsertExpenses import dev.achmad.ledgerr.domain.expense.interactor.ReassignExpenseCategory import dev.achmad.ledgerr.domain.expense.interactor.UpsertExpense +import dev.achmad.ledgerr.domain.recurring.interactor.DeleteRecurringExpense +import dev.achmad.ledgerr.domain.recurring.interactor.GetRecurringExpenses +import dev.achmad.ledgerr.domain.recurring.interactor.ProcessDueRecurringExpenses +import dev.achmad.ledgerr.domain.recurring.interactor.UpsertRecurringExpense import org.koin.dsl.module val domainModule = module { @@ -24,4 +28,9 @@ val domainModule = module { factory { DeleteExpense(get()) } factory { ReassignExpenseCategory(get()) } factory { GetExpenseSummary(get(), get()) } + + factory { GetRecurringExpenses(get()) } + factory { UpsertRecurringExpense(get()) } + factory { DeleteRecurringExpense(get()) } + factory { ProcessDueRecurringExpenses(get()) } } diff --git a/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/DeleteRecurringExpense.kt b/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/DeleteRecurringExpense.kt new file mode 100644 index 0000000..aaaf91a --- /dev/null +++ b/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/DeleteRecurringExpense.kt @@ -0,0 +1,11 @@ +package dev.achmad.ledgerr.domain.recurring.interactor + +import dev.achmad.ledgerr.data.local.dao.RecurringExpenseDao + +class DeleteRecurringExpense( + private val dao: RecurringExpenseDao, +) { + suspend fun await(id: Long) { + dao.deleteById(id) + } +} diff --git a/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/GetRecurringExpenses.kt b/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/GetRecurringExpenses.kt new file mode 100644 index 0000000..418038b --- /dev/null +++ b/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/GetRecurringExpenses.kt @@ -0,0 +1,25 @@ +package dev.achmad.ledgerr.domain.recurring.interactor + +import dev.achmad.ledgerr.data.local.dao.RecurringExpenseDao +import dev.achmad.ledgerr.data.local.mapper.toModel +import dev.achmad.ledgerr.domain.recurring.model.RecurringExpense +import dev.achmad.ledgerr.domain.recurring.model.RecurringExpenseWithCategory +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class GetRecurringExpenses( + private val recurringDao: RecurringExpenseDao, +) { + fun subscribeAll(): Flow> = + recurringDao.subscribeAll().map { rows -> + rows.map { row -> + RecurringExpenseWithCategory( + recurring = row.recurring.toModel(), + category = row.category.toModel(), + ) + } + } + + suspend fun awaitOne(id: Long): RecurringExpense? = + recurringDao.getById(id)?.toModel() +} diff --git a/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/ProcessDueRecurringExpenses.kt b/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/ProcessDueRecurringExpenses.kt new file mode 100644 index 0000000..4a05ca2 --- /dev/null +++ b/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/ProcessDueRecurringExpenses.kt @@ -0,0 +1,38 @@ +package dev.achmad.ledgerr.domain.recurring.interactor + +import androidx.room.withTransaction +import dev.achmad.ledgerr.data.local.AppDatabase +import dev.achmad.ledgerr.data.local.mapper.toEntity +import dev.achmad.ledgerr.data.local.mapper.toModel +import dev.achmad.ledgerr.domain.expense.model.Expense +import java.time.LocalDate + +class ProcessDueRecurringExpenses( + private val database: AppDatabase, +) { + suspend fun await(today: LocalDate = LocalDate.now()): List = + database.withTransaction { + val recurringDao = database.recurringExpenseDao() + val expenseDao = database.expenseDao() + val dueTemplates = recurringDao.getDue(today.toEpochDay()) + if (dueTemplates.isEmpty()) return@withTransaction emptyList() + val created = mutableListOf() + for (templateEntity in dueTemplates) { + val template = templateEntity.toModel() + val expense = Expense( + amount = template.amount, + categoryId = template.categoryId, + date = template.nextDueDate, + note = template.note, + recurringExpenseId = template.id, + ) + val newId = expenseDao.insert(expense.toEntity()) + created += expense.copy(id = newId) + val advanced = template.copy( + nextDueDate = template.interval.advance(template.nextDueDate), + ) + recurringDao.update(advanced.toEntity()) + } + created + } +} diff --git a/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/UpsertRecurringExpense.kt b/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/UpsertRecurringExpense.kt new file mode 100644 index 0000000..6c84104 --- /dev/null +++ b/app/src/main/java/dev/achmad/ledgerr/domain/recurring/interactor/UpsertRecurringExpense.kt @@ -0,0 +1,19 @@ +package dev.achmad.ledgerr.domain.recurring.interactor + +import dev.achmad.ledgerr.data.local.dao.RecurringExpenseDao +import dev.achmad.ledgerr.data.local.mapper.toEntity +import dev.achmad.ledgerr.domain.recurring.model.RecurringExpense + +class UpsertRecurringExpense( + private val dao: RecurringExpenseDao, +) { + suspend fun await(recurring: RecurringExpense): Long { + val entity = recurring.toEntity() + return if (recurring.id == 0L) { + dao.insert(entity) + } else { + dao.update(entity) + recurring.id + } + } +}