Skip to content

Commit b8924be

Browse files
authored
Merge pull request #37 from felipemelozx/feat/budgets
Feat/budgets
2 parents e9dc37d + 37a5a10 commit b8924be

File tree

13 files changed

+719
-0
lines changed

13 files changed

+719
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package fun.trackmoney.budget.controller;
2+
3+
import fun.trackmoney.budget.dtos.BudgetCreateDTO;
4+
import fun.trackmoney.budget.dtos.BudgetResponseDTO;
5+
import fun.trackmoney.budget.service.BudgetsService;
6+
import fun.trackmoney.utils.response.ApiResponse;
7+
import org.springframework.http.HttpStatus;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.web.bind.annotation.DeleteMapping;
10+
import org.springframework.web.bind.annotation.GetMapping;
11+
import org.springframework.web.bind.annotation.PathVariable;
12+
import org.springframework.web.bind.annotation.PostMapping;
13+
import org.springframework.web.bind.annotation.PutMapping;
14+
import org.springframework.web.bind.annotation.RequestBody;
15+
import org.springframework.web.bind.annotation.RequestMapping;
16+
import org.springframework.web.bind.annotation.RestController;
17+
18+
import java.util.List;
19+
20+
@RestController
21+
@RequestMapping("budgets")
22+
public class BudgetsController {
23+
24+
private final BudgetsService budgetsService;
25+
26+
public BudgetsController(BudgetsService budgetsService) {
27+
this.budgetsService = budgetsService;
28+
}
29+
30+
@PostMapping
31+
public ResponseEntity<ApiResponse<BudgetResponseDTO>> create(@RequestBody BudgetCreateDTO dto) {
32+
return ResponseEntity.status(HttpStatus.CREATED).body(
33+
new ApiResponse<>(true, "Budget created", budgetsService.create(dto), null));
34+
}
35+
36+
@GetMapping
37+
public ResponseEntity<ApiResponse<List<BudgetResponseDTO>>> findAll() {
38+
var list = budgetsService.findAll();
39+
return ResponseEntity.status(HttpStatus.OK).body(
40+
new ApiResponse<>(true, "Get all Budget",list , null));
41+
}
42+
43+
@GetMapping("/{id}")
44+
public ResponseEntity<ApiResponse<BudgetResponseDTO>> findById(@PathVariable Integer id) {
45+
return ResponseEntity.status(HttpStatus.OK).body(
46+
new ApiResponse<>(true, "Get Budget by Id", budgetsService.findById(id), null));
47+
}
48+
49+
@DeleteMapping("/{id}")
50+
public ResponseEntity<ApiResponse<String>> deleteById(@PathVariable Integer id) {
51+
budgetsService.findById(id);
52+
return ResponseEntity.status(HttpStatus.OK).body(
53+
new ApiResponse<>(true, "Delete Budget by id", "Budget deleted", null));
54+
}
55+
56+
@PutMapping("/{id}")
57+
public ResponseEntity<ApiResponse<BudgetResponseDTO>> updateById(@PathVariable Integer id,
58+
@RequestBody BudgetCreateDTO dto) {
59+
return ResponseEntity.status(HttpStatus.OK).body(
60+
new ApiResponse<>(true, "Update Budget", budgetsService.update(dto,id), null));
61+
}
62+
}
63+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package fun.trackmoney.budget.dtos;
2+
3+
import java.math.BigDecimal;
4+
import java.util.UUID;
5+
6+
public record BudgetCreateDTO(Integer categoryId,
7+
UUID userId,
8+
Integer accountId,
9+
BigDecimal targetAmount,
10+
Integer resetDay) {
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package fun.trackmoney.budget.dtos;
2+
3+
import fun.trackmoney.account.dtos.AccountResponseDTO;
4+
import fun.trackmoney.category.entity.CategoryEntity;
5+
6+
import java.math.BigDecimal;
7+
8+
public record BudgetResponseDTO (Integer budgetId,
9+
CategoryEntity category,
10+
AccountResponseDTO account,
11+
BigDecimal targetAmount,
12+
Integer resetDay) {
13+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package fun.trackmoney.budget.entity;
2+
3+
import fun.trackmoney.account.entity.AccountEntity;
4+
import fun.trackmoney.category.entity.CategoryEntity;
5+
import fun.trackmoney.user.entity.UserEntity;
6+
import jakarta.persistence.Column;
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.GeneratedValue;
9+
import jakarta.persistence.GenerationType;
10+
import jakarta.persistence.Id;
11+
import jakarta.persistence.JoinColumn;
12+
import jakarta.persistence.ManyToOne;
13+
import jakarta.persistence.Table;
14+
15+
import java.math.BigDecimal;
16+
17+
@Entity
18+
@Table(name = "tb_budget")
19+
public class BudgetsEntity {
20+
21+
@Id
22+
@GeneratedValue(strategy = GenerationType.IDENTITY)
23+
@Column(name = "budget_id")
24+
private Integer budgetId;
25+
26+
@ManyToOne
27+
@JoinColumn(name = "category_id")
28+
private CategoryEntity category;
29+
30+
@ManyToOne
31+
@JoinColumn(name = "account_id")
32+
private AccountEntity account;
33+
@ManyToOne
34+
@JoinColumn(name = "user_id")
35+
private UserEntity userEntity;
36+
37+
private BigDecimal targetAmount;
38+
@Column(name = "reset_day")
39+
private Integer resetDay;
40+
41+
public AccountEntity getAccount() {
42+
return account;
43+
}
44+
45+
public BudgetsEntity() {
46+
47+
}
48+
49+
public BudgetsEntity(Integer budgetId,
50+
CategoryEntity category,
51+
UserEntity userEntity,
52+
BigDecimal targetAmount,
53+
Integer resetDay) {
54+
this.budgetId = budgetId;
55+
this.category = category;
56+
this.userEntity = userEntity;
57+
this.targetAmount = targetAmount;
58+
this.resetDay = resetDay;
59+
}
60+
61+
public void setAccount(AccountEntity account) {
62+
this.account = account;
63+
}
64+
65+
public BudgetsEntity(UserEntity userEntity) {
66+
this.userEntity = userEntity;
67+
}
68+
69+
public Integer getBudgetId() {
70+
return budgetId;
71+
}
72+
73+
public void setBudgetId(Integer budgetId) {
74+
this.budgetId = budgetId;
75+
}
76+
77+
public CategoryEntity getCategory() {
78+
return category;
79+
}
80+
81+
public void setCategory(CategoryEntity category) {
82+
this.category = category;
83+
}
84+
85+
public BigDecimal getTargetAmount() {
86+
return targetAmount;
87+
}
88+
89+
public void setTargetAmount(BigDecimal targetAmount) {
90+
this.targetAmount = targetAmount;
91+
}
92+
93+
public Integer getResetDay() {
94+
return resetDay;
95+
}
96+
97+
public void setResetDay(Integer resetDay) {
98+
this.resetDay = resetDay;
99+
}
100+
101+
public UserEntity getUserEntity() {
102+
return userEntity;
103+
}
104+
105+
public void setUserEntity(UserEntity userEntity) {
106+
this.userEntity = userEntity;
107+
}
108+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package fun.trackmoney.budget.exception;
2+
3+
import fun.trackmoney.utils.CustomFieldError;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
8+
public class BudgetsNotFoundException extends RuntimeException {
9+
private final List<CustomFieldError> errors = new ArrayList<>();
10+
11+
public BudgetsNotFoundException(String message) {
12+
super(message);
13+
this.errors.add(new CustomFieldError("Budgets", message));
14+
}
15+
16+
public BudgetsNotFoundException(List<CustomFieldError> errors) {
17+
super("Budgets not found!");
18+
this.errors.addAll(errors);
19+
}
20+
21+
public List<CustomFieldError> getErrors() {
22+
return errors;
23+
}
24+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package fun.trackmoney.budget.mapper;
2+
3+
import fun.trackmoney.budget.dtos.BudgetCreateDTO;
4+
import fun.trackmoney.budget.dtos.BudgetResponseDTO;
5+
import fun.trackmoney.budget.entity.BudgetsEntity;
6+
import org.mapstruct.Mapper;
7+
8+
import java.util.List;
9+
10+
@Mapper(componentModel = "spring")
11+
public interface BudgetMapper {
12+
13+
BudgetsEntity createDtoTOEntity(BudgetCreateDTO dto);
14+
15+
BudgetResponseDTO entityToResponseDTO(BudgetsEntity entity);
16+
17+
List<BudgetResponseDTO> entityListToResponseList(List<BudgetsEntity> entityList);
18+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package fun.trackmoney.budget.repository;
2+
3+
import fun.trackmoney.budget.entity.BudgetsEntity;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
public interface BudgetsRepository extends JpaRepository<BudgetsEntity, Integer> {
7+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package fun.trackmoney.budget.service;
2+
3+
import fun.trackmoney.account.mapper.AccountMapper;
4+
import fun.trackmoney.account.service.AccountService;
5+
import fun.trackmoney.budget.dtos.BudgetCreateDTO;
6+
import fun.trackmoney.budget.dtos.BudgetResponseDTO;
7+
import fun.trackmoney.budget.entity.BudgetsEntity;
8+
import fun.trackmoney.budget.exception.BudgetsNotFoundException;
9+
import fun.trackmoney.budget.mapper.BudgetMapper;
10+
import fun.trackmoney.budget.repository.BudgetsRepository;
11+
import fun.trackmoney.category.service.CategoryService;
12+
import fun.trackmoney.user.service.UserService;
13+
import org.springframework.stereotype.Service;
14+
15+
import java.util.List;
16+
17+
@Service
18+
public class BudgetsService {
19+
20+
private final BudgetsRepository budgetsRepository;
21+
private final BudgetMapper budgetMapper;
22+
private final AccountService accountService;
23+
private final AccountMapper accountMapper;
24+
private final CategoryService categoryService;
25+
private final UserService userService;
26+
27+
public BudgetsService(BudgetsRepository budgetsRepository,
28+
BudgetMapper budgetMapper,
29+
AccountService accountService,
30+
AccountMapper accountMapper,
31+
CategoryService categoryService,
32+
UserService userService) {
33+
this.budgetsRepository = budgetsRepository;
34+
this.budgetMapper = budgetMapper;
35+
this.accountService = accountService;
36+
this.accountMapper = accountMapper;
37+
this.categoryService = categoryService;
38+
this.userService = userService;
39+
}
40+
41+
public BudgetResponseDTO create(BudgetCreateDTO dto) {
42+
BudgetsEntity budgets = budgetMapper.createDtoTOEntity(dto);
43+
44+
budgets.setUserEntity(userService.findUserById(dto.userId()));
45+
budgets.setAccount(accountMapper.accountResponseToEntity(accountService.findAccountById(dto.accountId())));
46+
budgets.setCategory(categoryService.findById(dto.categoryId()));
47+
return budgetMapper.entityToResponseDTO(budgetsRepository.save(budgets));
48+
}
49+
50+
public List<BudgetResponseDTO> findAll() {
51+
return budgetMapper.entityListToResponseList(budgetsRepository.findAll());
52+
}
53+
54+
public BudgetResponseDTO findById(Integer id) {
55+
return budgetMapper.entityToResponseDTO(budgetsRepository.findById(id)
56+
.orElseThrow(() -> new BudgetsNotFoundException("Budget not found")));
57+
}
58+
59+
public BudgetResponseDTO update(BudgetCreateDTO dto, Integer id) {
60+
budgetsRepository.findById(id)
61+
.orElseThrow(() -> new BudgetsNotFoundException(("Budget not found")));
62+
63+
BudgetsEntity budgets = budgetMapper.createDtoTOEntity(dto);
64+
budgets.setBudgetId(id);
65+
budgets.setUserEntity(userService.findUserById(dto.userId()));
66+
budgets.setAccount(accountMapper.accountResponseToEntity(accountService.findAccountById(dto.accountId())));
67+
budgets.setCategory(categoryService.findById(dto.categoryId()));
68+
budgets.setTargetAmount(dto.targetAmount());
69+
budgets.setResetDay(dto.resetDay());
70+
71+
return budgetMapper.entityToResponseDTO(budgetsRepository.save(budgets));
72+
}
73+
74+
public void deleteById(Integer id) {
75+
budgetsRepository.deleteById(id);
76+
}
77+
}

src/main/java/fun/trackmoney/config/exception/RestExceptionHandler.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import fun.trackmoney.account.exception.AccountNotFoundException;
44
import fun.trackmoney.auth.exception.LoginException;
5+
import fun.trackmoney.budget.exception.BudgetsNotFoundException;
56
import fun.trackmoney.category.exception.CategoryNotFoundException;
67
import fun.trackmoney.goal.exception.GoalsNotFoundException;
78
import fun.trackmoney.transaction.exception.TransactionNotFoundException;
@@ -101,4 +102,12 @@ public ResponseEntity<ApiResponse<List<CustomFieldError>>> goalsNotFound(GoalsNo
101102
.body(new ApiResponse<>(false, ex.getMessage(), null, ex.getErrors())
102103
);
103104
}
105+
106+
@ExceptionHandler(BudgetsNotFoundException.class)
107+
public ResponseEntity<ApiResponse<List<CustomFieldError>>> budgetsNotFound(BudgetsNotFoundException ex) {
108+
return ResponseEntity
109+
.status(HttpStatus.NOT_FOUND)
110+
.body(new ApiResponse<>(false, ex.getMessage(), null, ex.getErrors())
111+
);
112+
}
104113
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE TABLE tb_budget(
2+
budget_id SERIAL PRIMARY KEY,
3+
user_id UUID NOT NULL,
4+
account_id SERIAL NOT NULL,
5+
category_id SERIAL NOT NULL,
6+
target_amount NUMERIC(19, 4) NOT NULL DEFAULT 0.0000,
7+
reset_day INTEGER,
8+
9+
CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES tb_user(user_id),
10+
CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES tb_account(account_id),
11+
CONSTRAINT fk_category FOREIGN KEY (category_id) REFERENCES tb_category(category_id)
12+
);

0 commit comments

Comments
 (0)