Skip to content

feat: 입고 목록 조회 기능 구현#85

Merged
JoonKyoLee merged 6 commits intomainfrom
feat/get-receipt-list
Nov 23, 2025
Merged

feat: 입고 목록 조회 기능 구현#85
JoonKyoLee merged 6 commits intomainfrom
feat/get-receipt-list

Conversation

@JoonKyoLee
Copy link
Contributor

@JoonKyoLee JoonKyoLee commented Nov 23, 2025

✨ 작업 내용

  • 입고 목록 조회 기능 구현

📝 적용 범위

  • /receipt

📌 참고 사항

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 입고 목록 조회 기능 추가
    • 페이지네이션 지원으로 대량의 입고 데이터 관리 용이
    • 발주처, 입고 상태, 기간으로 입고 목록 필터링 가능
    • 다양한 필터 조합을 통한 유연한 검색 지원

✏️ Tip: You can customize this high-level summary in your review settings.

@JoonKyoLee JoonKyoLee self-assigned this Nov 23, 2025
@JoonKyoLee JoonKyoLee added the enhancement New feature or request label Nov 23, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 23, 2025

Walkthrough

입고 목록 조회 기능을 구현했습니다. 페이징, 발주처 필터링, 상태 필터링, 날짜 범위 필터링을 지원하며, 컨트롤러-서비스-저장소 계층에 걸쳐 엔드포인트와 데이터베이스 쿼리를 추가하고 테스트 커버리지를 확대했습니다.

Changes

Cohort / File(s) 변경 요약
메시지 및 응답 상수
src/main/java/com/almang/inventory/global/api/SuccessMessage.java
GET_RECEIPT_LIST_SUCCESS("입고 목록 조회 성공") 상수 추가
API 컨트롤러 계층
src/main/java/com/almang/inventory/receipt/controller/ReceiptController.java
GET /api/v1/receipt 엔드포인트 추가: 페이지, 사이즈, vendorId, status, fromDate, endDate 파라미터 지원
데이터 접근 계층
src/main/java/com/almang/inventory/receipt/repository/ReceiptRepository.java
4개의 페이지네이션 쿼리 메서드 추가: 발주처·상태·날짜 범위 조합 필터링 지원 (findAllByStoreIdAndReceiptDateBetween, findAllByStoreIdAndStatusAndReceiptDateBetween, 등)
비즈니스 로직 계층
src/main/java/com/almang/inventory/receipt/service/ReceiptService.java
getReceiptList() 서비스 메서드 추가: 필터 조합별 저장소 쿼리 위임 및 PageResponse 반환
컨트롤러 테스트
src/test/java/com/almang/inventory/receipt/controller/ReceiptControllerTest.java
목록 조회 엔드포인트에 대한 성공/사용자 없음/접근 거부 시나리오 테스트 추가
서비스 테스트
src/test/java/com/almang/inventory/receipt/service/ReceiptServiceTest.java
필터 없음, 발주처 필터, 날짜 범위 필터 각각에 대한 3개 테스트 케이스 추가

Sequence Diagram

sequenceDiagram
    participant Client
    participant Controller as ReceiptController
    participant Service as ReceiptService
    participant Repository as ReceiptRepository
    participant DB as Database

    Client->>Controller: GET /api/v1/receipt<br/>(page, size, vendorId,<br/>status, fromDate, endDate)
    
    rect rgb(200, 240, 255)
    Note over Controller: 요청 검증 & 인증<br/>(AuthenticationPrincipal)
    end
    
    Controller->>Service: getReceiptList(userId, page,<br/>size, vendorId, status,<br/>fromDate, toDate)
    
    rect rgb(240, 255, 240)
    Note over Service: 필터 조합별<br/>분기 처리
    end
    
    Service->>Service: findReceiptsByFilter()<br/>(4가지 케이스)<br/>- 필터 없음<br/>- 상태만<br/>- 발주처만<br/>- 발주처+상태
    
    Service->>Repository: findAllByStoreId*<br/>(해당 필터 쿼리 선택)
    
    Repository->>DB: SQL Query with pagination
    DB-->>Repository: Page<Receipt>
    
    Repository-->>Service: Page<Receipt>
    
    rect rgb(255, 250, 240)
    Note over Service: Receipt → ReceiptResponse<br/>매핑 및 PageResponse 구성
    end
    
    Service-->>Controller: PageResponse<ReceiptResponse>
    
    Controller-->>Client: ApiResponse<br/>(GET_RECEIPT_LIST_SUCCESS,<br/>PageResponse)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 분

추가 검토 주요 대상:

  • ReceiptService.findReceiptsByFilter(): 4가지 필터 조합 분기 로직이 정확히 구현되었는지, 누락되거나 중복된 경우가 없는지 확인 필요 (특히 Pageable 객체 전달 여부)
  • Repository 쿼리 메서드 네이밍: findAllByStoreIdAndOrderVendorIdAndReceiptDateBetween() 등 메서드 명이 Spring Data JPA 규칙과 정확하게 일치하는지, 실제 쿼리가 의도대로 생성되는지 검증
  • 날짜 범위 기본값 처리: 조회 기간이 제공되지 않을 때 기본값 계산 로직이 명시되어 있는지, 무한 조회로부터 보호되는지 확인
  • 테스트 케이스 경계값: 날짜 경계(fromDate = endDate), 페이지 번호 0/음수 등 엣지 케이스에 대한 테스트 추가 검토

Possibly related issues

  • [FEAT] 입고 조회 기능 구현 #76: 이 PR이 정확히 "입고 목록 조회 기능" 구현 요구사항을 이행합니다. 벡터 검색 결과와 일치하며, 백엔드 엔드포인트, 서비스 메서드, 저장소 쿼리, DTO, 성공 메시지, 테스트 모두 포함합니다.

Possibly related PRs

Poem

📦 목록을 조회하니,
페이지 나누고 필터 걸어,
발주처, 상태, 날짜로 재분류 ✨
저장소 쿼리 네 가지 조합,
테스트 믿음이 함께하니—
입고 관리의 새 경지! 🚀

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경 사항의 핵심을 명확하게 반영하고 있으며, 입고 목록 조회 기능 구현이라는 주요 작업을 정확하게 설명합니다.
Description check ✅ Passed PR 설명이 제공된 템플릿 구조를 따르고 있으며, 작업 내용, 적용 범위, 참고 사항 섹션이 모두 포함되어 있습니다.
Linked Issues check ✅ Passed 코드 변경사항이 이슈 #75에서 정의한 입고 목록 조회 기능 구현 요구사항을 완전히 충족합니다. 페이지네이션, 필터링(발주처, 상태, 날짜 범위) 기능이 모두 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 입고 목록 조회 기능 구현이라는 정의된 범위 내에 있으며, 불필요한 변경이나 기능이 없습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/get-receipt-list

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@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: 0

🧹 Nitpick comments (5)
src/main/java/com/almang/inventory/receipt/repository/ReceiptRepository.java (1)

4-9: 입고 목록용 파생 쿼리 메서드 구성이 도메인/패턴과 잘 맞습니다

  • storeId + receiptDate Between 를 기준으로 하고, ReceiptStatus / order.vendor.id 조합으로 4가지 메서드를 나눈 구조가 직관적입니다.
  • OrderRepository 쪽의 findAllByStoreIdAnd...CreatedAtBetween 패턴과도 일관되어, 서비스 계층 코드 가독성이 좋아집니다.
  • ReceiptStatus, LocalDate, Pageable 타입 사용도 Spring Data JPA 파생 쿼리 규칙에 맞게 정리되어 있습니다 (공식 문서의 Derived Query Methods 섹션 참고하시면 좋습니다).

향후 필터 조건이 더 늘어날 경우에는, 지금과 같은 메서드 폭발을 막기 위해 QueryDSL, Specification, 혹은 동적 쿼리 빌더로의 전환도 고려해 볼 수 있겠습니다만, 현재 범위에서는 이 정도가 가장 단순하고 명확합니다.

Also applies to: 16-26

src/test/java/com/almang/inventory/receipt/controller/ReceiptControllerTest.java (1)

3-12: 입고 목록 조회 컨트롤러 테스트가 핵심 시나리오를 잘 잡았습니다

  • 성공 케이스에서 PageResponse를 직접 구성해 두고, status, message, data.totalElements, content[*].receiptId 까지 검증한 부분이 좋습니다. “API 스펙이 정확히 이렇게 생겼다”는 계약이 잘 드러납니다.
  • 두 가지 에러 케이스(사용자 없음, 상점 접근 거부)에 대해 HTTP status와 ErrorCodehttpStatus/message를 그대로 검증한 것도 컨트롤러 예외 매핑을 잘 보호하고 있습니다.

개선 아이디어(선택 사항):

  • 현재 테스트는 페이지/사이즈만 넘기고 있고, vendorId, receiptStatus, fromDate, endDate 파라미터가 실제로 바인딩되는지는 검증하지 않습니다.
    • 예를 들어 아래와 같이 필터 파라미터를 포함한 테스트를 하나 추가하고,
    • Mockito.verify(receiptService).getReceiptList(userId, page, size, vendorId, status, fromDate, toDate);
      형태로 정확한 인자가 전달되는지도 함께 확인하면, 컨트롤러–서비스 사이 계약이 더 견고해집니다.
  • 이 부분은 Spring MVC의 @RequestParam 바인딩 동작을 확인하는 좋은 예제가 되므로, 필요하면 Spring 공식 레퍼런스의 Web MVC – Method Arguments and Return Values 섹션도 같이 참고해 보시면 좋겠습니다.

Also applies to: 404-500

src/test/java/com/almang/inventory/receipt/service/ReceiptServiceTest.java (1)

6-6: 입고 목록 조회 서비스 테스트가 필터 동작을 잘 검증하고 있습니다

  • 필터 없음 테스트에서:
    • 동일 상점의 두 입고와 다른 상점의 입고를 만들어 두고,
    • 응답의 storeId가 하나의 상점 ID만 포함되는지, receiptIdreceipt1/receipt2만 있는지 확인하는 구조가 멀티테넌시 스코프 검증에 좋습니다.
  • 발주처 필터 테스트에서:
    • 서로 다른 vendor 2개를 두고, vendor1만 필터링했을 때 1건만 나오고 그게 기대한 receipt/order 인지 확인하는 흐름이 명확합니다.
  • 기간 필터 테스트minusDays(7) / now()로 데이터를 분리하고, fromDate=now-1, toDate=now로 최근 건만 걸러내는지 잘 확인하고 있습니다. 테스트 시나리오 구성이 교과서적으로 깔끔합니다.

보완 아이디어(권장):

  • 프로덕션 코드의 findReceiptsByFilter는 4가지 조합(필터 없음 / 상태만 / 발주처만 / 발주처+상태)을 가지는데, 현재 테스트는 “필터 없음 / 발주처 / 기간”만 다룹니다.
    • ReceiptStatus 기준 필터, 그리고 vendorId + status 동시 필터 케이스도 각각 한 개씩 추가해 두면 분기 전체가 보호되어 유지보수 시 안심하기 좋습니다.
  • 입고 엔티티/아이템을 만드는 코드가 여러 테스트에 반복되는데, 필요하다면
    • newReceiptWithItems(Store, Order, LocalDate, int totalBoxCount) 정도의 테스트용 헬퍼로 추출해 중복을 줄일 수 있습니다.
    • 다만 지금도 각 테스트가 “어떤 상황을 위한 데이터인지”를 바로 읽을 수 있어서, 가독성과 DRY 사이에서 현재 상태도 충분히 괜찮은 편입니다.

Also applies to: 431-636

src/main/java/com/almang/inventory/receipt/service/ReceiptService.java (1)

3-7: 입고 목록 조회 서비스 로직이 Order 쪽 패턴과 잘 정렬되어 있습니다

좋은 점:

  • getReceiptList에서
    • findUserByIdstore 획득 → 로그 → PaginationUtil.createPageRequest(page, size, "createdAt")findReceiptsByFilterPageResponse.from 의 흐름이 OrderService의 getOrderList와 거의 동일해 일관성이 높습니다.
    • @Transactional(readOnly = true) 적용으로 조회 성격도 명확히 표현돼 있습니다.
  • findReceiptsByFilter:
    • fromDate/toDate가 없을 때 1970-01-01 ~ LocalDate.now() 범위를 기본값으로 두어 “날짜 필터 미지정=전체(과거~오늘)” 동작이 직관적입니다.
    • vendorId / status 조합을 boolean 플래그로 나눠 4가지 케이스(없음 / 상태만 / 발주처만 / 발주처+상태)를 명확히 분기한 구조라, 나중에 읽을 때도 조건 해석이 쉽습니다.
    • Receipt.receiptDateLocalDate 타입인 점을 고려해, 별도의 LocalDateTime 변환 없이 Between(LocalDate, LocalDate)를 사용하는 것도 도메인에 잘 맞습니다.

개선 제안(권장, 필수 아님):

  1. 정렬 기준 컬럼 재검토

    • 현재 PaginationUtil.createPageRequest(page, size, "createdAt") 로 정렬하고 있는데, 비즈니스적으로 “입고 목록” 화면에서 더 자연스러운 기준이 createdAt인지 receiptDate인지 한 번 고민해 볼 만합니다.
    • 실제 사용자가 “입고 처리일(=receiptDate)” 순으로 보고 싶어 한다면, sortBy"receiptDate"로 바꾸는 것도 UX 측면에서 더 맞을 수 있습니다. (반대로 “생성 시각 기준 정렬”이 일관성 목표라면 지금도 괜찮습니다.)
    • 이 부분은 Spring Data JPA의 PageRequest 정렬 동작과 직결되므로, 팀 내에서 일관된 기준을 정해 두면 좋습니다.
  2. 날짜 범위 유효성 검증

    • 현재는 fromDate > toDate 인 경우에도 그냥 Between(startDate, endDate)로 넘어가고, 결과가 빈 목록이 되는 식으로 동작합니다.
    • 사용자가 잘못된 범위를 넣은 경우를 명시적으로 막고 싶다면,
      • fromDatetoDate가 모두 null이 아니고, fromDate.isAfter(toDate) 이면 예외를 던지거나,
      • 두 값을 swap해서 자동 교정하는 방식도 고려할 수 있습니다.
    • 이건 도메인 정책 문제라 반드시 필요하진 않지만, 나중에 혼동을 줄이는 데 도움이 됩니다.
  3. 중복 로직 정리

    • OrderService의 findOrdersByFilter와 ReceiptService의 findReceiptsByFilter가 개념적으로 거의 동일한 구조(날짜 기본값, vendor/status 조합 분기)를 가지므로,
      • 장기적으로는 날짜 범위 계산 부분만이라도 작은 유틸(예: DateRangeUtil)로 빼두면 정책 변경 시 동시 수정할 곳을 줄일 수 있습니다.
    • 다만 지금도 코드 길이가 과도하지는 않아서, 리팩터링은 여유 있을 때 진행해도 됩니다.

Also applies to: 21-28, 89-105, 179-213

src/main/java/com/almang/inventory/receipt/controller/ReceiptController.java (1)

4-13: 입고 목록 조회 엔드포인트가 기존 Order/Vendor API와 잘 맞습니다

  • @GetMapping 시그니처가 OrderController의 목록 조회와 거의 동일해, 클라이언트 입장에서 /order / /receipt API를 동일한 감각으로 사용할 수 있다는 점이 좋습니다.
    • page, size, vendorId, receiptStatus, fromDate, endDate 파라미터 구성이 명확합니다.
  • @AuthenticationPrincipaluserId를 꺼내고, 서비스에 그대로 넘긴 뒤 SuccessMessage.GET_RECEIPT_LIST_SUCCESS와 함께 ApiResponse<PageResponse<ReceiptResponse>>로 감싸는 패턴도 기존 컨트롤러들과 일관됩니다.
  • Swagger @Operation으로 요약/설명을 붙여 둔 것도 API 문서화 측면에서 좋습니다. 한 줄 요약이 깔끔하네요.

개선 제안(선택 사항):

  1. 메서드 이름 정리

    • 현재 메서드 이름이 getOrderList인데, ReceiptController 안에서는 getReceiptList 정도가 더 자연스럽고, 서비스 메서드 이름(getReceiptList)과도 일치합니다.
    • IDE 리네임으로 쉽게 바꿀 수 있는 부분이라, 나중에 검색/탐색 시 혼동을 줄이기 위해 정리해 두면 좋겠습니다.
  2. Swagger 설명 보강

    • 필요하다면 description에 예시 쿼리(?page=1&size=20&vendorId=...&receiptStatus=...&fromDate=...&endDate=...)를 간단히 추가해 두면, 프론트/외부 소비자가 파라미터 조합을 이해하는 데 도움이 됩니다.
    • 이는 OpenAPI 문서 활용성을 높이는 정도의 개선이라, 여유 있을 때 진행해도 충분합니다.

Also applies to: 21-21, 75-95

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40cb765 and 80ff69d.

📒 Files selected for processing (6)
  • src/main/java/com/almang/inventory/global/api/SuccessMessage.java (1 hunks)
  • src/main/java/com/almang/inventory/receipt/controller/ReceiptController.java (3 hunks)
  • src/main/java/com/almang/inventory/receipt/repository/ReceiptRepository.java (1 hunks)
  • src/main/java/com/almang/inventory/receipt/service/ReceiptService.java (4 hunks)
  • src/test/java/com/almang/inventory/receipt/controller/ReceiptControllerTest.java (2 hunks)
  • src/test/java/com/almang/inventory/receipt/service/ReceiptServiceTest.java (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-22T18:12:13.161Z
Learnt from: JoonKyoLee
Repo: almang2/inventory-server PR: 66
File: src/main/java/com/almang/inventory/order/domain/OrderItem.java:41-53
Timestamp: 2025-11-22T18:12:13.161Z
Learning: In the almang2/inventory-server repository, OrderItem entity update methods (updateQuantity, updatePrice in src/main/java/com/almang/inventory/order/domain/OrderItem.java) do not require null checks because OrderService will validate parameters before calling these update methods, following the same pattern as Product entity updates.
<!--

Applied to files:

  • src/main/java/com/almang/inventory/receipt/service/ReceiptService.java
🧬 Code graph analysis (2)
src/main/java/com/almang/inventory/receipt/service/ReceiptService.java (3)
src/main/java/com/almang/inventory/global/util/PaginationUtil.java (1)
  • PaginationUtil (7-17)
src/main/java/com/almang/inventory/order/service/OrderService.java (2)
  • Transactional (82-97)
  • findOrdersByFilter (264-301)
src/main/java/com/almang/inventory/order/repository/OrderRepository.java (1)
  • OrderRepository (10-31)
src/main/java/com/almang/inventory/receipt/controller/ReceiptController.java (3)
src/main/java/com/almang/inventory/vendor/controller/VendorController.java (1)
  • Slf4j (30-136)
src/main/java/com/almang/inventory/receipt/domain/Receipt.java (1)
  • Entity (13-77)
src/main/java/com/almang/inventory/order/controller/OrderController.java (1)
  • Slf4j (33-155)
🔇 Additional comments (1)
src/main/java/com/almang/inventory/global/api/SuccessMessage.java (1)

50-55: 입고 목록 성공 메시지 상수 추가가 일관성 있게 잘 들어갔습니다

  • RECEIPT 영역의 다른 상수들과 네이밍(GET_RECEIPT_LIST_SUCCESS)과 한글 메시지가 잘 맞습니다.
  • 컨트롤러에서 목록 조회 응답에 사용하기에 의미도 명확합니다.

@JoonKyoLee JoonKyoLee merged commit 8b5052e into main Nov 23, 2025
1 check passed
@JoonKyoLee JoonKyoLee deleted the feat/get-receipt-list branch November 24, 2025 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 입고 목록 조회 기능 구현

1 participant