diff --git a/src/main/kotlin/space/luminic/finance/repos/TransactionRepo.kt b/src/main/kotlin/space/luminic/finance/repos/TransactionRepo.kt index 813584a..67156ad 100644 --- a/src/main/kotlin/space/luminic/finance/repos/TransactionRepo.kt +++ b/src/main/kotlin/space/luminic/finance/repos/TransactionRepo.kt @@ -16,4 +16,6 @@ interface TransactionRepo { fun setCategory(txId:Int, categoryId: Int) + fun findByDateAndKind(date: java.time.LocalDate, kind: Transaction.TransactionKind): List + } \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/repos/TransactionRepoImpl.kt b/src/main/kotlin/space/luminic/finance/repos/TransactionRepoImpl.kt index 5754065..218b595 100644 --- a/src/main/kotlin/space/luminic/finance/repos/TransactionRepoImpl.kt +++ b/src/main/kotlin/space/luminic/finance/repos/TransactionRepoImpl.kt @@ -30,6 +30,7 @@ class TransactionRepoImpl( ) else null Transaction( id = rs.getInt("t_id"), + space = Space(id = rs.getInt("t_space_id"), name = "", owner = User(0, "", "")), parent = parent, type = Transaction.TransactionType.valueOf(rs.getString("t_type")), kind = Transaction.TransactionKind.valueOf(rs.getString("t_kind")), @@ -391,4 +392,44 @@ class TransactionRepoImpl( ) jdbcTemplate.update(sql, params) } + + override fun findByDateAndKind(date: java.time.LocalDate, kind: Transaction.TransactionKind): List { + val sql = """SELECT + t.id AS t_id, + t.parent_id AS t_parent_id, + t.space_id AS t_space_id, + t.type AS t_type, + t.kind AS t_kind, + t.comment AS t_comment, + t.amount AS t_amount, + t.fees AS t_fees, + t.date AS t_date, + t.is_deleted AS t_is_deleted, + t.is_done AS t_is_done, + t.created_at AS t_created_at, + t.updated_at AS t_updated_at, + t.tg_chat_id AS tg_chat_id, + t.tg_message_id AS tg_message_id, + c.id AS c_id, + c.type AS c_type, + c.name AS c_name, + c.description AS c_description, + c.icon AS c_icon, + c.is_deleted AS c_is_deleted, + c.created_at AS c_created_at, + c.updated_at AS c_updated_at, + u.id AS u_id, + u.username AS u_username, + u.first_name AS u_first_name, + t.recurrent_id AS t_recurrent_id + FROM finance.transactions t + LEFT JOIN finance.categories c ON t.category_id = c.id + JOIN finance.users u ON u.id = t.created_by_id + WHERE t.date = :date and t.kind = :kind and t.is_deleted = false""".trimMargin() + val params = mapOf( + "date" to date, + "kind" to kind.name, + ) + return jdbcTemplate.query(sql, params, transactionRowMapper()) + } } \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/services/NotificationService.kt b/src/main/kotlin/space/luminic/finance/services/NotificationService.kt index 5b2e1c8..2f38010 100644 --- a/src/main/kotlin/space/luminic/finance/services/NotificationService.kt +++ b/src/main/kotlin/space/luminic/finance/services/NotificationService.kt @@ -7,6 +7,7 @@ import space.luminic.finance.models.Transaction interface NotificationService { fun sendDailyReminder() + fun sendPlannedTransactionsReminder() fun sendTXNotification(action: TxActionType, space: Space, userId: Int, tx: Transaction, tx2: Transaction? = null) fun sendTextMessage(chatId: Long, message: String, replyMarkup: ReplyMarkup? = null) fun sendMediaGroup(chatId: Long, group: MediaGroup) diff --git a/src/main/kotlin/space/luminic/finance/services/NotificationServiceImpl.kt b/src/main/kotlin/space/luminic/finance/services/NotificationServiceImpl.kt index f3e3955..ceecde5 100644 --- a/src/main/kotlin/space/luminic/finance/services/NotificationServiceImpl.kt +++ b/src/main/kotlin/space/luminic/finance/services/NotificationServiceImpl.kt @@ -12,10 +12,18 @@ import org.springframework.stereotype.Service import org.springframework.context.annotation.Lazy import space.luminic.finance.models.Space import space.luminic.finance.models.Transaction +import space.luminic.finance.repos.SpaceRepo +import space.luminic.finance.repos.TransactionRepo +import java.time.LocalDate import java.time.format.DateTimeFormatter @Service -class NotificationServiceImpl(private val userService: UserService, private val bot: Bot) : NotificationService { +class NotificationServiceImpl( + private val userService: UserService, + private val bot: Bot, + @Lazy private val transactionRepo: TransactionRepo, + @Lazy private val spaceRepo: SpaceRepo +) : NotificationService { private val logger = LoggerFactory.getLogger(this.javaClass) @@ -59,6 +67,31 @@ class NotificationServiceImpl(private val userService: UserService, private val } } + override fun sendPlannedTransactionsReminder() { + val today = LocalDate.now() + val plannedTxs = transactionRepo.findByDateAndKind(today, Transaction.TransactionKind.PLANNING) + + if (plannedTxs.isEmpty()) { + return + } + + // Группируем по spaceId. У нас нет Space объекта целиком в ответе findByDateAndKind, + // но есть t_space_id в маппере (хотя в модели Transaction.space может быть null). + // В RepoImpl маппер заполняет space.id + val groupedBySpace = plannedTxs.filter { it.space?.id != null }.groupBy { it.space!!.id!! } + + for ((spaceId, txs) in groupedBySpace) { + // Чтобы получить владельца, нужно загрузить Space + // Используем системного пользователя или просто id для получения + val space = spaceRepo.findSpaceById(spaceId, txs.first().createdBy?.id ?: 0) + if (space?.owner?.tgId != null) { + val txList = txs.joinToString("\n") { "- ${it.comment}: ${it.amount}" } + val text = "📅 На сегодня запланированы транзакции:\n\n$txList" + sendTextMessage(space.owner.tgId!!, text, createWebAppButton(spaceId)) + } + } + } + override fun sendTXNotification( action: TxActionType, space: Space, diff --git a/src/main/kotlin/space/luminic/finance/services/Scheduler.kt b/src/main/kotlin/space/luminic/finance/services/Scheduler.kt index 2987c7e..0a31a87 100644 --- a/src/main/kotlin/space/luminic/finance/services/Scheduler.kt +++ b/src/main/kotlin/space/luminic/finance/services/Scheduler.kt @@ -27,6 +27,12 @@ class Scheduler( notificationService.sendDailyReminder() } + @Scheduled(cron = "0 0 9 * * *") + fun sendPlannedTransactionsReminders() { + log.info("Sending planned transactions reminders") + notificationService.sendPlannedTransactionsReminder() + } + // @Scheduled(cron = "0 0 */3 * * *") @Scheduled(fixedRate = 3, timeUnit =TimeUnit.HOURS) fun analyzePeriodScheduled() {