Skip to content

[feat] #128 포인트 차감 기능 구현 및 트랜잭션 타입 분기 처리#129

Merged
2hyunjinn merged 2 commits intomainfrom
feat/#128
May 14, 2025
Merged

[feat] #128 포인트 차감 기능 구현 및 트랜잭션 타입 분기 처리#129
2hyunjinn merged 2 commits intomainfrom
feat/#128

Conversation

@2hyunjinn
Copy link
Copy Markdown
Member

@2hyunjinn 2hyunjinn commented May 14, 2025

📌 PR 제목

[feat] #128 포인트 차감 기능 구현 및 트랜잭션 타입 분기 처리

📌 PR 내용

  • 포인트 트랜잭션에 CREDIT / DEBIT 타입 분기 처리 추가
  • 포인트 차감 기능(dischargePoint) 구현
  • 잔여 포인트가 부족한 경우 예외 처리 추가
  • 관련 테스트 코드 수정 및 분기 케이스 커버

🛠 작업 내용

  • 포인트 차감 기능 구현
  • 트랜잭션 타입(CREDIT / DEBIT) 분기 처리
  • 포인트 차감 시 잔액 부족 체크
  • 테스트 코드 수정 및 추가

🔍 관련 이슈

Closes #128

📸 스크린샷 (Optional)

image

📚 레퍼런스 (Optional)

트랜잭션 타입 분기 처리는 기존 TransactionType enum 기반으로 처리하였습니다.

Summary by CodeRabbit

  • New Features
    • Added support for both crediting and debiting participant points in the point management system.
    • Users can now specify the transaction type (credit or debit) when adjusting points.
  • Bug Fixes
    • Improved validation to prevent debiting more points than available.
  • Tests
    • Updated tests to cover the new transaction type parameter for point adjustments.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented May 14, 2025

Walkthrough

The changes introduce support for both credit and debit point transactions by adding a TransactionType field to RechargePointRequest, updating the PointFacade logic to branch based on this type, and implementing a new dischargePoint method in the service layer. Corresponding tests are updated to include the transaction type.

Changes

Files/Paths Change Summary
src/main/java/org/festimate/team/api/point/dto/RechargePointRequest.java Added a TransactionType type field to the record and updated the constructor accordingly.
src/main/java/org/festimate/team/api/facade/PointFacade.java Modified rechargePoints to branch on TransactionType, calling either rechargePoint or dischargePoint.
src/main/java/org/festimate/team/domain/point/service/PointService.java
src/main/java/org/festimate/team/domain/point/service/impl/PointServiceImpl.java
Added and implemented the dischargePoint method for debiting points from a participant.
src/test/java/org/festimate/team/api/facade/PointFacadeTest.java Updated tests to construct RechargePointRequest with the new TransactionType parameter.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PointFacade
    participant PointService

    User->>PointFacade: rechargePoints(RechargePointRequest)
    PointFacade->>PointService: validateFestivalAndHost()
    alt TransactionType is CREDIT
        PointFacade->>PointService: rechargePoint(participant, amount)
    else TransactionType is DEBIT
        PointFacade->>PointService: dischargePoint(participant, amount)
    end
Loading

Possibly related PRs

Suggested labels

feat

Poem

A rabbit hopped with points to spare,
Now credits and debits are handled with care.
With a type in each request,
The service does its best—
To balance the books, fair and square!
🐇💰

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Copy Markdown

Test Results

45 tests   45 ✅  1s ⏱️
10 suites   0 💤
10 files     0 ❌

Results for commit 9c089f3.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🔭 Outside diff range comments (2)
src/test/java/org/festimate/team/api/facade/PointFacadeTest.java (1)

98-113: 🛠️ Refactor suggestion

Add test cases for the new discharge functionality.

While you've updated existing tests to use TransactionType.CREDIT, there are no tests for the new discharge (debit) functionality. Consider adding tests that verify point discharge operations work correctly, including validation of insufficient points.

For example, add a test like:

@Test
@DisplayName("포인트 차감 성공 (호스트 권한)")
void dischargePoints_success() {
    // given
    RechargePointRequest request = new RechargePointRequest(TransactionType.DEBIT, 200L, 5);
    
    when(userService.getUserByIdOrThrow(1L)).thenReturn(host);
    when(festivalService.getFestivalByIdOrThrow(100L)).thenReturn(festival);
    when(festivalService.isHost(host, festival)).thenReturn(true);
    when(participantService.getParticipantById(200L)).thenReturn(participant);
    
    // when
    pointFacade.rechargePoints(1L, 100L, request);
    
    // then
    verify(pointService).dischargePoint(participant, 5);
}

@Test
@DisplayName("포인트 차감 실패 - 잔액 부족")
void dischargePoints_insufficientPoints_throws() {
    // given
    RechargePointRequest request = new RechargePointRequest(TransactionType.DEBIT, 200L, 5);
    
    when(userService.getUserByIdOrThrow(1L)).thenReturn(host);
    when(festivalService.getFestivalByIdOrThrow(100L)).thenReturn(festival);
    when(festivalService.isHost(host, festival)).thenReturn(true);
    when(participantService.getParticipantById(200L)).thenReturn(participant);
    when(pointService.dischargePoint(participant, 5)).thenThrow(new FestimateException(ResponseError.INSUFFICIENT_POINTS));
    
    // expect
    assertThatThrownBy(() ->
            pointFacade.rechargePoints(1L, 100L, request)
    ).isInstanceOf(FestimateException.class);
}
src/main/java/org/festimate/team/api/facade/PointFacade.java (1)

45-61: 🛠️ Refactor suggestion

Request validation for negative point values is missing.

The current implementation doesn't validate that point values are positive. For DEBIT transactions, a negative value would effectively become a credit, and vice versa. Consider adding validation to ensure point values are always positive, improving transaction integrity.

 @Transactional
 public void rechargePoints(Long userId, Long festivalId, RechargePointRequest request) {
     User user = userService.getUserByIdOrThrow(userId);
     Festival festival = festivalService.getFestivalByIdOrThrow(festivalId);
     isHost(user, festival);

     Participant participant = participantService.getParticipantById(request.participantId());
     if (participant.getFestival() != festival) {
         throw new FestimateException(ResponseError.FORBIDDEN_RESOURCE);
     }
+    
+    if (request.point() <= 0) {
+        throw new FestimateException(ResponseError.INVALID_INPUT_VALUE, "Point value must be positive");
+    }

     if(request.type().equals(TransactionType.CREDIT)) {
         pointService.rechargePoint(participant, request.point());
     }else if (request.type().equals(TransactionType.DEBIT)) {
         pointService.dischargePoint(participant, request.point());
     }
 }
🧹 Nitpick comments (3)
src/main/java/org/festimate/team/domain/point/service/impl/PointServiceImpl.java (1)

57-66: Consider refactoring to reduce code duplication.

The dischargePoint method is correctly implemented and checks for sufficient points before proceeding. However, there's significant code duplication between this method and the usePoint method. Both methods check for sufficient points and create a debit transaction.

Consider refactoring to eliminate duplication:

@Transactional
@Override
public void usePoint(Participant participant) {
-   int totalPoint = getTotalPointByParticipant(participant);
-   if (totalPoint < 1) {
-       throw new FestimateException(ResponseError.INSUFFICIENT_POINTS);
-   }
-
-   Point pointUsage = createPointTransaction(participant, 1, TransactionType.DEBIT);
-   pointRepository.save(pointUsage);
+   dischargePoint(participant, 1);
}

@Transactional
@Override
public void dischargePoint(Participant participant, int amount) {
    int totalPoint = getTotalPointByParticipant(participant);
    if (totalPoint < amount) {
        throw new FestimateException(ResponseError.INSUFFICIENT_POINTS);
    }
    Point pointUsage = createPointTransaction(participant, amount, TransactionType.DEBIT);
    pointRepository.save(pointUsage);
}
src/main/java/org/festimate/team/api/facade/PointFacade.java (2)

55-60: Consider renaming method to better reflect its dual purpose.

The method name rechargePoints now handles both crediting and debiting points, which makes it slightly misleading. Consider renaming to something more generic like processPointTransaction to better reflect its expanded functionality.

Additionally, there's no default case handling for potential future transaction types. Consider adding an else clause with appropriate error handling.

-public void rechargePoints(Long userId, Long festivalId, RechargePointRequest request) {
+public void processPointTransaction(Long userId, Long festivalId, RechargePointRequest request) {
 if(request.type().equals(TransactionType.CREDIT)) {
     pointService.rechargePoint(participant, request.point());
 }else if (request.type().equals(TransactionType.DEBIT)) {
     pointService.dischargePoint(participant, request.point());
+}else {
+    throw new FestimateException(ResponseError.INVALID_INPUT_VALUE, "Unsupported transaction type");
 }

36-43: Consistent method naming across facade and service layer.

For maintainability, ensure that the service method names are consistently aligned with the facade. If you rename the facade method to processPointTransaction, consider similar naming conventions in the service layer for clarity.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 83a63d2 and 9c089f3.

📒 Files selected for processing (5)
  • src/main/java/org/festimate/team/api/facade/PointFacade.java (2 hunks)
  • src/main/java/org/festimate/team/api/point/dto/RechargePointRequest.java (1 hunks)
  • src/main/java/org/festimate/team/domain/point/service/PointService.java (1 hunks)
  • src/main/java/org/festimate/team/domain/point/service/impl/PointServiceImpl.java (2 hunks)
  • src/test/java/org/festimate/team/api/facade/PointFacadeTest.java (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: test
🔇 Additional comments (6)
src/main/java/org/festimate/team/domain/point/service/PointService.java (1)

17-19: LGTM! New functionality added correctly.

The dischargePoint method is a logical addition to support debit transactions, complementing the existing rechargePoint method. The @Transactional annotation ensures data integrity during point deduction operations.

src/test/java/org/festimate/team/api/facade/PointFacadeTest.java (3)

10-10: LGTM! Import added for new functionality.

The import for TransactionType has been correctly added to support the updated request structure.


119-119: LGTM! Updated to include transaction type.

The RechargePointRequest has been correctly updated to include TransactionType.CREDIT.


137-137: LGTM! Updated to include transaction type.

The RechargePointRequest has been correctly updated to include TransactionType.CREDIT.

src/main/java/org/festimate/team/api/facade/PointFacade.java (2)

10-10: Good addition of TransactionType import for the new functionality.

The addition of this import is appropriate for the new transaction type handling.


45-61:

Details

✅ Verification successful

Verify sufficient point balance is checked in the service layer.

While not visible in this file, make sure that the dischargePoint method in the service layer validates that the participant has sufficient points before deducting them to prevent negative balances.


🏁 Script executed:

#!/bin/bash
# Verify that the service implementation checks for sufficient points
rg -A 10 "dischargePoint" --include="*.java" | grep -i "sufficient\|balance\|enough"

Length of output: 526


The previous ripgrep invocation used an unsupported flag. Let’s re-run the search correctly to locate and inspect the dischargePoint implementation:


🏁 Script executed:

#!/bin/bash
# Find all dischargePoint implementations/usages in Java files with context
rg -n "dischargePoint" -g "*.java" -A5

Length of output: 1774


Balance validation already in place
The PointServiceImpl.dischargePoint method (src/main/java/org/festimate/team/domain/point/service/impl/PointServiceImpl.java:59–63) retrieves the participant’s total points and throws a FestimateException(ResponseError.INSUFFICIENT_POINTS) if amount exceeds the balance. No further checks are needed here.

@2hyunjinn 2hyunjinn merged commit fea4163 into main May 14, 2025
4 checks passed
@2hyunjinn 2hyunjinn changed the title Feat/#128 [feat] #128 포인트 차감 기능 구현 및 트랜잭션 타입 분기 처리 May 15, 2025
@2hyunjinn 2hyunjinn self-assigned this May 15, 2025
@2hyunjinn 2hyunjinn added the feat Extra attention is needed label May 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat Extra attention is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 포인트 충전/차감 기능 구현

1 participant