feat: sales API 데이터 레이어 (network/DTO/repository, USE_API 플래그) - #3
Conversation
…플래그) - data/remote: Net(OkHttp+Retrofit+Gson, Bearer 인터셉터), UiState, SalesApi, DTO - data/repo: SalesOrderRepository (arrivals/branchOrders/receivedByMe/receive) - build: BuildConfig BASE_URL/USE_API(gradle property), INTERNET 권한 - 화면 미배선(USE_API 기본 false) → 앱 동작 무변경. 모델 매핑은 후속 PR.
📝 WalkthroughWalkthroughThis PR introduces a complete networking and data layer for sales orders. It configures Retrofit and OkHttp via Gradle properties injected into ChangesSales Order Networking & Data Layer
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/build.gradle.kts`:
- Around line 11-12: The `bbdUseApi` variable currently stores the property as a
String value ("true" or "false"), but when emitted to BuildConfig at line 31, it
needs to be an actual Boolean instead of a string literal to avoid breaking code
generation. Convert the `bbdUseApi` variable from a String to a real Boolean by
parsing the string value to determine if it evaluates to true or false, ensuring
that the BuildConfig field receives a proper boolean literal rather than a raw
string value.
In `@app/src/main/AndroidManifest.xml`:
- Around line 9-11: The android:usesCleartextTraffic="true" attribute in the
main AndroidManifest.xml enables cleartext HTTP traffic for all build variants
including release builds, which compromises transport security in production.
Remove the android:usesCleartextTraffic="true" attribute from the application
element in the main AndroidManifest.xml. Then add this attribute only to the
debug variant's AndroidManifest.xml located in src/debug/AndroidManifest.xml, or
alternatively create a debug-only networkSecurityConfig resource file that
permits cleartext traffic exclusively for debug builds. This ensures HTTP
cleartext is allowed only during development and testing, not in release builds.
In `@app/src/main/java/com/example/bbd/data/remote/Net.kt`:
- Around line 42-45: The `retrofit` lazy property is using
`BuildConfig.BASE_URL` directly with the `.baseUrl()` method, but Retrofit
requires URLs to end with a trailing slash and the gradle property doesn't
enforce this. Normalize `BuildConfig.BASE_URL` before passing it to `.baseUrl()`
by checking if it ends with a forward slash and appending one if it doesn't,
ensuring Retrofit receives a properly formatted URL that won't cause an
`IllegalArgumentException` at runtime.
In `@app/src/main/java/com/example/bbd/data/repo/SalesOrderRepository.kt`:
- Around line 21-30: The three methods arrivals, branchOrders, and receivedByMe
are calling api.search() without pagination parameters, which means they only
fetch the first page of results (default size 50) and silently drop all
remaining data. Update each of these methods to iterate through all available
pages by looping while the current page number is less than
pagination.totalPages, accumulating all items from each page into a single list
before returning it. Pass page and size parameters to api.search() in each
iteration to fetch subsequent pages.
- Around line 35-41: The runCatching block with the fold call for
api.receive(soNumber) is catching CancellationException along with other
exceptions, which prevents proper coroutine cancellation. In the onFailure
lambda, add a check at the beginning to detect if the thrown exception is a
CancellationException and re-throw it to preserve structured concurrency,
otherwise wrap the exception in UiState.Error as currently done. Apply this same
fix to the second runCatching block mentioned in lines 48-51.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9fa47cd7-f069-4f37-ac14-9e701b816801
📒 Files selected for processing (8)
app/build.gradle.ktsapp/src/main/AndroidManifest.xmlapp/src/main/java/com/example/bbd/data/remote/Net.ktapp/src/main/java/com/example/bbd/data/remote/SalesApi.ktapp/src/main/java/com/example/bbd/data/remote/UiState.ktapp/src/main/java/com/example/bbd/data/remote/dto/SalesOrderDto.ktapp/src/main/java/com/example/bbd/data/repo/SalesOrderRepository.ktgradle/libs.versions.toml
- build.gradle: BBD_USE_API → boolean 리터럴 정규화(임의 문자열 codegen 깨짐 방지) - Net: Retrofit BASE_URL 트레일링 슬래시 정규화(런타임 IllegalArgumentException 방지) - Manifest: cleartext(http) 허용을 디버그 빌드 전용으로 분리(src/debug), 릴리스는 https만 - Repository: 전체 페이지 수집(첫 페이지 누락 방지, 20p 안전캡) + CancellationException 재던짐(structured concurrency 보존) - (Copilot Overlays interactionSource=null 지적은 tapNoRipple 사용+Compose 2026 nullable 오버로드라 무효) - 로컬 assembleDebug GREEN
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/main/java/com/example/bbd/data/repo/SalesOrderRepository.kt`:
- Around line 48-71: The searchAll function silently returns incomplete results
when the MAX_PAGES limit is reached without indicating truncation to the caller.
After the while loop exits in searchAll, add a check to detect if the function
stopped due to hitting the MAX_PAGES cap while there are still more pages
available (by comparing the current page value against MAX_PAGES and checking if
there are remaining pages), and log a warning message to signal that the dataset
has been truncated, making it clear to users that the returned list may be
incomplete.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 43fc4907-4df1-4b95-895c-1adac631b394
📒 Files selected for processing (5)
app/build.gradle.ktsapp/src/debug/AndroidManifest.xmlapp/src/main/AndroidManifest.xmlapp/src/main/java/com/example/bbd/data/remote/Net.ktapp/src/main/java/com/example/bbd/data/repo/SalesOrderRepository.kt
✅ Files skipped from review due to trivial changes (1)
- app/src/debug/AndroidManifest.xml
🚧 Files skipped from review as they are similar to previous changes (2)
- app/build.gradle.kts
- app/src/main/java/com/example/bbd/data/remote/Net.kt
| private suspend fun searchAll( | ||
| status: String? = null, | ||
| toWarehouseCode: String? = null, | ||
| requestedBy: String? = null, | ||
| receivedBy: String? = null, | ||
| ): List<SalesOrderSummaryDto> { | ||
| val all = mutableListOf<SalesOrderSummaryDto>() | ||
| var page = 0 | ||
| while (page < MAX_PAGES) { | ||
| val resp = api.search( | ||
| status = status, | ||
| toWarehouseCode = toWarehouseCode, | ||
| requestedBy = requestedBy, | ||
| receivedBy = receivedBy, | ||
| page = page, | ||
| size = PAGE_SIZE, | ||
| ) | ||
| all += resp.items | ||
| val totalPages = resp.pagination?.totalPages ?: 1 | ||
| page++ | ||
| if (page >= totalPages || resp.items.isEmpty()) break | ||
| } | ||
| return all | ||
| } |
There was a problem hiding this comment.
Silent truncation at page cap returns incomplete datasets.
searchAll(...) stops at MAX_PAGES (Line 56) but currently returns partial results without signaling truncation. If total pages exceed 20, list APIs will silently omit orders.
Suggested fix
private suspend fun searchAll(
@@
): List<SalesOrderSummaryDto> {
val all = mutableListOf<SalesOrderSummaryDto>()
var page = 0
+ var completed = false
while (page < MAX_PAGES) {
val resp = api.search(
@@
all += resp.items
val totalPages = resp.pagination?.totalPages ?: 1
page++
- if (page >= totalPages || resp.items.isEmpty()) break
+ if (page >= totalPages || resp.items.isEmpty()) {
+ completed = true
+ break
+ }
}
+ if (!completed) {
+ throw IllegalStateException("조회 건수가 한도를 초과했습니다. 검색 조건을 좁혀주세요.")
+ }
return all
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/main/java/com/example/bbd/data/repo/SalesOrderRepository.kt` around
lines 48 - 71, The searchAll function silently returns incomplete results when
the MAX_PAGES limit is reached without indicating truncation to the caller.
After the while loop exits in searchAll, add a check to detect if the function
stopped due to hitting the MAX_PAGES cap while there are still more pages
available (by comparing the current page value against MAX_PAGES and checking if
there are remaining pages), and log a warning message to signal that the dataset
has been truncated, making it clear to users that the returned list may be
incomplete.
무엇
sales 서비스 연동을 위한 데이터 레이어(네트워크·DTO·API·repository)를 추가합니다. 계약은 sales 백엔드 컨트롤러/DTO로 검증했습니다.
data/remote/Net.kt— OkHttp+Retrofit+Gson 단일 설정 + Bearer 인터셉터(토큰은Net.bearer로 주입)data/remote/UiState.kt— Loading/Success/Errordata/remote/SalesApi.kt—GET /api/v1/sales-orders(검색),PATCH /{soNumber}/receive(도착 확인)data/remote/dto/SalesOrderDto.kt—SalesOrderPageDto·SalesOrderSummaryDto·PaginationDto(백엔드 record와 1:1)data/repo/SalesOrderRepository.kt—arrivals/branchOrders/receivedByMe/receivebuild.gradle.kts—BuildConfig.BASE_URL·USE_API(gradle property 주입),buildConfig=true, 의존성(Retrofit/OkHttp/Coroutines)AndroidManifest.xml— INTERNET 권한, dev용 cleartext안전장치
USE_API기본false→ 앱은 기존과 100% 동일(목업). 이 PR은 순수 additive 데이터 레이어.-PBBD_BASE_URL로 주입(기본 emulator localhost).작성 환경에 Android SDK가 없어 작성자가 컴파일하지 못했습니다. 머지 전 확인 부탁:
다음 PR에서 결정 필요 — 모델 매핑
모바일 모델이 백엔드와 1:1이 아님:
Pr(부품 1개=요청 1건)SalesOrder(다중 라인 주문)PrStatus(5상태)SalesOrderStatus(7상태)Movement(입/출고)연동 가능/차단 매트릭스
로드맵
Net.bearer주입Summary by CodeRabbit