fix recurrents
This commit is contained in:
@@ -39,7 +39,6 @@ class FinancialService(
|
||||
val recurrentService: RecurrentService,
|
||||
val userService: UserService,
|
||||
val reactiveMongoTemplate: ReactiveMongoTemplate,
|
||||
private val spaceService: SpaceService,
|
||||
private val categoryRepo: CategoryRepo,
|
||||
val transactionsMapper: TransactionsMapper,
|
||||
val budgetMapper: BudgetMapper
|
||||
@@ -197,35 +196,10 @@ class FinancialService(
|
||||
Sort.by(it.order, it.by)
|
||||
} ?: Sort.by(Direction.DESC, "dateFrom")
|
||||
|
||||
return ReactiveSecurityContextHolder.getContext().map { it.authentication }.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
spaceService.getSpace(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for $spaceId")))
|
||||
.flatMap { space ->
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
val userIds = space.users.mapNotNull { it.id }
|
||||
if (user.id !in userIds) {
|
||||
Mono.error(IllegalArgumentException("User cannot access this Space"))
|
||||
} else {
|
||||
val spaceObjectId = try {
|
||||
ObjectId(space.id!!) // Преобразуем строку в ObjectId
|
||||
} catch (e: IllegalArgumentException) {
|
||||
return@flatMap Mono.error(IllegalArgumentException("Invalid Space ID format: ${space.id}"))
|
||||
}
|
||||
|
||||
println("Space ID type: ${spaceObjectId::class.java}, value: $spaceObjectId")
|
||||
// Применяем сортировку к запросу
|
||||
findProjectedBudgets(spaceObjectId, sort)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return findProjectedBudgets(ObjectId(spaceId), sort)
|
||||
}
|
||||
|
||||
|
||||
fun findProjectedBudgets(spaceId: ObjectId, sortRequested: Sort? = null): Mono<List<Budget>> {
|
||||
val lookupCategories = lookup("categories", "categories.category.\$id", "_id", "categoriesDetails")
|
||||
|
||||
@@ -242,7 +216,7 @@ class FinancialService(
|
||||
Sort.by(Direction.DESC, "date").and(Sort.by(Direction.DESC, "createdAt"))
|
||||
)
|
||||
val aggregation =
|
||||
newAggregation(lookupCategories, lookupIncomeCategories, lookupSpace, unwindSpace, matchStage, sort)
|
||||
newAggregation(lookupCategories, lookupIncomeCategories, lookupSpace, unwindSpace, matchStage, sort)
|
||||
|
||||
return reactiveMongoTemplate.aggregate(aggregation, "budgets", Document::class.java).collectList().map { docs ->
|
||||
docs.map { doc ->
|
||||
@@ -268,7 +242,7 @@ class FinancialService(
|
||||
dateTo?.let { matchCriteria.add(Criteria.where("dateTo").gte(it)) }
|
||||
matchCriteria.add(Criteria.where("spaceDetails._id").`is`(ObjectId(spaceId)))
|
||||
val matchStage = match(Criteria().andOperator(*matchCriteria.toTypedArray()))
|
||||
val aggregation = newAggregation(lookupCategories, lookupIncomeCategories, lookupSpace, unwindSpace, matchStage)
|
||||
val aggregation = newAggregation(lookupCategories, lookupIncomeCategories, lookupSpace, unwindSpace, matchStage)
|
||||
|
||||
return reactiveMongoTemplate.aggregate(aggregation, "budgets", Document::class.java).next().map { doc ->
|
||||
budgetMapper.fromDocument(doc)
|
||||
@@ -380,10 +354,10 @@ class FinancialService(
|
||||
}
|
||||
|
||||
|
||||
fun createBudget(spaceId: String, budget: Budget, createRecurrent: Boolean): Mono<Budget> {
|
||||
return Mono.zip(getBudgetByDate(budget.dateFrom, spaceId).map { Optional.ofNullable(it) }
|
||||
fun createBudget(space: Space, budget: Budget, createRecurrent: Boolean): Mono<Budget> {
|
||||
return Mono.zip(getBudgetByDate(budget.dateFrom, space.id!!).map { Optional.ofNullable(it) }
|
||||
.switchIfEmpty(Mono.just(Optional.empty())),
|
||||
getBudgetByDate(budget.dateTo, spaceId).map { Optional.ofNullable(it) }
|
||||
getBudgetByDate(budget.dateTo, space.id!!).map { Optional.ofNullable(it) }
|
||||
.switchIfEmpty(Mono.just(Optional.empty()))).flatMap { tuple ->
|
||||
val startBudget = tuple.t1.orElse(null)
|
||||
val endBudget = tuple.t2.orElse(null)
|
||||
@@ -394,65 +368,53 @@ class FinancialService(
|
||||
}
|
||||
|
||||
// Получаем Space по spaceId
|
||||
spaceService.getSpace(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for $spaceId"))).flatMap { space ->
|
||||
// Проверяем, входит ли пользователь в этот Space
|
||||
ReactiveSecurityContextHolder.getContext().flatMap { securityContext ->
|
||||
val username = securityContext.authentication.name
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
if (space.users.none { it.id == user.id }) {
|
||||
return@flatMap Mono.error<Budget>(IllegalArgumentException("User does not have access to this space"))
|
||||
}
|
||||
|
||||
// Присваиваем Space бюджету
|
||||
budget.space = space
|
||||
|
||||
// Если createRecurrent=true, создаем рекуррентные транзакции
|
||||
val recurrentsCreation = if (createRecurrent) {
|
||||
recurrentService.createRecurrentsForBudget(space, budget)
|
||||
} else {
|
||||
Mono.empty()
|
||||
}
|
||||
// Присваиваем Space бюджету
|
||||
budget.space = space
|
||||
|
||||
// Создаем бюджет после возможного создания рекуррентных транзакций
|
||||
recurrentsCreation.then(
|
||||
getCategoryTransactionPipeline(
|
||||
spaceId,
|
||||
budget.dateFrom,
|
||||
budget.dateTo
|
||||
).flatMap { categories ->
|
||||
budget.categories = categories
|
||||
budgetRepo.save(budget)
|
||||
}.publishOn(Schedulers.boundedElastic()).doOnNext { savedBudget ->
|
||||
// Выполнение updateBudgetWarns в фоне
|
||||
updateBudgetWarns(budget = savedBudget).doOnError { error ->
|
||||
// Логируем ошибку, если произошла
|
||||
logger.error("Error during updateBudgetWarns: ${error.message}")
|
||||
}.subscribe()
|
||||
}).then(
|
||||
getCategoryTransactionPipeline(
|
||||
spaceId,
|
||||
budget.dateFrom,
|
||||
budget.dateTo,
|
||||
"INCOME"
|
||||
).flatMap { categories ->
|
||||
budget.incomeCategories = categories
|
||||
budgetRepo.save(budget)
|
||||
}.publishOn(Schedulers.boundedElastic()).doOnNext { savedBudget ->
|
||||
// Выполнение updateBudgetWarns в фоне
|
||||
updateBudgetWarns(budget = savedBudget).doOnError { error ->
|
||||
// Логируем ошибку, если произошла
|
||||
logger.error("Error during updateBudgetWarns: ${error.message}")
|
||||
}.subscribe()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
// Если createRecurrent=true, создаем рекуррентные транзакции
|
||||
val recurrentsCreation = if (createRecurrent) {
|
||||
recurrentService.createRecurrentsForBudget(space, budget)
|
||||
} else {
|
||||
Mono.empty()
|
||||
}
|
||||
|
||||
// Создаем бюджет после возможного создания рекуррентных транзакций
|
||||
recurrentsCreation.then(
|
||||
getCategoryTransactionPipeline(
|
||||
space.id!!,
|
||||
budget.dateFrom,
|
||||
budget.dateTo
|
||||
).flatMap { categories ->
|
||||
budget.categories = categories
|
||||
budgetRepo.save(budget)
|
||||
}.publishOn(Schedulers.boundedElastic()).doOnNext { savedBudget ->
|
||||
// Выполнение updateBudgetWarns в фоне
|
||||
updateBudgetWarns(budget = savedBudget).doOnError { error ->
|
||||
// Логируем ошибку, если произошла
|
||||
logger.error("Error during updateBudgetWarns: ${error.message}")
|
||||
}.subscribe()
|
||||
}).then(
|
||||
getCategoryTransactionPipeline(
|
||||
space.id!!,
|
||||
budget.dateFrom,
|
||||
budget.dateTo,
|
||||
"INCOME"
|
||||
).flatMap { categories ->
|
||||
budget.incomeCategories = categories
|
||||
budgetRepo.save(budget)
|
||||
}.publishOn(Schedulers.boundedElastic()).doOnNext { savedBudget ->
|
||||
// Выполнение updateBudgetWarns в фоне
|
||||
updateBudgetWarns(budget = savedBudget).doOnError { error ->
|
||||
// Логируем ошибку, если произошла
|
||||
logger.error("Error during updateBudgetWarns: ${error.message}")
|
||||
}.subscribe()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun getBudgetByDate(date: LocalDate, spaceId: String): Mono<Budget> {
|
||||
return budgetRepo.findByDateFromLessThanEqualAndDateToGreaterThanEqualAndSpace(date, date, ObjectId(spaceId))
|
||||
.switchIfEmpty(Mono.empty())
|
||||
@@ -665,82 +627,69 @@ class FinancialService(
|
||||
limit: Int? = null,
|
||||
offset: Int? = null,
|
||||
): Mono<MutableList<Transaction>> {
|
||||
return ReactiveSecurityContextHolder.getContext().map { it.authentication }.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
spaceService.getSpace(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for $spaceId")))
|
||||
.flatMap { space ->
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
if (space.users.none { it.id.toString() == user.id }) {
|
||||
return@flatMap Mono.error<MutableList<Transaction>>(IllegalArgumentException("User does not have access to this Space"))
|
||||
}
|
||||
|
||||
val matchCriteria = mutableListOf<Criteria>()
|
||||
val matchCriteria = mutableListOf<Criteria>()
|
||||
|
||||
// Добавляем фильтры
|
||||
matchCriteria.add(Criteria.where("spaceDetails._id").`is`(ObjectId(spaceId)))
|
||||
dateFrom?.let { matchCriteria.add(Criteria.where("date").gte(it)) }
|
||||
dateTo?.let { matchCriteria.add(Criteria.where("date").lt(it)) }
|
||||
transactionType?.let { matchCriteria.add(Criteria.where("type.code").`is`(it)) }
|
||||
isDone?.let { matchCriteria.add(Criteria.where("isDone").`is`(it)) }
|
||||
categoryId?.let { matchCriteria.add(Criteria.where("categoryDetails._id").`is`(it)) }
|
||||
categoryType?.let {
|
||||
matchCriteria.add(
|
||||
Criteria.where("categoryDetails.type.code").`is`(it)
|
||||
)
|
||||
}
|
||||
userId?.let { matchCriteria.add(Criteria.where("userDetails._id").`is`(ObjectId(it))) }
|
||||
parentId?.let { matchCriteria.add(Criteria.where("parentId").`is`(it)) }
|
||||
isChild?.let { matchCriteria.add(Criteria.where("parentId").exists(it)) }
|
||||
// Добавляем фильтры
|
||||
matchCriteria.add(Criteria.where("spaceDetails._id").`is`(ObjectId(spaceId)))
|
||||
dateFrom?.let { matchCriteria.add(Criteria.where("date").gte(it)) }
|
||||
dateTo?.let { matchCriteria.add(Criteria.where("date").lt(it)) }
|
||||
transactionType?.let { matchCriteria.add(Criteria.where("type.code").`is`(it)) }
|
||||
isDone?.let { matchCriteria.add(Criteria.where("isDone").`is`(it)) }
|
||||
categoryId?.let { matchCriteria.add(Criteria.where("categoryDetails._id").`is`(it)) }
|
||||
categoryType?.let {
|
||||
matchCriteria.add(
|
||||
Criteria.where("categoryDetails.type.code").`is`(it)
|
||||
)
|
||||
}
|
||||
userId?.let { matchCriteria.add(Criteria.where("userDetails._id").`is`(ObjectId(it))) }
|
||||
parentId?.let { matchCriteria.add(Criteria.where("parentId").`is`(it)) }
|
||||
isChild?.let { matchCriteria.add(Criteria.where("parentId").exists(it)) }
|
||||
|
||||
// Сборка агрегации
|
||||
val lookup = lookup("categories", "category.\$id", "_id", "categoryDetails")
|
||||
val unwindCategory = unwind("categoryDetails")
|
||||
val lookupSpaces = lookup("spaces", "space.\$id", "_id", "spaceDetails")
|
||||
val unwindSpace = unwind("spaceDetails")
|
||||
val lookupUsers = lookup("users", "user.\$id", "_id", "userDetails")
|
||||
val unwindUser = unwind("userDetails")
|
||||
// Сборка агрегации
|
||||
val lookup = lookup("categories", "category.\$id", "_id", "categoryDetails")
|
||||
val unwindCategory = unwind("categoryDetails")
|
||||
val lookupSpaces = lookup("spaces", "space.\$id", "_id", "spaceDetails")
|
||||
val unwindSpace = unwind("spaceDetails")
|
||||
val lookupUsers = lookup("users", "user.\$id", "_id", "userDetails")
|
||||
val unwindUser = unwind("userDetails")
|
||||
|
||||
val match = match(Criteria().andOperator(*matchCriteria.toTypedArray()))
|
||||
val match = match(Criteria().andOperator(*matchCriteria.toTypedArray()))
|
||||
|
||||
var sort =
|
||||
sort(Sort.by(Direction.DESC, "date").and(Sort.by(Direction.DESC, "createdAt")))
|
||||
var sort =
|
||||
sort(Sort.by(Direction.DESC, "date").and(Sort.by(Direction.DESC, "createdAt")))
|
||||
|
||||
sortSetting?.let {
|
||||
sort = sort(Sort.by(it.order, it.by).and(Sort.by(Direction.ASC, "createdAt")))
|
||||
}
|
||||
sortSetting?.let {
|
||||
sort = sort(Sort.by(it.order, it.by).and(Sort.by(Direction.ASC, "createdAt")))
|
||||
}
|
||||
|
||||
val aggregationBuilder = mutableListOf(
|
||||
lookup,
|
||||
unwindCategory,
|
||||
lookupSpaces,
|
||||
unwindSpace,
|
||||
lookupUsers,
|
||||
unwindUser,
|
||||
match.takeIf { matchCriteria.isNotEmpty() },
|
||||
sort,
|
||||
offset?.let { skip(it.toLong()) },
|
||||
limit?.let { limit(it.toLong()) }).filterNotNull()
|
||||
val aggregationBuilder = mutableListOf(
|
||||
lookup,
|
||||
unwindCategory,
|
||||
lookupSpaces,
|
||||
unwindSpace,
|
||||
lookupUsers,
|
||||
unwindUser,
|
||||
match.takeIf { matchCriteria.isNotEmpty() },
|
||||
sort,
|
||||
offset?.let { skip(it.toLong()) },
|
||||
limit?.let { limit(it.toLong()) }).filterNotNull()
|
||||
|
||||
val aggregation = newAggregation(aggregationBuilder)
|
||||
val aggregation = newAggregation(aggregationBuilder)
|
||||
|
||||
return@flatMap reactiveMongoTemplate.aggregate(
|
||||
aggregation, "transactions", Document::class.java
|
||||
).collectList().map { docs ->
|
||||
return reactiveMongoTemplate.aggregate(
|
||||
aggregation, "transactions", Document::class.java
|
||||
).collectList().map { docs ->
|
||||
|
||||
val test = docs.map { doc ->
|
||||
transactionsMapper.fromDocument(doc)
|
||||
}.toMutableList()
|
||||
val test = docs.map { doc ->
|
||||
transactionsMapper.fromDocument(doc)
|
||||
}.toMutableList()
|
||||
|
||||
test
|
||||
}
|
||||
}
|
||||
}
|
||||
test
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun getTransactionByParentId(
|
||||
parentId: String
|
||||
): Mono<Transaction> {
|
||||
@@ -832,26 +781,22 @@ class FinancialService(
|
||||
}
|
||||
|
||||
|
||||
fun createTransaction(spaceId: String, transaction: Transaction): Mono<Transaction> {
|
||||
fun createTransaction(space: Space, transaction: Transaction): Mono<Transaction> {
|
||||
return ReactiveSecurityContextHolder.getContext().map { it.authentication }.flatMap { authentication ->
|
||||
val username = authentication.name
|
||||
spaceService.getSpace(spaceId)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for $spaceId")))
|
||||
.flatMap { space ->
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
if (space.users.none { it.id.toString() == user.id }) {
|
||||
return@flatMap Mono.error<Transaction>(IllegalArgumentException("User does not have access to this Space"))
|
||||
}
|
||||
// Привязываем space и user к транзакции
|
||||
transaction.user = user
|
||||
transaction.space = space
|
||||
userService.getByUsername(username)
|
||||
.switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username")))
|
||||
.flatMap { user ->
|
||||
if (space.users.none { it.id.toString() == user.id }) {
|
||||
return@flatMap Mono.error<Transaction>(IllegalArgumentException("User does not have access to this Space"))
|
||||
}
|
||||
// Привязываем space и user к транзакции
|
||||
transaction.user = user
|
||||
transaction.space = space
|
||||
|
||||
transactionsRepo.save(transaction).flatMap { savedTransaction ->
|
||||
updateBudgetOnCreate(savedTransaction).thenReturn(savedTransaction) // Ждём выполнения updateBudgetOnCreate перед возвратом
|
||||
}
|
||||
}
|
||||
transactionsRepo.save(transaction).flatMap { savedTransaction ->
|
||||
updateBudgetOnCreate(savedTransaction).thenReturn(savedTransaction) // Ждём выполнения updateBudgetOnCreate перед возвратом
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1669,7 +1614,7 @@ class FinancialService(
|
||||
Document("\$unwind", "\$categoryInfo"),
|
||||
|
||||
// 5. Фильтруем по типу категории (EXPENSE)
|
||||
Document("\$match", Document("categoryInfo.type.code", "EXPENSE")),
|
||||
// Document("\$match", Document("categoryInfo.type.code", "EXPENSE")),
|
||||
|
||||
// 6. Группируем обратно по категории, собирая все (год, месяц, total)
|
||||
Document(
|
||||
|
||||
Reference in New Issue
Block a user