Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/opixxx step3 #27

Merged
merged 16 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.c4marathon.assignment.global.util;

import java.security.SecureRandom;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class SettlementUtil {
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

배워갑니다~👍


public static int getRandomInt(int range) {
return SECURE_RANDOM.nextInt(range);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.c4marathon.assignment.settlement.domain;

import static jakarta.persistence.FetchType.*;

import java.util.ArrayList;
import java.util.List;

import org.c4marathon.assignment.global.entity.BaseEntity;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Settlement extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "settlement_id")
private Long id;

private Long requestAccountId; //정산 요청한 계좌 ID

private int totalAmount; //총 정산 금액

private int amount; //내 정산 금액

@Enumerated(EnumType.STRING)
private SettlementType type;

@OneToMany(mappedBy = "settlement", fetch = LAZY, cascade = CascadeType.ALL)
private List<SettlementDetail> settlementDetails = new ArrayList<>();

@Builder
private Settlement(Long requestAccountId, int totalAmount, SettlementType type) {
this.requestAccountId = requestAccountId;
this.totalAmount = totalAmount;
this.type = type;
}

public static Settlement create(Long requestAccountId, int totalAmount, SettlementType type) {
return Settlement.builder()
.requestAccountId(requestAccountId)
.totalAmount(totalAmount)
.type(type)
.build();
}

public void setAmount(int amount) {
this.amount = amount;
}

public void addSettlementDetail(SettlementDetail settlementDetail) {
this.settlementDetails.add(settlementDetail);
settlementDetail.setSettlement(this);

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.c4marathon.assignment.settlement.domain;

import org.c4marathon.assignment.global.entity.BaseEntity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class SettlementDetail extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "settlement_detail_id")
private Long id;

private Long accountId;

private int amount;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "settlement_id", nullable = false)
private Settlement settlement;

@Builder
private SettlementDetail(Settlement settlement, Long accountId, int amount) {
this.settlement = settlement;
this.accountId = accountId;
this.amount = amount;
}

public static SettlementDetail create(Settlement settlement, Long accountId, int amount) {
SettlementDetail settlementDetail = SettlementDetail.builder()
.accountId(accountId)
.amount(amount)
.build();
settlement.addSettlementDetail(settlementDetail);
return settlementDetail;
}

public void setSettlement(Settlement settlement) {
this.settlement = settlement;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.c4marathon.assignment.settlement.domain;

public enum SettlementType {
EQUAL,
RANDOM
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.c4marathon.assignment.settlement.domain.repository;

import java.util.List;

import org.c4marathon.assignment.settlement.domain.SettlementDetail;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface SettlementDetailRepository extends JpaRepository<SettlementDetail, Long> {

@Query("""
SELECT sd
FROM SettlementDetail sd
JOIN FETCH sd.settlement s
WHERE sd.accountId = :accountId
""")
List<SettlementDetail> findByAccountId(@Param("accountId") Long accountId);

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.c4marathon.assignment.settlement.domain.repository;

import java.util.List;

import org.c4marathon.assignment.settlement.domain.Settlement;
import org.springframework.data.jpa.repository.JpaRepository;

public interface SettlementRepository extends JpaRepository<Settlement, Long> {
List<Settlement> findByRequestAccountId(Long requestAccountId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.c4marathon.assignment.settlement.dto;

public record ReceivedSettlementResponse(
Long settlementId,
Long requestAccountId,
int totalAmount,
Long myAccountId,
int mySettlementAmount
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.c4marathon.assignment.settlement.dto;

public record SettlementDetailInfo(
Long settlementDetailId,
Long accountId,
int amount
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.c4marathon.assignment.settlement.dto;

import java.util.List;

import org.c4marathon.assignment.settlement.domain.SettlementType;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;

public record SettlementRequest(

@PositiveOrZero
@Max(value = 100, message = "100명까지 정산이 가능합니다.")
int totalNumber,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

totalNumber가 0이라면 이후 정산 금액을 계산하는 과정(getRandomSettlement, getEquallySettlement)에서 의도하지 않은 결과나 오류가 발생할 것 같아요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇겠네요 @min으로 최소 정산 인원을 검증하도록 변경하겠습니다


@PositiveOrZero
int totalAmount,

@NotNull(message = "정산 인원을 추가해주세요.")
List<Long> accountIds,

@NotNull(message = "정산 타입을 선택해주세요.")
SettlementType type

) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.c4marathon.assignment.settlement.dto;

import java.util.List;


public record SettlementResponse(
Long settlementId,
Long requestAccountId,
int totalAmount,
List<SettlementDetailInfo> members
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.c4marathon.assignment.settlement.presentation;

import java.util.List;

import org.c4marathon.assignment.global.annotation.Login;
import org.c4marathon.assignment.global.session.SessionMemberInfo;
import org.c4marathon.assignment.settlement.dto.ReceivedSettlementResponse;
import org.c4marathon.assignment.settlement.dto.SettlementRequest;
import org.c4marathon.assignment.settlement.dto.SettlementResponse;
import org.c4marathon.assignment.settlement.service.SettlementService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class SettlementController {
private final SettlementService settlementService;

@PostMapping("/settle")
public ResponseEntity<Void> settle(
@Login SessionMemberInfo loginMember,
@RequestBody @Valid SettlementRequest request
) {
settlementService.createSettlement(loginMember.accountId(), request);
return ResponseEntity.ok().build();
}

@GetMapping("/settlements/requested")
public ResponseEntity<List<SettlementResponse>> getRequestedSettlements(@Login SessionMemberInfo loginMember) {
return ResponseEntity.ok().body(settlementService.getRequestedSettlements(loginMember.accountId()));
}

@GetMapping("/settlements/received")
public ResponseEntity<List<ReceivedSettlementResponse>> getReceivedSettlements(@Login SessionMemberInfo loginMember) {
return ResponseEntity.ok().body(settlementService.getReceivedSettlements(loginMember.accountId()));
}
}
Loading