From 2452e5935fc4f9de0ba230a48b20cdc0f4797be9 Mon Sep 17 00:00:00 2001 From: xds Date: Thu, 20 Nov 2025 12:37:06 +0300 Subject: [PATCH] + targets --- .../luminic/finance/api/GoalController.kt | 19 --- .../luminic/finance/api/TargetController.kt | 19 +++ .../finance/dtos/{GoalDTO.kt => TargetDTO.kt} | 19 +-- .../{GoalMapper.kt => TargetMapper.kt} | 20 ++- .../finance/models/{Goal.kt => Target.kt} | 21 +-- .../space/luminic/finance/repos/GoalRepo.kt | 20 --- .../space/luminic/finance/repos/TargetRepo.kt | 20 +++ .../{GoalRepoImpl.kt => TargetRepoImpl.kt} | 116 +++++++-------- .../finance/repos/TransactionRepoImpl.kt | 5 + .../luminic/finance/services/GoalService.kt | 22 --- .../finance/services/GoalServiceImpl.kt | 140 ------------------ .../services/RecurrentOperationServiceImpl.kt | 1 + .../luminic/finance/services/TargetService.kt | 22 +++ .../finance/services/TargetServiceImpl.kt | 140 ++++++++++++++++++ .../finance/services/gpt/CategorizeService.kt | 6 +- .../finance/services/telegram/BotService.kt | 2 +- src/main/resources/db/migration/V31__.sql | 59 ++++++++ 17 files changed, 361 insertions(+), 290 deletions(-) delete mode 100644 src/main/kotlin/space/luminic/finance/api/GoalController.kt create mode 100644 src/main/kotlin/space/luminic/finance/api/TargetController.kt rename src/main/kotlin/space/luminic/finance/dtos/{GoalDTO.kt => TargetDTO.kt} (67%) rename src/main/kotlin/space/luminic/finance/mappers/{GoalMapper.kt => TargetMapper.kt} (54%) rename src/main/kotlin/space/luminic/finance/models/{Goal.kt => Target.kt} (71%) delete mode 100644 src/main/kotlin/space/luminic/finance/repos/GoalRepo.kt create mode 100644 src/main/kotlin/space/luminic/finance/repos/TargetRepo.kt rename src/main/kotlin/space/luminic/finance/repos/{GoalRepoImpl.kt => TargetRepoImpl.kt} (68%) delete mode 100644 src/main/kotlin/space/luminic/finance/services/GoalService.kt delete mode 100644 src/main/kotlin/space/luminic/finance/services/GoalServiceImpl.kt create mode 100644 src/main/kotlin/space/luminic/finance/services/TargetService.kt create mode 100644 src/main/kotlin/space/luminic/finance/services/TargetServiceImpl.kt create mode 100644 src/main/resources/db/migration/V31__.sql diff --git a/src/main/kotlin/space/luminic/finance/api/GoalController.kt b/src/main/kotlin/space/luminic/finance/api/GoalController.kt deleted file mode 100644 index bd99f1e..0000000 --- a/src/main/kotlin/space/luminic/finance/api/GoalController.kt +++ /dev/null @@ -1,19 +0,0 @@ -package space.luminic.finance.api - -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController -import space.luminic.finance.dtos.GoalDTO -import space.luminic.finance.mappers.GoalMapper.toDto -import space.luminic.finance.services.GoalService - -@RestController -@RequestMapping("/spaces/{spaceId}/goals") -class GoalController(private val goalService: GoalService) { - - @GetMapping - fun findAll(@PathVariable spaceId: Int): List { - return goalService.findAllBySpaceId(spaceId).map { it.toDto() } - } -} \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/api/TargetController.kt b/src/main/kotlin/space/luminic/finance/api/TargetController.kt new file mode 100644 index 0000000..b790419 --- /dev/null +++ b/src/main/kotlin/space/luminic/finance/api/TargetController.kt @@ -0,0 +1,19 @@ +package space.luminic.finance.api + +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import space.luminic.finance.dtos.TargetDTO +import space.luminic.finance.mappers.TargetMapper.toDto +import space.luminic.finance.services.TargetService + +@RestController +@RequestMapping("/spaces/{spaceId}/targets") +class TargetController(private val targetService: TargetService) { + + @GetMapping + fun findAll(@PathVariable spaceId: Int): List { + return targetService.findAllBySpaceId(spaceId).map { it.toDto() } + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/dtos/GoalDTO.kt b/src/main/kotlin/space/luminic/finance/dtos/TargetDTO.kt similarity index 67% rename from src/main/kotlin/space/luminic/finance/dtos/GoalDTO.kt rename to src/main/kotlin/space/luminic/finance/dtos/TargetDTO.kt index 4f74700..605dc7b 100644 --- a/src/main/kotlin/space/luminic/finance/dtos/GoalDTO.kt +++ b/src/main/kotlin/space/luminic/finance/dtos/TargetDTO.kt @@ -1,36 +1,37 @@ package space.luminic.finance.dtos -import space.luminic.finance.models.Goal -import space.luminic.finance.models.Goal.GoalType +import space.luminic.finance.models.Target +import space.luminic.finance.models.Target.TargetType import space.luminic.finance.models.Transaction import java.math.BigDecimal import java.time.Instant import java.time.LocalDate -data class GoalDTO( +data class TargetDTO( val id: Int, - val type: GoalType, + val type: TargetType, val name: String, val description: String? = null, val amount: BigDecimal, + val currentAmount: BigDecimal, val date: LocalDate, - val components: List, + val components: List, val transactions: List, val createdBy: UserDTO, val createdAt: Instant, val updatedBy: UserDTO? = null, val updatedAt: Instant? = null, ) { - data class CreateGoalDTO( - val type: GoalType, + data class CreateTargetDTO( + val type: TargetType, val name: String, val description: String?, val amount: BigDecimal, val date: LocalDate ) - data class UpdateGoalDTO( - val type: GoalType, + data class UpdateTargetDTO( + val type: TargetType, val name: String, val description: String?, val amount: BigDecimal, diff --git a/src/main/kotlin/space/luminic/finance/mappers/GoalMapper.kt b/src/main/kotlin/space/luminic/finance/mappers/TargetMapper.kt similarity index 54% rename from src/main/kotlin/space/luminic/finance/mappers/GoalMapper.kt rename to src/main/kotlin/space/luminic/finance/mappers/TargetMapper.kt index bb9cc22..07f28f9 100644 --- a/src/main/kotlin/space/luminic/finance/mappers/GoalMapper.kt +++ b/src/main/kotlin/space/luminic/finance/mappers/TargetMapper.kt @@ -1,22 +1,26 @@ package space.luminic.finance.mappers -import space.luminic.finance.dtos.GoalDTO +import space.luminic.finance.dtos.TargetDTO import space.luminic.finance.mappers.UserMapper.toDto -import space.luminic.finance.models.Goal +import space.luminic.finance.models.Target -object GoalMapper { +object TargetMapper { - fun Goal.toDto() = GoalDTO( - id = this.id ?: throw IllegalArgumentException("Goal id is not provided"), + fun Target.toDto() = TargetDTO( + id = this.id ?: throw IllegalArgumentException("Target id is not provided"), type = this.type, name = this.name, + description = this.description, amount = this.amount, + currentAmount = this.currentAmount, date = this.untilDate, components = this.components, transactions = this.transactions, createdBy = (this.createdBy ?: throw IllegalArgumentException("created by not provided")).toDto(), createdAt = this.createdAt ?: throw IllegalArgumentException("created at not provided"), - updatedBy = this.updatedBy?.toDto() , - updatedAt = this.updatedAt - ) + updatedBy = this.updatedBy?.toDto(), + updatedAt = this.updatedAt, + + + ) } \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/models/Goal.kt b/src/main/kotlin/space/luminic/finance/models/Target.kt similarity index 71% rename from src/main/kotlin/space/luminic/finance/models/Goal.kt rename to src/main/kotlin/space/luminic/finance/models/Target.kt index d9aca48..0f92f89 100644 --- a/src/main/kotlin/space/luminic/finance/models/Goal.kt +++ b/src/main/kotlin/space/luminic/finance/models/Target.kt @@ -8,30 +8,30 @@ import java.math.BigDecimal import java.time.Instant import java.time.LocalDate -data class Goal( +data class Target( var id: Int? = null, val space: Space? = null, - val type: GoalType, + val type: TargetType, val name: String, val description: String? = null, val amount: BigDecimal, - val components: List = emptyList(), + val components: List = emptyList(), val transactions: List = emptyList(), val untilDate: LocalDate, - @CreatedBy var createdBy: User? = null, + var createdBy: User? = null, - @CreatedDate var createdAt: Instant? = null, - @LastModifiedBy var updatedBy: User? = null, + var createdAt: Instant? = null, + var updatedBy: User? = null, - @LastModifiedDate var updatedAt: Instant? = null, - ) { + var updatedAt: Instant? = null, +) { var currentAmount: BigDecimal = { this.transactions.sumOf { it.amount } } as BigDecimal - data class GoalComponent( + data class TargetComponent( val id: Int? = null, val name: String, val amount: BigDecimal, @@ -39,8 +39,9 @@ data class Goal( val date: LocalDate = LocalDate.now(), ) - enum class GoalType(val displayName: String, val icon: String) { + enum class TargetType(val displayName: String, val icon: String) { AUTO("Авто", "🏎️"), + LEISURE("Досуг", "💃"), VACATION("Отпуск", "🏖️"), GOODS("Покупка", "🛍️"), OTHER("Прочее", "💸") diff --git a/src/main/kotlin/space/luminic/finance/repos/GoalRepo.kt b/src/main/kotlin/space/luminic/finance/repos/GoalRepo.kt deleted file mode 100644 index d5014ae..0000000 --- a/src/main/kotlin/space/luminic/finance/repos/GoalRepo.kt +++ /dev/null @@ -1,20 +0,0 @@ -package space.luminic.finance.repos - -import space.luminic.finance.models.Goal - -interface GoalRepo { - - fun findAllBySpaceId(spaceId: Int) : List - fun findBySpaceIdAndId(spaceId: Int, id: Int) : Goal? - fun create(goal: Goal, createdById: Int): Int - fun update(goal: Goal, updatedById: Int) - fun delete(spaceId: Int, id: Int) - fun getComponents(spaceId: Int, goalId: Int): List - fun getComponent(spaceId: Int, goalId: Int, id: Int): Goal.GoalComponent? - fun createComponent(goalId: Int, component: Goal.GoalComponent, createdById: Int): Int - fun updateComponent(goalId: Int, componentId: Int, component: Goal.GoalComponent, updatedById: Int) - fun deleteComponent(goalId: Int, componentId: Int) - - fun assignTransaction(goalId: Int, transactionId: Int) - fun refuseTransaction(goalId: Int, transactionId: Int) -} \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/repos/TargetRepo.kt b/src/main/kotlin/space/luminic/finance/repos/TargetRepo.kt new file mode 100644 index 0000000..a53a750 --- /dev/null +++ b/src/main/kotlin/space/luminic/finance/repos/TargetRepo.kt @@ -0,0 +1,20 @@ +package space.luminic.finance.repos + +import space.luminic.finance.models.Target + +interface TargetRepo { + + fun findAllBySpaceId(spaceId: Int) : List + fun findBySpaceIdAndId(spaceId: Int, id: Int) : Target? + fun create(target: Target, createdById: Int): Int + fun update(target: Target, updatedById: Int) + fun delete(spaceId: Int, id: Int) + fun getComponents(spaceId: Int, targetId: Int): List + fun getComponent(spaceId: Int, targetId: Int, id: Int): Target.TargetComponent? + fun createComponent(targetId: Int, component: Target.TargetComponent, createdById: Int): Int + fun updateComponent(targetId: Int, componentId: Int, component: Target.TargetComponent, updatedById: Int) + fun deleteComponent(targetId: Int, componentId: Int) + + fun assignTransaction(targetId: Int, transactionId: Int) + fun refuseTransaction(targetId: Int, transactionId: Int) +} \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/repos/GoalRepoImpl.kt b/src/main/kotlin/space/luminic/finance/repos/TargetRepoImpl.kt similarity index 68% rename from src/main/kotlin/space/luminic/finance/repos/GoalRepoImpl.kt rename to src/main/kotlin/space/luminic/finance/repos/TargetRepoImpl.kt index 1d8b50b..c6d2a8b 100644 --- a/src/main/kotlin/space/luminic/finance/repos/GoalRepoImpl.kt +++ b/src/main/kotlin/space/luminic/finance/repos/TargetRepoImpl.kt @@ -3,17 +3,17 @@ package space.luminic.finance.repos import org.springframework.jdbc.core.RowMapper import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate import org.springframework.stereotype.Repository -import space.luminic.finance.models.Goal +import space.luminic.finance.models.Target import space.luminic.finance.models.User @Repository -class GoalRepoImpl( +class TargetRepoImpl( private val jdbcTemplate: NamedParameterJdbcTemplate -) : GoalRepo { - private val goalRowMapper = RowMapper { rs, _ -> - Goal( +) : TargetRepo { + private val targetRowMapper = RowMapper { rs, _ -> + Target( id = rs.getInt("g_id"), - type = Goal.GoalType.valueOf(rs.getString("g_type")), + type = Target.TargetType.valueOf(rs.getString("g_type")), name = rs.getString("g_name"), description = rs.getString("g_description"), amount = rs.getBigDecimal("g_amount"), @@ -30,7 +30,7 @@ class GoalRepoImpl( } private val componentRowMapper = RowMapper { rs, _ -> - Goal.GoalComponent( + Target.TargetComponent( id = rs.getInt("gc_id"), name = rs.getString("gc_name"), amount = rs.getBigDecimal("gc_amount"), @@ -39,7 +39,7 @@ class GoalRepoImpl( ) } - override fun findAllBySpaceId(spaceId: Int): List { + override fun findAllBySpaceId(spaceId: Int): List { val sql = """ select g.id as g_id, @@ -51,7 +51,7 @@ class GoalRepoImpl( created_by.username as created_by_username, created_by.first_name as created_by_first_name, g.created_at as g_created_at - from finance.goals g + from finance.targets g join finance.users created_by on g.created_by_id = created_by.id where g.space_id = :spaceId @@ -60,10 +60,10 @@ class GoalRepoImpl( val params = mapOf( "space_id" to spaceId, ) - return jdbcTemplate.query(sql, params, goalRowMapper) + return jdbcTemplate.query(sql, params, targetRowMapper) } - override fun findBySpaceIdAndId(spaceId: Int, id: Int): Goal? { + override fun findBySpaceIdAndId(spaceId: Int, id: Int): Target? { val sql = """ select g.id as g_id, @@ -75,7 +75,7 @@ class GoalRepoImpl( created_by.username as created_by_username, created_by.first_name as created_by_first_name, g.created_at as g_created_at - from finance.goals g + from finance.targets g join finance.users created_by on g.created_by_id = created_by.id where g.space_id = :spaceId and g.id = :id @@ -85,12 +85,12 @@ class GoalRepoImpl( "space_id" to spaceId, "id" to id, ) - return jdbcTemplate.query(sql, params, goalRowMapper).firstOrNull() + return jdbcTemplate.query(sql, params, targetRowMapper).firstOrNull() } - override fun create(goal: Goal, createdById: Int): Int { + override fun create(target: Target, createdById: Int): Int { val sql = """ - insert into finance.goals( + insert into finance.targets( type, name, description, @@ -108,19 +108,19 @@ class GoalRepoImpl( returning id """.trimIndent() val params = mapOf( - "type" to goal.type, - "name" to goal.name, - "description" to goal.description, - "amount" to goal.amount, - "until_date" to goal.untilDate, + "type" to target.type, + "name" to target.name, + "description" to target.description, + "amount" to target.amount, + "until_date" to target.untilDate, "created_by_id" to createdById ) return jdbcTemplate.queryForObject(sql, params, Int::class.java)!! } - override fun update(goal: Goal, updatedById: Int) { + override fun update(target: Target, updatedById: Int) { val sql = """ - update finance.goals set + update finance.targets set type = :type, name = :name, description = :description, @@ -131,12 +131,12 @@ class GoalRepoImpl( where id = :id """.trimIndent() val params = mapOf( - "id" to goal.id, - "type" to goal.type.name, - "name" to goal.name, - "description" to goal.description, - "amount" to goal.amount, - "until_date" to goal.untilDate, + "id" to target.id, + "type" to target.type.name, + "name" to target.name, + "description" to target.description, + "amount" to target.amount, + "until_date" to target.untilDate, "updated_by_id" to updatedById ) @@ -145,7 +145,7 @@ class GoalRepoImpl( override fun delete(spaceId: Int, id: Int) { val sql = """ - delete from finance.goals where id = :id + delete from finance.targets where id = :id """.trimIndent() val params = mapOf( @@ -156,8 +156,8 @@ class GoalRepoImpl( override fun getComponents( spaceId: Int, - goalId: Int - ): List { + targetId: Int + ): List { val sql = """ select gc.id as gc_id, @@ -165,11 +165,11 @@ class GoalRepoImpl( gc.amount as gc_amount, gc.is_done as gc_is_done, gc.date as gc_date - from finance.goals_components gc - where gc.goal_id = :goal_id + from finance.targets_components gc + where gc.target_id = :target_id """.trimIndent() val params = mapOf( - "goal_id" to goalId + "target_id" to targetId ) return jdbcTemplate.query(sql, params, componentRowMapper) @@ -177,9 +177,9 @@ class GoalRepoImpl( override fun getComponent( spaceId: Int, - goalId: Int, + targetId: Int, id: Int - ): Goal.GoalComponent? { + ): Target.TargetComponent? { val sql = """ select gc.id as gc_id, @@ -187,27 +187,27 @@ class GoalRepoImpl( gc.amount as gc_amount, gc.is_done as gc_is_done, gc.date as gc_date - from finance.goals_components gc - where gc.goal_id = :goal_id and gc.id = :id + from finance.targets_components gc + where gc.target_id = :target_id and gc.id = :id """.trimIndent() val params = mapOf( - "goal_id" to goalId, + "target_id" to targetId, "id" to id ) return jdbcTemplate.query(sql, params, componentRowMapper).firstOrNull() } - override fun createComponent(goalId: Int, component: Goal.GoalComponent, createdById: Int): Int { + override fun createComponent(targetId: Int, component: Target.TargetComponent, createdById: Int): Int { val sql = """ - insert into finance.goals_components( - goal_id, + insert into finance.targets_components( + target_id, name, amount, is_done, date, created_by_id ) values ( - :goal_id, + :target_id, :name, :amount, :is_done, @@ -216,7 +216,7 @@ class GoalRepoImpl( returning id """.trimIndent() val params = mapOf( - "goal_id" to goalId, + "target_id" to targetId, "name" to component.name, "amount" to component.amount, "is_done" to component.isDone, @@ -226,17 +226,17 @@ class GoalRepoImpl( return jdbcTemplate.queryForObject(sql, params, Int::class.java)!! } - override fun updateComponent(goalId: Int, componentId: Int, component: Goal.GoalComponent, updatedById: Int) { + override fun updateComponent(targetId: Int, componentId: Int, component: Target.TargetComponent, updatedById: Int) { val sql = """ - update finance.goals_components set + update finance.targets_components set name = :name, amount = :amount, is_done = :is_done, updated_by_id = :updated_by_id - where goal_id = :goalId and id = :componentId + where target_id = :targetId and id = :componentId """.trimIndent() val params = mapOf( - "goalId" to goalId, + "targetId" to targetId, "componentId" to componentId, "name" to component.name, "amount" to component.amount, @@ -247,35 +247,35 @@ class GoalRepoImpl( jdbcTemplate.update(sql, params) } - override fun deleteComponent(goalId: Int, componentId: Int) { + override fun deleteComponent(targetId: Int, componentId: Int) { val sql = """ - delete from finance.goals_components where goal_id = :goalId and id = :componentId + delete from finance.targets_components where target_id = :targetId and id = :componentId """.trimIndent() val params = mapOf( - "goalId" to goalId, + "targetId" to targetId, "componentId" to componentId ) jdbcTemplate.update(sql, params) } - override fun assignTransaction(goalId: Int, transactionId: Int) { + override fun assignTransaction(targetId: Int, transactionId: Int) { val sql = """ - insert into finance.goals_transactions(goal_id, transactions_id) - values (:goal_id, :transaction_id) + insert into finance.targets_transactions(target_id, transactions_id) + values (:targetId, :transaction_id) """.trimIndent() val params = mapOf( - "goal_id" to goalId, + "targetId" to targetId, "transaction_id" to transactionId ) jdbcTemplate.update(sql, params) } - override fun refuseTransaction(goalId: Int, transactionId: Int) { + override fun refuseTransaction(targetId: Int, transactionId: Int) { val sql = """ - delete from finance.goals_transactions where goal_id = :goalId and transactions_id = :transactionId + delete from finance.targets_transactions where target_id = :goalId and transactions_id = :transactionId """.trimIndent() val params = mapOf( - "goal_id" to goalId, + "target_id" to targetId, "transaction_id" to transactionId ) jdbcTemplate.update(sql, params) diff --git a/src/main/kotlin/space/luminic/finance/repos/TransactionRepoImpl.kt b/src/main/kotlin/space/luminic/finance/repos/TransactionRepoImpl.kt index 796399b..84606f0 100644 --- a/src/main/kotlin/space/luminic/finance/repos/TransactionRepoImpl.kt +++ b/src/main/kotlin/space/luminic/finance/repos/TransactionRepoImpl.kt @@ -7,6 +7,8 @@ import space.luminic.finance.models.Category import space.luminic.finance.models.Transaction import space.luminic.finance.models.User import space.luminic.finance.services.TransactionService +import java.time.LocalDate +import java.time.LocalDateTime @Repository class TransactionRepoImpl( @@ -109,6 +111,9 @@ class TransactionRepoImpl( filters.dateFrom?.let { sql += " AND t.date >= :dateFrom" params.put("dateFrom", it) + } ?: { + sql += " AND t.date >= :dateFrom" + params.put("dateFrom", LocalDate.now().minusMonths(1)) } filters.dateTo?.let { sql += " AND t.date <= :dateTo" diff --git a/src/main/kotlin/space/luminic/finance/services/GoalService.kt b/src/main/kotlin/space/luminic/finance/services/GoalService.kt deleted file mode 100644 index 1757116..0000000 --- a/src/main/kotlin/space/luminic/finance/services/GoalService.kt +++ /dev/null @@ -1,22 +0,0 @@ -package space.luminic.finance.services - -import space.luminic.finance.dtos.GoalDTO -import space.luminic.finance.models.Goal - -interface GoalService { - fun findAllBySpaceId(spaceId: Int): List - fun findBySpaceIdAndId(spaceId: Int, id: Int): Goal - fun create(spaceId: Int,goal: GoalDTO.CreateGoalDTO): Int - fun update(spaceId: Int, goalId: Int, goal: GoalDTO.UpdateGoalDTO) - fun delete(spaceId: Int, id: Int) - - fun getComponents(spaceId: Int, goalId: Int): List - fun getComponent(spaceId: Int, goalId: Int, id: Int): Goal.GoalComponent? - fun createComponent(spaceId: Int, goalId: Int, component: Goal.GoalComponent): Int - fun updateComponent(spaceId: Int, goalId: Int, component: Goal.GoalComponent) - fun deleteComponent(spaceId: Int, goalId: Int, id: Int) - - fun assignTransaction(spaceId: Int, goalId: Int, transactionId: Int) - fun refuseTransaction(spaceId: Int,goalId: Int, transactionId: Int) - -} \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/services/GoalServiceImpl.kt b/src/main/kotlin/space/luminic/finance/services/GoalServiceImpl.kt deleted file mode 100644 index 7abcb63..0000000 --- a/src/main/kotlin/space/luminic/finance/services/GoalServiceImpl.kt +++ /dev/null @@ -1,140 +0,0 @@ -package space.luminic.finance.services - -import org.springframework.stereotype.Service -import space.luminic.finance.dtos.GoalDTO -import space.luminic.finance.models.Goal -import space.luminic.finance.models.NotFoundException -import space.luminic.finance.repos.GoalRepo -import space.luminic.finance.repos.SpaceRepo -import space.luminic.finance.repos.TransactionRepo - -@Service -class GoalServiceImpl( - private val goalRepo: GoalRepo, - private val spaceRepo: SpaceRepo, - private val authService: AuthService, - private val transactionRepo: TransactionRepo -) : GoalService { - override fun findAllBySpaceId(spaceId: Int): List { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - return goalRepo.findAllBySpaceId(spaceId) - } - - override fun findBySpaceIdAndId(spaceId: Int, id: Int): Goal { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - return goalRepo.findBySpaceIdAndId(spaceId, userId) ?: throw NotFoundException("Goal $id not found") - } - - override fun create(spaceId: Int, goal: GoalDTO.CreateGoalDTO): Int { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - val creatingGoal = Goal( - type = goal.type, - name = goal.name, - amount = goal.amount, - untilDate = goal.date - ) - return goalRepo.create(creatingGoal, userId) - } - - override fun update(spaceId: Int, goalId: Int, goal: GoalDTO.UpdateGoalDTO) { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - val existingGoal = - goalRepo.findBySpaceIdAndId(spaceId, goalId) ?: throw NotFoundException("Goal $goalId not found") - val updatedGoal = existingGoal.copy( - type = goal.type, - name = goal.name, - description = goal.description, - amount = goal.amount, - untilDate = goal.date - ) - goalRepo.update(updatedGoal, userId) - } - - override fun delete(spaceId: Int, id: Int) { - goalRepo.delete(spaceId, id) - } - - override fun getComponents( - spaceId: Int, - goalId: Int - ): List { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - goalRepo.findBySpaceIdAndId(spaceId, goalId) ?: throw NotFoundException("Goal $goalId not found") - return goalRepo.getComponents(spaceId, goalId) - } - - override fun getComponent( - spaceId: Int, - goalId: Int, - id: Int - ): Goal.GoalComponent? { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - goalRepo.findBySpaceIdAndId(spaceId, goalId) ?: throw NotFoundException("Goal $goalId not found") - return goalRepo.getComponent(spaceId, goalId, id) - } - - override fun createComponent( - spaceId: Int, - goalId: Int, - component: Goal.GoalComponent - ): Int { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - goalRepo.findBySpaceIdAndId(spaceId, goalId) ?: throw NotFoundException("Goal $goalId not found") - return goalRepo.createComponent(goalId, component, userId) - } - - override fun updateComponent( - spaceId: Int, - goalId: Int, - component: Goal.GoalComponent - ) { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - goalRepo.findBySpaceIdAndId(spaceId, goalId) ?: throw NotFoundException("Goal $goalId not found") - val existingComponent = goalRepo.getComponent(spaceId, goalId, component.id!!) - ?: throw NotFoundException("Component $goalId not found") - val updatedComponent = existingComponent.copy( - name = component.name, - amount = component.amount, - isDone = component.isDone, - date = component.date - ) - goalRepo.updateComponent(goalId, updatedComponent.id!!, updatedComponent, userId) - } - - override fun deleteComponent(spaceId: Int, goalId: Int, id: Int) { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - goalRepo.findBySpaceIdAndId(spaceId, goalId) ?: throw NotFoundException("Goal $goalId not found") - goalRepo.getComponent(spaceId, goalId, id) ?: throw NotFoundException("Component $goalId not found") - goalRepo.deleteComponent(goalId, id) - } - - override fun assignTransaction(spaceId: Int, goalId: Int, transactionId: Int) { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - goalRepo.findBySpaceIdAndId(spaceId, goalId) ?: throw NotFoundException("Goal $goalId not found") - transactionRepo.findBySpaceIdAndId(spaceId, transactionId) ?: throw NotFoundException( - "Transaction $transactionId not found" - ) - goalRepo.assignTransaction(goalId, transactionId) - - } - - override fun refuseTransaction(spaceId: Int, goalId: Int, transactionId: Int) { - val userId = authService.getSecurityUserId() - spaceRepo.findSpaceById(spaceId, userId) - goalRepo.findBySpaceIdAndId(spaceId, goalId) ?: throw NotFoundException("Goal $goalId not found") - transactionRepo.findBySpaceIdAndId(spaceId, transactionId) ?: throw NotFoundException( - "Transaction $transactionId not found" - ) - goalRepo.refuseTransaction(goalId, transactionId) - } -} \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/services/RecurrentOperationServiceImpl.kt b/src/main/kotlin/space/luminic/finance/services/RecurrentOperationServiceImpl.kt index 75f3463..cc2ace0 100644 --- a/src/main/kotlin/space/luminic/finance/services/RecurrentOperationServiceImpl.kt +++ b/src/main/kotlin/space/luminic/finance/services/RecurrentOperationServiceImpl.kt @@ -110,6 +110,7 @@ class RecurrentOperationServiceImpl( type = if (it.category?.type == Category.CategoryType.EXPENSE) Transaction.TransactionType.EXPENSE else Transaction.TransactionType.INCOME, category = updatedOperation.category, comment = operation.name, + amount = updatedOperation.amount, date = LocalDate.of( it.date.year, it.date.monthValue, diff --git a/src/main/kotlin/space/luminic/finance/services/TargetService.kt b/src/main/kotlin/space/luminic/finance/services/TargetService.kt new file mode 100644 index 0000000..84c4de1 --- /dev/null +++ b/src/main/kotlin/space/luminic/finance/services/TargetService.kt @@ -0,0 +1,22 @@ +package space.luminic.finance.services + +import space.luminic.finance.dtos.TargetDTO +import space.luminic.finance.models.Target + +interface TargetService { + fun findAllBySpaceId(spaceId: Int): List + fun findBySpaceIdAndId(spaceId: Int, id: Int): Target + fun create(spaceId: Int,target: TargetDTO.CreateTargetDTO): Int + fun update(spaceId: Int, targetId: Int, target: TargetDTO.UpdateTargetDTO) + fun delete(spaceId: Int, id: Int) + + fun getComponents(spaceId: Int, targetId: Int): List + fun getComponent(spaceId: Int, targetId: Int, id: Int): Target.TargetComponent? + fun createComponent(spaceId: Int, targetId: Int, component: Target.TargetComponent): Int + fun updateComponent(spaceId: Int, targetId: Int, component: Target.TargetComponent) + fun deleteComponent(spaceId: Int, targetId: Int, id: Int) + + fun assignTransaction(spaceId: Int, targetId: Int, transactionId: Int) + fun refuseTransaction(spaceId: Int,targetId: Int, transactionId: Int) + +} \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/services/TargetServiceImpl.kt b/src/main/kotlin/space/luminic/finance/services/TargetServiceImpl.kt new file mode 100644 index 0000000..47ab9db --- /dev/null +++ b/src/main/kotlin/space/luminic/finance/services/TargetServiceImpl.kt @@ -0,0 +1,140 @@ +package space.luminic.finance.services + +import org.springframework.stereotype.Service +import space.luminic.finance.dtos.TargetDTO +import space.luminic.finance.models.Target +import space.luminic.finance.models.NotFoundException +import space.luminic.finance.repos.TargetRepo +import space.luminic.finance.repos.SpaceRepo +import space.luminic.finance.repos.TransactionRepo + +@Service +class TargetServiceImpl( + private val targetRepo: TargetRepo, + private val spaceRepo: SpaceRepo, + private val authService: AuthService, + private val transactionRepo: TransactionRepo +) : TargetService { + override fun findAllBySpaceId(spaceId: Int): List { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + return targetRepo.findAllBySpaceId(spaceId) + } + + override fun findBySpaceIdAndId(spaceId: Int, id: Int): Target { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + return targetRepo.findBySpaceIdAndId(spaceId, userId) ?: throw NotFoundException("Goal $id not found") + } + + override fun create(spaceId: Int, target: TargetDTO.CreateTargetDTO): Int { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + val creatingTarget = Target( + type = target.type, + name = target.name, + amount = target.amount, + untilDate = target.date + ) + return targetRepo.create(creatingTarget, userId) + } + + override fun update(spaceId: Int, targetId: Int, target: TargetDTO.UpdateTargetDTO) { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + val existingGoal = + targetRepo.findBySpaceIdAndId(spaceId, targetId) ?: throw NotFoundException("Goal $targetId not found") + val updatedGoal = existingGoal.copy( + type = target.type, + name = target.name, + description = target.description, + amount = target.amount, + untilDate = target.date + ) + targetRepo.update(updatedGoal, userId) + } + + override fun delete(spaceId: Int, id: Int) { + targetRepo.delete(spaceId, id) + } + + override fun getComponents( + spaceId: Int, + targetId: Int + ): List { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + targetRepo.findBySpaceIdAndId(spaceId, targetId) ?: throw NotFoundException("Goal $targetId not found") + return targetRepo.getComponents(spaceId, targetId) + } + + override fun getComponent( + spaceId: Int, + targetId: Int, + id: Int + ): Target.TargetComponent? { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + targetRepo.findBySpaceIdAndId(spaceId, targetId) ?: throw NotFoundException("Target $targetId not found") + return targetRepo.getComponent(spaceId, targetId, id) + } + + override fun createComponent( + spaceId: Int, + targetId: Int, + component: Target.TargetComponent + ): Int { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + targetRepo.findBySpaceIdAndId(spaceId, targetId) ?: throw NotFoundException("Target $targetId not found") + return targetRepo.createComponent(targetId, component, userId) + } + + override fun updateComponent( + spaceId: Int, + targetId: Int, + component: Target.TargetComponent + ) { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + targetRepo.findBySpaceIdAndId(spaceId, targetId) ?: throw NotFoundException("Target $targetId not found") + val existingComponent = targetRepo.getComponent(spaceId, targetId, component.id!!) + ?: throw NotFoundException("Component $targetId not found") + val updatedComponent = existingComponent.copy( + name = component.name, + amount = component.amount, + isDone = component.isDone, + date = component.date + ) + targetRepo.updateComponent(targetId, updatedComponent.id!!, updatedComponent, userId) + } + + override fun deleteComponent(spaceId: Int, targetId: Int, id: Int) { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + targetRepo.findBySpaceIdAndId(spaceId, targetId) ?: throw NotFoundException("Target $targetId not found") + targetRepo.getComponent(spaceId, targetId, id) ?: throw NotFoundException("Component $targetId not found") + targetRepo.deleteComponent(targetId, id) + } + + override fun assignTransaction(spaceId: Int, targetId: Int, transactionId: Int) { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + targetRepo.findBySpaceIdAndId(spaceId, targetId) ?: throw NotFoundException("Target $targetId not found") + transactionRepo.findBySpaceIdAndId(spaceId, transactionId) ?: throw NotFoundException( + "Transaction $transactionId not found" + ) + targetRepo.assignTransaction(targetId, transactionId) + + } + + override fun refuseTransaction(spaceId: Int, targetId: Int, transactionId: Int) { + val userId = authService.getSecurityUserId() + spaceRepo.findSpaceById(spaceId, userId) + targetRepo.findBySpaceIdAndId(spaceId, targetId) ?: throw NotFoundException("Target $targetId not found") + transactionRepo.findBySpaceIdAndId(spaceId, transactionId) ?: throw NotFoundException( + "Transaction $transactionId not found" + ) + targetRepo.refuseTransaction(targetId, transactionId) + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/luminic/finance/services/gpt/CategorizeService.kt b/src/main/kotlin/space/luminic/finance/services/gpt/CategorizeService.kt index fcd3b3b..fb4902c 100644 --- a/src/main/kotlin/space/luminic/finance/services/gpt/CategorizeService.kt +++ b/src/main/kotlin/space/luminic/finance/services/gpt/CategorizeService.kt @@ -60,7 +60,7 @@ class CategorizeService( listOf( InlineKeyboardButton.WebApp( "Открыть в WebApp", - WebAppInfo("https://app.luminic.space/transactions/${tx.id}/edit") + WebAppInfo("https://app.luminic.space/transactions/${tx.id}/edit?mode=from_bot") ) ) ) @@ -85,7 +85,7 @@ class CategorizeService( listOf( InlineKeyboardButton.WebApp( "Открыть в WebApp", - WebAppInfo("https://app.luminic.space/transactions/${tx.id}/edit") + WebAppInfo("https://app.luminic.space/transactions/${tx.id}/edit?mode=from_bot") ) ) ), @@ -131,7 +131,7 @@ class CategorizeService( listOf( InlineKeyboardButton.WebApp( "Открыть в WebApp", - WebAppInfo("https://app.luminic.space/transactions/${tx.id}/edit") + WebAppInfo("https://app.luminic.space/transactions/${tx.id}/edit?mode=from_bot") ) ) ), diff --git a/src/main/kotlin/space/luminic/finance/services/telegram/BotService.kt b/src/main/kotlin/space/luminic/finance/services/telegram/BotService.kt index 4545b8d..41e8070 100644 --- a/src/main/kotlin/space/luminic/finance/services/telegram/BotService.kt +++ b/src/main/kotlin/space/luminic/finance/services/telegram/BotService.kt @@ -119,7 +119,7 @@ class BotService( @Bean fun bot(): Bot { val bot = com.github.kotlintelegrambot.bot { - logLevel = LogLevel.All() + logLevel = LogLevel.None token = botToken dispatch { message(Filter.Text) { diff --git a/src/main/resources/db/migration/V31__.sql b/src/main/resources/db/migration/V31__.sql new file mode 100644 index 0000000..e0da070 --- /dev/null +++ b/src/main/resources/db/migration/V31__.sql @@ -0,0 +1,59 @@ +DROP table if exists finance.goals cascade; +DROP table if exists finance.goals_components cascade; +DROP table if exists finance.goals_transactions cascade; + +DROP table if exists finance.targets cascade; +DROP table if exists finance.targets_components cascade; +DROP table if exists finance.targets_transactions cascade; + + +CREATE TABLE finance.targets +( + id integer generated by default as identity not null, + space_id INTEGER, + type SMALLINT, + name VARCHAR(255), + description VARCHAR(255), + amount DECIMAL, + until_date date, + created_by_id INTEGER, + created_at TIMESTAMP WITHOUT TIME ZONE, + updated_by_id INTEGER, + updated_at TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT pk_targets PRIMARY KEY (id) +); + + +ALTER TABLE finance.targets + ADD CONSTRAINT FK_TARGETS_ON_CREATEDBY FOREIGN KEY (created_by_id) REFERENCES finance.users (id); + +ALTER TABLE finance.targets + ADD CONSTRAINT FK_TARGETS_ON_SPACE FOREIGN KEY (space_id) REFERENCES finance.spaces (id); + +ALTER TABLE finance.targets + ADD CONSTRAINT FK_TARGETS_ON_UPDATEDBY FOREIGN KEY (updated_by_id) REFERENCES finance.users (id); + +CREATE TABLE finance.targets_transactions +( + target_id INTEGER NOT NULL, + transactions_id INTEGER NOT NULL +); +ALTER TABLE finance.targets_transactions + ADD CONSTRAINT fk_targettx_on_target FOREIGN KEY (target_id) REFERENCES finance.targets (id); + +ALTER TABLE finance.targets_transactions + ADD CONSTRAINT fk_targettx_on_tx FOREIGN KEY (transactions_id) REFERENCES finance.transactions (id); + +create table if not exists finance.targets_components +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, + target_id INTEGER NOT NULL, + name VARCHAR(255) NOT NULL, + amount NUMERIC NOT NULL, + is_done BOOLEAN NOT NULL DEFAULT FALSE, + date TIMESTAMP WITH TIME ZONE NULL +); + +alter table finance.targets_components + add constraint fk_target_on_components foreign key (target_id) references finance.targets (id); +