Skip to content

Commit

Permalink
Unit test for transaction (#127)
Browse files Browse the repository at this point in the history
* add test

* add test

* fix duplicate

* fix in out to vietnamese

* fix choose a user to vietnamese

* fix validation and to vietnamese

* fix validation to vietnamese

* fix default is admin

* fix edit modal

* add statistic

* fix return active category

* fix checkstyle

* add test

* add test

* fix
  • Loading branch information
VoHoangAn authored Sep 26, 2024
1 parent ac15a18 commit ba92a3d
Show file tree
Hide file tree
Showing 13 changed files with 468 additions and 221 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterAndUntilNow {
String message() default "must be after {value} and before now";
String message() default "Thời gian tạo phải sau 01/01/2020 và trước hiện tại";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String value();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.fjb.sunrise.constraints;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = StringMustBeDigitWithFractionValidator.class)
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface StringMustBeDigitWithFraction {
String message() default "Số tiền phải là chữ số với số thập phân là {fraction}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

int fraction();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.fjb.sunrise.constraints;


import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.util.StringUtils;

public class StringMustBeDigitWithFractionValidator
implements ConstraintValidator<StringMustBeDigitWithFraction, String> {
private int fraction = 0;

@Override
public void initialize(StringMustBeDigitWithFraction constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
fraction = constraintAnnotation.fraction();
}

@Override
public boolean isValid(String string, ConstraintValidatorContext constraintValidatorContext) {
String ignoreComma = string.replaceAll(",", "");
String ignoreDot = ignoreComma.replace(".", "");
if (ignoreDot.chars().allMatch(Character::isDigit)) {
if (fraction > 0) {
int startOfFraction = ignoreComma.indexOf(".");
if (startOfFraction == -1) {
return true;
}
if (ignoreComma.length() - startOfFraction - 1 > fraction) {
return false;
}
}
return true;
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package com.fjb.sunrise.controllers;

import static com.fjb.sunrise.utils.Constants.ApiConstant.CATEGORIES;
import static com.fjb.sunrise.utils.Constants.ApiConstant.TRANSACTION_INDEX;
import static com.fjb.sunrise.utils.Constants.ApiConstant.USERS;

import com.fjb.sunrise.dtos.base.DataTableInputDTO;
import com.fjb.sunrise.dtos.requests.CreateOrUpdateTransactionRequest;
import com.fjb.sunrise.dtos.responses.TransactionFullPageResponse;
Expand All @@ -13,6 +9,7 @@
import com.fjb.sunrise.services.CategoryService;
import com.fjb.sunrise.services.TransactionService;
import com.fjb.sunrise.services.UserService;
import com.fjb.sunrise.utils.Constants;
import jakarta.validation.Valid;
import java.text.ParseException;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -42,21 +39,24 @@ public class TransactionController {

@GetMapping("/create")
public String getCreate(@ModelAttribute("request") CreateOrUpdateTransactionRequest request, Model model) {
model.addAttribute(CATEGORIES, categoryService.findCategoryByAdminAndUser());
model.addAttribute(USERS, userService.findAllNormalUser());
return TRANSACTION_INDEX;
model.addAttribute(Constants.ApiConstant.CATEGORIES, categoryService.findCategoryByAdminAndUser());
model.addAttribute(Constants.ApiConstant.USERS, userService.findAllNormalUser());
model.addAttribute(Constants.ApiConstant.STATISTIC, transactionService.statistic());
return Constants.ApiConstant.TRANSACTION_INDEX;
}

@PostMapping("/create")
public String postCreate(@ModelAttribute("request") @Valid CreateOrUpdateTransactionRequest request,
BindingResult result, Model model)
throws ParseException {
model.addAttribute(CATEGORIES, categoryService.findCategoryByAdminAndUser());
model.addAttribute(USERS, userService.findAllNormalUser());
model.addAttribute(Constants.ApiConstant.CATEGORIES, categoryService.findCategoryByAdminAndUser());
model.addAttribute(Constants.ApiConstant.USERS, userService.findAllNormalUser());
model.addAttribute(Constants.ApiConstant.STATISTIC, transactionService.statistic());
if (result.hasErrors()) {
model.addAttribute(CATEGORIES, categoryService.findCategoryByAdminAndUser());
model.addAttribute(USERS, userService.findAllNormalUser());
return TRANSACTION_INDEX;
model.addAttribute(Constants.ApiConstant.CATEGORIES, categoryService.findCategoryByAdminAndUser());
model.addAttribute(Constants.ApiConstant.USERS, userService.findAllNormalUser());
model.addAttribute(Constants.ApiConstant.STATISTIC, transactionService.statistic());
return Constants.ApiConstant.TRANSACTION_INDEX;
}
Transaction transaction = transactionService.create(request);
return "redirect:/transaction/create";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fjb.sunrise.constraints.AfterAndUntilNow;
import com.fjb.sunrise.constraints.StringMustBeDigitWithFraction;
import com.fjb.sunrise.enums.ETrans;
import jakarta.validation.constraints.NotBlank;
import java.io.Serializable;
Expand All @@ -16,6 +17,7 @@
public class CreateOrUpdateTransactionRequest implements Serializable {
private Long id;
@NotBlank(message = "Amount must not be blank")
@StringMustBeDigitWithFraction(fraction = 2)
private String amount;

private ETrans transactionType;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.fjb.sunrise.dtos.responses;

import java.io.Serializable;
import lombok.Data;



@Data
public class StatisticResponse implements Serializable {
private String totalThisYear;
private String totalInputThisYear;
private String totalThisMonth;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
package com.fjb.sunrise.repositories;


import com.fjb.sunrise.enums.ETrans;
import com.fjb.sunrise.models.Transaction;
import java.time.LocalDateTime;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;



public interface TransactionRepository extends JpaRepository<Transaction, Long>,
JpaSpecificationExecutor<Transaction> {

Page<Transaction> findAll(Pageable pageable);

@Query("select sum(t.amount) from Transaction t "
+ "where t.updatedAt between ?1 and ?2")
Double sumAmountInRange(LocalDateTime start, LocalDateTime end);

@Query("select sum(t.amount) from Transaction t "
+ "where t.transactionType = ?1 and t.updatedAt between ?2 and ?3 ")
Double sumTransactionTypeINInThisYear(ETrans transactionType, LocalDateTime start, LocalDateTime end);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fjb.sunrise.dtos.base.DataTableInputDTO;
import com.fjb.sunrise.dtos.requests.CreateOrUpdateTransactionRequest;
import com.fjb.sunrise.dtos.responses.StatisticResponse;
import com.fjb.sunrise.models.Transaction;
import java.text.ParseException;
import org.springframework.data.domain.Page;
Expand All @@ -12,4 +13,6 @@ public interface TransactionService {
Page<Transaction> getTransactionList(DataTableInputDTO payload, String email);

Transaction update(CreateOrUpdateTransactionRequest request) throws ParseException;

StatisticResponse statistic();
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public List<Category> findCategoryByAdminAndUser() {
List<Sort.Order> orders = new ArrayList<>();
orders.add(Sort.Order.asc("owner.role"));
Sort sortOpt = Sort.by(orders);
Specification<Category> specs = findAllByUser();
Specification<Category> specs = findAllForTransaction();
return categoryRepository.findAll(specs, sortOpt);
}

Expand All @@ -169,6 +169,21 @@ private Specification<Category> findAllByUser() {
});
}

private Specification<Category> findAllForTransaction() {
return Specification.where((root, query, builder) -> {
Join<Category, User> userJoin = root.join("owner");
User dbUser = userRepository.findById(getCurrentUserId()).orElseThrow();
if (dbUser.getRole() == ERole.ADMIN) {
return builder.equal(root.get("status"), EStatus.ACTIVE);
}
Predicate hasRoleAdmin = builder.equal(userJoin.get("role"), "ADMIN");
Predicate isOwner = builder.equal(userJoin.get("id"), getCurrentUserId());
Predicate active = builder.equal(root.get("status"), EStatus.ACTIVE);
Predicate or = builder.or(hasRoleAdmin, isOwner);
return builder.and(or, active);
});
}

public Long getCurrentUserId() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
org.springframework.security.core.userdetails.User securityUser =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fjb.sunrise.dtos.base.DataTableInputDTO;
import com.fjb.sunrise.dtos.requests.CreateOrUpdateTransactionRequest;
import com.fjb.sunrise.dtos.responses.StatisticResponse;
import com.fjb.sunrise.enums.ETrans;
import com.fjb.sunrise.models.Category;
import com.fjb.sunrise.models.Transaction;
Expand All @@ -11,8 +12,6 @@
import com.fjb.sunrise.services.TransactionService;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import jakarta.transaction.Transactional;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
Expand All @@ -21,16 +20,7 @@
import java.time.LocalDateTime;
import java.time.Month;
import java.time.Year;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
Expand Down Expand Up @@ -65,12 +55,6 @@ public Transaction create(CreateOrUpdateTransactionRequest request) throws Parse
return transactionRepository.save(transaction);
}

public Transaction findById(Long id) {
return transactionRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("Invalid transaction id")
);
}

@Override
public Page<Transaction> getTransactionList(DataTableInputDTO payload, String email) {
Sort sortOpt = Sort.by(Sort.Direction.ASC, "id");
Expand Down Expand Up @@ -100,9 +84,15 @@ public Page<Transaction> getTransactionList(DataTableInputDTO payload, String em
// "%" + keyword + "%"
specs = specs.and(((root, query, builder) -> {
Join<Transaction, Category> categoryJoin = root.join("category");
String search = payload.getSearch().getOrDefault("value", "").toLowerCase();
if (search.equals("thu")) {
search = "IN";
} else if (search.equals("chi")) {
search = "OUT";
}
Predicate predictTransactionType =
builder.like(builder.lower(root.get("transactionType")), String.format("%%%s%%",
payload.getSearch().getOrDefault("value", "").toLowerCase()));
search.toLowerCase()));
Predicate predictCategory = builder.like(builder.lower(categoryJoin.get("name")),
String.format("%%%s%%",
payload.getSearch().getOrDefault("value", "").toLowerCase()
Expand All @@ -121,7 +111,6 @@ public Transaction update(CreateOrUpdateTransactionRequest request) throws Parse
transaction.setUpdatedAt(request.getCreatedAt());
transaction.setTransactionType(request.getTransactionType());
transaction.setAmount(convertMoneyStringWithCommaToDouble(request.getAmount()));
transaction.setUser(userRepository.findByEmailOrPhone(getCurrentUserName()));
transaction.setCategory(categoryRepository.findById(request.getCategory()).orElse(null));

log.error("update: {}", transaction.toString());
Expand All @@ -130,14 +119,27 @@ public Transaction update(CreateOrUpdateTransactionRequest request) throws Parse
return transaction1;
}

private String changeFormatFromFullDateToMonthDate(LocalDateTime dateTime) throws ParseException {
SimpleDateFormat monthDate = new SimpleDateFormat("dd-MM", Locale.ENGLISH);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");


Date date = sdf.parse(dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
monthDate.format(date);
return monthDate.format(date);
@Override
public StatisticResponse statistic() {
StatisticResponse response = new StatisticResponse();
final LocalDateTime firstDay = getFirstOrLastDateOfThisYear(false);
final LocalDateTime lastDay = getFirstOrLastDateOfThisYear(true);
final LocalDateTime firstDayOfThisMonth = getFirstDayOfThisMonth();


response.setTotalThisMonth(
convertDoubleWithScientificNotationToDouble(
transactionRepository.sumAmountInRange(firstDayOfThisMonth, lastDay)
));

response.setTotalThisYear(
convertDoubleWithScientificNotationToDouble(
transactionRepository.sumAmountInRange(firstDay, lastDay)
));
response.setTotalInputThisYear(convertDoubleWithScientificNotationToDouble(
transactionRepository.sumTransactionTypeINInThisYear(ETrans.IN, firstDay, lastDay)
));
return response;
}

private String convertDoubleWithScientificNotationToDouble(Double amount) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/fjb/sunrise/utils/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ private ApiConstant() {}
public static final String TRANSACTION_INDEX = "transaction/index";
public static final String CATEGORIES = "categories";
public static final String USERS = "users";
public static final String STATISTIC = "statistic";

public static final String AUTH_REDIRECT_LOGIN = "redirect:/auth/login";
public static final String AUTH_VIEW = "auth/loginAndRegister";
Expand Down
Loading

0 comments on commit ba92a3d

Please sign in to comment.