Skip to content

Commit c5f58fe

Browse files
authored
Merge pull request #32 from felipemelozx/feat/account-crud
feat: Add account endpoints create, findAll, findById, delete and upd…
2 parents 7035f2a + 4d4da1d commit c5f58fe

File tree

17 files changed

+557
-37
lines changed

17 files changed

+557
-37
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package fun.trackmoney.account.controller;
2+
3+
import fun.trackmoney.account.dtos.AccountRequestDTO;
4+
import fun.trackmoney.account.dtos.AccountResponseDTO;
5+
import fun.trackmoney.account.dtos.AccountUpdateRequestDTO;
6+
import fun.trackmoney.account.service.AccountService;
7+
import fun.trackmoney.utils.response.ApiResponse;
8+
import org.springframework.http.HttpStatus;
9+
import org.springframework.http.ResponseEntity;
10+
import org.springframework.web.bind.annotation.DeleteMapping;
11+
import org.springframework.web.bind.annotation.GetMapping;
12+
import org.springframework.web.bind.annotation.PathVariable;
13+
import org.springframework.web.bind.annotation.PostMapping;
14+
import org.springframework.web.bind.annotation.PutMapping;
15+
import org.springframework.web.bind.annotation.RequestBody;
16+
import org.springframework.web.bind.annotation.RequestMapping;
17+
import org.springframework.web.bind.annotation.RestController;
18+
19+
import java.util.List;
20+
21+
@RestController
22+
@RequestMapping("/accounts")
23+
public class AccountController {
24+
25+
private final AccountService accountService;
26+
27+
public AccountController(AccountService accountService) {
28+
this.accountService = accountService;
29+
}
30+
31+
@PostMapping
32+
public ResponseEntity<ApiResponse<AccountResponseDTO>> createAccount(@RequestBody AccountRequestDTO dto) {
33+
AccountResponseDTO createdAccount = accountService.createAccount(dto);
34+
return new ResponseEntity<>(new ApiResponse<>(
35+
true, "Account successfully created.", createdAccount, null), HttpStatus.CREATED);
36+
}
37+
38+
@GetMapping
39+
public ResponseEntity<ApiResponse<List<AccountResponseDTO>>> findAllAccounts() {
40+
List<AccountResponseDTO> accounts = accountService.findAllAccount();
41+
return ResponseEntity.ok(new ApiResponse<>(
42+
true, "Account list retrieved successfully.", accounts, null));
43+
}
44+
45+
@GetMapping("/{id}")
46+
public ResponseEntity<ApiResponse<AccountResponseDTO>> findAccountById(@PathVariable Integer id) {
47+
AccountResponseDTO account = accountService.findAccountById(id);
48+
return ResponseEntity.ok(new ApiResponse<>(
49+
true, "Account retrieved successfully.", account, null));
50+
}
51+
52+
@PutMapping("/{id}")
53+
public ResponseEntity<ApiResponse<AccountResponseDTO>> updateAccountById(@PathVariable Integer id,
54+
@RequestBody AccountUpdateRequestDTO dto) {
55+
AccountResponseDTO updatedAccount = accountService.updateAccountById(id, dto);
56+
return ResponseEntity.ok(new ApiResponse<>(
57+
true, "Account updated successfully.", updatedAccount, null));
58+
}
59+
60+
@DeleteMapping("/{id}")
61+
public ResponseEntity<Void> deleteAccountById(@PathVariable Integer id) {
62+
accountService.deleteById(id);
63+
return ResponseEntity.noContent().build();
64+
}
65+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package fun.trackmoney.account.dtos;
2+
3+
import java.math.BigDecimal;
4+
import java.util.UUID;
5+
6+
public record AccountRequestDTO(
7+
UUID userId,
8+
String name,
9+
BigDecimal balance,
10+
Boolean isAccountDefault
11+
) {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package fun.trackmoney.account.dtos;
2+
3+
import fun.trackmoney.user.dtos.UserResponseDTO;
4+
5+
import java.math.BigDecimal;
6+
7+
public record AccountResponseDTO(
8+
Integer accountId,
9+
UserResponseDTO user,
10+
String name,
11+
BigDecimal balance,
12+
Boolean isAccountDefault
13+
) {}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package fun.trackmoney.account.dtos;
2+
3+
public record AccountUpdateRequestDTO(
4+
String name,
5+
Boolean isAccountDefault
6+
) {}

src/main/java/fun/trackmoney/account/entity/AccountEntity.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fun.trackmoney.account.entity;
22

33
import fun.trackmoney.user.entity.UserEntity;
4+
import jakarta.persistence.Column;
45
import jakarta.persistence.Entity;
56
import jakarta.persistence.GeneratedValue;
67
import jakarta.persistence.GenerationType;
@@ -48,6 +49,7 @@ public class AccountEntity {
4849
* Indicates whether this account is the user's default account.
4950
* Can be {@code true} or {@code false}.
5051
*/
52+
@Column(name = "is_account_default")
5153
private Boolean isAccountDefault;
5254

5355
/**
@@ -152,7 +154,7 @@ public void setBalance(BigDecimal balance) {
152154
*
153155
* @return {@code true} if this is the default account, {@code false} otherwise.
154156
*/
155-
public Boolean getAccountDefault() {
157+
public Boolean getIsAccountDefault() {
156158
return isAccountDefault;
157159
}
158160

@@ -161,7 +163,7 @@ public Boolean getAccountDefault() {
161163
*
162164
* @param accountDefault {@code true} if this is the default account, {@code false} otherwise.
163165
*/
164-
public void setAccountDefault(Boolean accountDefault) {
166+
public void setIsAccountDefault(Boolean accountDefault) {
165167
isAccountDefault = accountDefault;
166168
}
167169
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package fun.trackmoney.account.exception;
2+
3+
import fun.trackmoney.utils.CustomFieldError;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
8+
public class AccountNotFoundException extends RuntimeException {
9+
private final List<CustomFieldError> errors = new ArrayList<>();
10+
11+
public AccountNotFoundException(String message) {
12+
super(message);
13+
this.errors.add(new CustomFieldError("Account", message));
14+
}
15+
16+
public AccountNotFoundException(List<CustomFieldError> errors) {
17+
super("Account not found!");
18+
this.errors.addAll(errors);
19+
}
20+
21+
public List<CustomFieldError> getErrors() {
22+
return errors;
23+
}
24+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package fun.trackmoney.account.mapper;
2+
3+
import fun.trackmoney.account.dtos.AccountRequestDTO;
4+
import fun.trackmoney.account.dtos.AccountResponseDTO;
5+
import fun.trackmoney.account.dtos.AccountUpdateRequestDTO;
6+
import fun.trackmoney.account.entity.AccountEntity;
7+
import org.mapstruct.Mapper;
8+
9+
import java.util.List;
10+
11+
@Mapper(componentModel = "spring")
12+
public interface AccountMapper {
13+
AccountEntity accountRequestToAccountEntity(AccountRequestDTO accountRequestDTO);
14+
15+
AccountEntity accountUpdateRequestToAccountEntity(AccountUpdateRequestDTO accountRequestDTO);
16+
17+
AccountResponseDTO accountEntityToAccountResponse(AccountEntity accountEntity);
18+
19+
List<AccountResponseDTO> accountEntityListToAccountResponseList(List<AccountEntity> entities);
20+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package fun.trackmoney.account.repository;
2+
3+
import fun.trackmoney.account.entity.AccountEntity;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
public interface AccountRepository extends JpaRepository<AccountEntity, Integer> {
7+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package fun.trackmoney.account.service;
2+
3+
import fun.trackmoney.account.dtos.AccountRequestDTO;
4+
import fun.trackmoney.account.dtos.AccountResponseDTO;
5+
import fun.trackmoney.account.dtos.AccountUpdateRequestDTO;
6+
import fun.trackmoney.account.entity.AccountEntity;
7+
import fun.trackmoney.account.exception.AccountNotFoundException;
8+
import fun.trackmoney.account.mapper.AccountMapper;
9+
import fun.trackmoney.account.repository.AccountRepository;
10+
import fun.trackmoney.user.service.UserService;
11+
import org.springframework.stereotype.Service;
12+
13+
import java.util.List;
14+
15+
@Service
16+
public class AccountService {
17+
18+
private final AccountRepository accountRepository;
19+
private final AccountMapper accountMapper;
20+
private final UserService userService;
21+
22+
public AccountService(AccountRepository accountRepository, AccountMapper accountMapper, UserService userService) {
23+
this.accountRepository = accountRepository;
24+
this.accountMapper = accountMapper;
25+
this.userService = userService;
26+
}
27+
28+
public AccountResponseDTO createAccount(AccountRequestDTO dto) {
29+
AccountEntity account = accountMapper.accountRequestToAccountEntity(dto);
30+
31+
account.setUser(userService.findUserById(dto.userId()));
32+
33+
return accountMapper.accountEntityToAccountResponse(accountRepository
34+
.save(account));
35+
}
36+
37+
public List<AccountResponseDTO> findAllAccount() {
38+
return accountMapper.accountEntityListToAccountResponseList(accountRepository.findAll());
39+
}
40+
41+
public AccountResponseDTO findAccountById(Integer id) {
42+
return accountMapper.accountEntityToAccountResponse(accountRepository.findById(id)
43+
.orElseThrow(() -> new AccountNotFoundException("Account not found!")));
44+
}
45+
46+
public AccountResponseDTO updateAccountById(Integer id, AccountUpdateRequestDTO dto) {
47+
AccountEntity account = accountRepository.findById(id)
48+
.orElseThrow(() -> new AccountNotFoundException("Account not found!"));
49+
50+
account.setName(dto.name());
51+
account.setIsAccountDefault(dto.isAccountDefault());
52+
53+
return accountMapper.accountEntityToAccountResponse(accountRepository.save(account));
54+
}
55+
56+
public void deleteById(Integer id) {
57+
accountRepository.deleteById(id);
58+
}
59+
}

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package fun.trackmoney.config.exception;
22

3+
import fun.trackmoney.account.exception.AccountNotFoundException;
34
import fun.trackmoney.auth.exception.LoginException;
45
import fun.trackmoney.category.exception.CategoryNotFoundException;
56
import fun.trackmoney.user.exception.EmailAlreadyExistsException;
6-
import fun.trackmoney.user.exception.EmailNotFoundException;
7+
import fun.trackmoney.user.exception.UserNotFoundException;
78
import fun.trackmoney.user.exception.PasswordNotValid;
89
import fun.trackmoney.utils.CustomFieldError;
910
import fun.trackmoney.utils.response.ApiResponse;
@@ -53,8 +54,8 @@ public ResponseEntity<ApiResponse<List<CustomFieldError>>> handleEmailAlreadyExi
5354
List.of(new CustomFieldError("Email", ex.getMessage()))));
5455
}
5556

56-
@ExceptionHandler(EmailNotFoundException.class)
57-
public ResponseEntity<ApiResponse<List<CustomFieldError>>> emailNotFound(EmailNotFoundException ex) {
57+
@ExceptionHandler(UserNotFoundException.class)
58+
public ResponseEntity<ApiResponse<List<CustomFieldError>>> emailNotFound(UserNotFoundException ex) {
5859
return ResponseEntity.badRequest().body(
5960
new ApiResponse<>(false, ex.getMessage(), null, ex.getErrors())
6061
);
@@ -74,4 +75,12 @@ public ResponseEntity<ApiResponse<List<CustomFieldError>>> categoryNotFound(Cate
7475
.body(new ApiResponse<>(false, ex.getMessage(), null,
7576
List.of(new CustomFieldError("Category", ex.getMessage()))));
7677
}
78+
79+
@ExceptionHandler(AccountNotFoundException.class)
80+
public ResponseEntity<ApiResponse<List<CustomFieldError>>> accountNotFound(AccountNotFoundException ex) {
81+
return ResponseEntity
82+
.status(HttpStatus.NOT_FOUND)
83+
.body(new ApiResponse<>(false, ex.getMessage(), null, ex.getErrors())
84+
);
85+
}
7786
}

0 commit comments

Comments
 (0)