Skip to content

[FEAT] 입고처리/사용처리 기능 구현#12

Merged
Yoo-Hyuna merged 4 commits into
devfrom
feat/#11
Nov 1, 2025
Merged

[FEAT] 입고처리/사용처리 기능 구현#12
Yoo-Hyuna merged 4 commits into
devfrom
feat/#11

Conversation

@Yoo-Hyuna

@Yoo-Hyuna Yoo-Hyuna commented Nov 1, 2025

Copy link
Copy Markdown
Collaborator

📣 Related Issue

📝 Summary

  • QR 스캔을 통해 주문 데이터 받아오기
  • 입고처리 API 연결
  • 사용처리 API 연결
  • QR을 통해 받아온 데이터를 이용하여 주문 입고 처리
  • QR을 통해 받아온 데이터를 이용하여 재고 사용 처리

Summary by CodeRabbit

릴리스 노트

  • New Features
    • QR 코드 스캔을 통한 입고 처리 기능 추가
    • QR 코드 스캔을 통한 부품 사용 처리 기능 추가
    • 주문 상세 정보 화면 개선 - 주문 상태, 거부 사유, 배송정보 및 요청사항 표시

@Yoo-Hyuna Yoo-Hyuna requested a review from rhkr8521 November 1, 2025 08:34
@Yoo-Hyuna Yoo-Hyuna self-assigned this Nov 1, 2025
@Yoo-Hyuna Yoo-Hyuna added the FEAT label Nov 1, 2025
@coderabbitai

coderabbitai Bot commented Nov 1, 2025

Copy link
Copy Markdown

🐰 분석 리포트

워크스루

프로젝트에 QR 스캔 기능 기반의 입고처리 및 사용처리 기능을 추가했습니다. 이는 QR 스캐너 구현체, API 계층, 리포지토리, 뷰모델, UI 컴포넌트를 포함하며, 프로젝트 설정에 카메라 사용 권한 설정을 추가했습니다. 또한 주문 상세 뷰의 레이아웃을 개선했습니다.

변경사항

응집군 / 파일 변경 요약
프로젝트 설정
StockMate/StockMate.xcodeproj/project.pbxproj
Info.plist 파일 예외 집합 추가 및 NSCameraUsageDescription 설정 (Debug/Release 구성)
QR 스캐너 기본 구현
StockMate/StockMate/app/feature/parts/ui/QRScannerView.swift, QRScannerViewController.swift
UIViewControllerRepresentable을 통한 QR 스캐너 래퍼 및 AVCaptureSession 기반 카메라 구현 추가
입고 처리 기능
StockMate/StockMate/app/feature/inventory/ui/IncomingScanView.swift, app/feature/orders/data/OrderApi.swift, OrderRepositoryImpl.swift, OrderRepositoryProtocol.swift, OrderViewModel.swift
QR 기반 주문 입고 처리 워크플로우: 스캔 → 로딩 → 결과 피드백. 새로운 receiveOrder() API 및 저장소 메서드 추가, 기존 orderStatus 필드를 paymentType으로 변경
사용 처리 기능
StockMate/StockMate/app/feature/inventory/ui/OutgoingScanView.swift, app/feature/parts/data/PartApi.swift, PartRepositoryImpl.swift, PartRepositoryProtocol.swift, PartViewModel.swift
QR 기반 재고 사용 처리 기능: releaseParts() API, 저장소, 뷰모델 추가
UI 업데이트
StockMate/StockMate/app/feature/inventory/ui/InventoryView.swift, app/feature/orders/ui/OrderDetailView.swift, app/feature/auth/ui/LoginView.swift, ContentView.swift, Info.plist
인벤토리 네비게이션 대상 변경, 주문 상세 뷰 섹션 재구성 및 스타일링, 기타 UI/설정 파일 추가

시퀀스 다이어그램

sequenceDiagram
    participant User as 사용자
    participant IncomingView as IncomingScanView
    participant QRScanner as QRScannerView
    participant ViewModel as OrderViewModel
    participant API as OrderApi
    
    User->>IncomingView: 입고 처리 화면 진입
    IncomingView->>QRScanner: QR 스캐너 표시
    User->>QRScanner: QR 코드 스캔
    QRScanner->>IncomingView: scannedCode 바인딩 업데이트
    IncomingView->>IncomingView: handleScannedCode() 호출
    IncomingView->>ViewModel: receiveOrder(orderNumber) 실행
    ViewModel->>API: receiveOrder 요청
    API->>API: POST /api/v1/order/receive
    alt 성공
        API-->>ViewModel: 성공 응답
        ViewModel->>ViewModel: loadOrders() 새로고침
        ViewModel-->>IncomingView: 결과 메시지 반환
        IncomingView->>User: 성공 알림 표시
    else 실패
        API-->>ViewModel: 오류 응답
        ViewModel-->>IncomingView: 오류 메시지 반환
        IncomingView->>User: 오류 알림 표시
    end
Loading
sequenceDiagram
    participant User as 사용자
    participant OutgoingView as OutgoingScanView
    participant QRScanner as QRScannerView
    participant ViewModel as PartViewModel
    participant API as PartApi
    
    User->>OutgoingView: 사용 처리 화면 진입
    OutgoingView->>QRScanner: QR 스캐너 표시
    User->>QRScanner: 부품 QR 코드 스캔
    QRScanner->>OutgoingView: scannedCode 바인딩 업데이트
    OutgoingView->>OutgoingView: handleScannedCode() 호출
    OutgoingView->>OutgoingView: ReleaseItemRequest 생성 (partCode, quantity=1)
    OutgoingView->>ViewModel: releaseParts(items) 실행
    ViewModel->>API: releaseParts 요청
    API->>API: POST /api/v1/store/release
    alt 성공
        API-->>ViewModel: 성공 응답
        ViewModel-->>OutgoingView: 결과 메시지 반환
        OutgoingView->>User: 성공 알림 표시
    else 실패
        API-->>ViewModel: 오류 응답
        ViewModel-->>OutgoingView: 오류 메시지 반환
        OutgoingView->>User: 오류 알림 표시
    end
Loading

예상 코드 리뷰 난이도

🎯 3 (중간) | ⏱️ ~25분

주의가 필요한 부분:

  • LoginView.swift의 검증 로직 문제: isValidForm() 메서드에 무조건적인 return true가 추가되어 실제 입력 검증이 무시되고 있습니다. 이는 로그인 폼 검증 로직을 완전히 우회하는 것으로 보이며, 의도적인 변경인지 버그인지 확인이 필요합니다.
  • OrderCreateResponseData 필드 변경: orderStatuspaymentType으로 변경되었으나, 기존 코드에서 orderStatus 필드를 사용하는 다른 부분이 있는지 확인 필요
  • QR 스캐너 카메라 권한 처리: AVCaptureSession 설정 시 카메라 권한 요청 및 거부 시 처리 로직이 명확히 구현되어 있는지 확인
  • 비동기 플로우 안전성: 스캔 중복 방지 및 로딩 상태 동안 추가 스캔 시도에 대한 처리 확인
  • API 응답 타입 일관성: PartApi의 releasePartsApiResponse<String>을 반환하지만 PartViewModel에서 AppResult<String>으로 변환하는 로직이 제대로 처리되고 있는지 확인

관련 PR

제안 검수자

  • rhkr8521

🐰 QR 코드를 쓱, 스캔하니
입고도 되고 재고도 풀려 🎉
카메라 허락 받고 구글링 검색
코더는 웃고, 버그는 없고 ✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning LoginView.swift에서 발견된 변경사항이 이슈 범위를 벗어납니다. isValidForm() 메서드가 조건부 반환 이후에 무조건 true를 반환하도록 수정되어, 로그인 폼 검증 로직이 완전히 무효화되었습니다. 이는 입고처리/사용처리 기능 구현과 무관한 변경이며, 애플리케이션의 로그인 기능에 부작용을 야기할 수 있는 문제입니다. 나머지 변경사항들(QR 스캔, API 연결, 뷰 구현, Info.plist 업데이트)은 이슈 범위 내입니다. LoginView.swift의 isValidForm() 메서드 변경을 제거하거나 원래 상태로 복원해야 합니다. 이 파일은 입고처리/사용처리 기능 구현과 무관하므로 이번 PR에서 제외되어야 하며, 만약 의도적인 변경이었다면 별도의 이슈와 PR로 분리하여 진행하기를 권장합니다.
Docstring Coverage ⚠️ Warning Docstring coverage is 21.05% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed PR 제목 "[FEAT] 입고처리/사용처리 기능 구현"은 changeset의 주요 변경 내용을 정확하게 반영하고 있습니다. QRScannerView와 QRScannerViewController를 통한 QR 스캔 기능 구현, OrderApi 및 OrderViewModel의 입고처리(receiveOrder) 기능, PartApi 및 PartViewModel의 사용처리(releaseParts) 기능이 모두 이 제목과 일치합니다. 제목은 간결하고 명확하며 불필요한 노이즈가 없습니다.
Linked Issues Check ✅ Passed PR에 포함된 코드 변경사항들은 이슈 #11의 주요 요구사항을 충족합니다. QR 스캔 기능(QRScannerViewController, QRScannerView)으로 주문 데이터 조회가 가능하고, OrderApi의 receiveOrder 메서드와 PartApi의 releaseParts 메서드로 API 연결이 구현되었으며, IncomingScanView와 OutgoingScanView에서 각각 입고처리와 사용처리가 구현되었습니다. 이슈의 5가지 TODO 항목(QR 스캔, 입고처리 API 연결, 사용처리 API 연결, 입고 처리 구현, 재고 사용 처리 구현)이 모두 코드에 반영되었습니다.
✨ 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/#11

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

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

@Yoo-Hyuna

Copy link
Copy Markdown
Collaborator Author

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)

  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#11

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

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

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 1, 2025

Copy link
Copy Markdown

@Yoo-Hyuna: I'll review the changes in this PR right away.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
StockMate/StockMate/app/feature/auth/ui/LoginView.swift (1)

121-126: 즉시 제거 필요: 도달 불가능한 코드로 인한 검증 우회

Line 125의 return true는 도달할 수 없는 코드입니다. Line 124가 이미 결과를 반환하므로 Line 125는 절대 실행되지 않습니다. 그러나 이 코드는 의도적으로 추가된 것으로 보이며, 실제로는 검증 로직을 완전히 우회하는 심각한 보안 문제를 발생시킵니다.

영향:

  • 유효하지 않은 이메일 형식으로 로그인 가능
  • 8자 미만의 비밀번호로 로그인 가능
  • 클라이언트 측 검증 완전 무력화

다음과 같이 수정하세요:

 private func isValidForm() -> Bool {
     emailError = isValidEmail(authViewModel.email) ? nil : "이메일 형식을 확인해주세요"
     pwError = authViewModel.password.count >= 8 ? nil : "8자 이상 비밀번호를 입력해주세요"
     return emailError == nil && pwError == nil
-    return true
 }
🧹 Nitpick comments (8)
StockMate/StockMate/ContentView.swift (1)

10-49: 주석 처리된 코드 제거 권장

주석 처리된 QR 스캐너 예제 코드가 더 이상 필요하지 않다면 제거하는 것을 권장합니다. 코드베이스를 깔끔하게 유지하는 데 도움이 됩니다.

StockMate/StockMate/app/feature/orders/viewmodel/OrderViewModel.swift (1)

99-111: 주석 처리된 코드를 제거하세요.

더 이상 사용하지 않는 코드는 버전 관리 시스템에서 확인할 수 있으므로 삭제하는 것이 코드베이스를 깔끔하게 유지하는 데 도움이 됩니다.

-//    func receiveOrder(orderNumber: String) async {
-//        isLoading = true
-//        defer { isLoading = false }
-//        
-//        let result = await repository.receiveOrder(orderNumber: orderNumber)
-//        switch result {
-//        case .success(let message):
-//            print("✅ 입고 처리 성공:", message)
-//            await loadOrders() // 리스트 갱신
-//        case .failure(let error):
-//            errorMessage = error.message
-//        }
-//    }
StockMate/StockMate/app/feature/inventory/ui/OutgoingScanView.swift (2)

13-13: 불필요한 nil 초기화를 제거하세요.

옵셔널 변수는 명시적으로 nil을 할당하지 않아도 자동으로 nil로 초기화됩니다.

-    @State private var scannedCode: String? = nil
+    @State private var scannedCode: String?

Based on learnings


95-113: MainActor.run 호출을 단순화하세요.

PartViewModel이 이미 @MainActor로 선언되어 있고 메인 스레드에서 호출되므로, 명시적인 MainActor.run 블록은 불필요합니다. 또한 isLoadingpartViewModel@Published 속성이므로 직접 설정할 수 있습니다.

 private func handleScannedCode(_ code: String) async {
-    await MainActor.run {
-        partViewModel.isLoading = true
-    }
-
     let request = [ReleaseItemRequest(partCode: code, quantity: 1)]
     let result = await partViewModel.releaseParts(items: request)
 
-    await MainActor.run {
-        partViewModel.isLoading = false
-        switch result {
-        case .success(let message):
-            alertMessage = message
-        case .failure(let error):
-            alertMessage = error.message
-        }
-        showAlert = true
+    switch result {
+    case .success(let message):
+        alertMessage = message
+    case .failure(let error):
+        alertMessage = error.message
     }
+    showAlert = true
 }
StockMate/StockMate/app/feature/inventory/ui/IncomingScanView.swift (2)

12-12: 불필요한 nil 초기화를 제거하세요.

옵셔널 변수는 명시적으로 nil을 할당하지 않아도 자동으로 nil로 초기화됩니다.

-    @State private var scannedCode: String? = nil
+    @State private var scannedCode: String?

Based on learnings


90-106: MainActor.run 호출을 단순화하세요.

OrderViewModel이 이미 @MainActor로 선언되어 있고, 이 뷰 자체도 메인 스레드에서 실행되므로 명시적인 MainActor.run 블록은 불필요합니다.

 private func handleScannedCode(_ code: String) async {
-    await MainActor.run {
-        orderViewModel.isLoading = true
-    }
-    
     let result = await orderViewModel.receiveOrder(orderNumber: code)
-    await MainActor.run {
-        orderViewModel.isLoading = false
-        switch result {
-        case .success(let message):
-            alertMessage = message
-        case .failure(let error):
-            alertMessage = error.message
-        }
-        showAlert = true
+    
+    switch result {
+    case .success(let message):
+        alertMessage = message
+    case .failure(let error):
+        alertMessage = error.message
     }
+    showAlert = true
 }
StockMate/StockMate/app/feature/orders/ui/OrderDetailView.swift (1)

226-236: 입고 처리 버튼 기능 구현이 필요합니다.

입고 처리 버튼이 표시되지만 아직 액션이 구현되지 않았습니다. IncomingScanView로 이동하거나 orderViewModel.receiveOrder()를 직접 호출하는 로직을 추가해야 합니다.

입고 처리 버튼의 액션 구현 코드를 생성해드릴까요? 예를 들어, QR 스캔 화면으로 이동하거나 주문번호를 직접 전달하는 방식 중 어떤 방식을 선호하시는지 알려주세요.

StockMate/StockMate/app/feature/orders/data/OrderApi.swift (1)

107-112: 주석 처리된 코드는 제거하는 것이 좋습니다.

버전 관리 시스템(Git)을 사용하고 있으므로, 주석 처리된 이전 코드는 제거하고 필요시 Git 히스토리에서 확인할 수 있습니다.

다음 diff를 적용하여 주석 처리된 코드를 제거하세요:

-// Response
-//struct OrderCreateResponseData: Decodable {
-//    let orderId: Int
-//    let orderNumber: String
-//    let totalPrice: Int
-//    let orderStatus: String
-//}
-
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b9715c and 574be77.

📒 Files selected for processing (18)
  • StockMate/StockMate.xcodeproj/project.pbxproj (3 hunks)
  • StockMate/StockMate/ContentView.swift (1 hunks)
  • StockMate/StockMate/Info.plist (1 hunks)
  • StockMate/StockMate/app/feature/auth/ui/LoginView.swift (1 hunks)
  • StockMate/StockMate/app/feature/inventory/ui/IncomingScanView.swift (1 hunks)
  • StockMate/StockMate/app/feature/inventory/ui/InventoryView.swift (1 hunks)
  • StockMate/StockMate/app/feature/inventory/ui/OutgoingScanView.swift (1 hunks)
  • StockMate/StockMate/app/feature/orders/data/OrderApi.swift (2 hunks)
  • StockMate/StockMate/app/feature/orders/data/OrderRepositoryImpl.swift (1 hunks)
  • StockMate/StockMate/app/feature/orders/domain/OrderRepositoryProtocol.swift (1 hunks)
  • StockMate/StockMate/app/feature/orders/ui/OrderDetailView.swift (3 hunks)
  • StockMate/StockMate/app/feature/orders/viewmodel/OrderViewModel.swift (1 hunks)
  • StockMate/StockMate/app/feature/parts/data/PartApi.swift (1 hunks)
  • StockMate/StockMate/app/feature/parts/data/PartRepositoryImpl.swift (1 hunks)
  • StockMate/StockMate/app/feature/parts/domain/PartRepositoryProtocol.swift (1 hunks)
  • StockMate/StockMate/app/feature/parts/ui/QRScannerView.swift (1 hunks)
  • StockMate/StockMate/app/feature/parts/ui/QRScannerViewController.swift (1 hunks)
  • StockMate/StockMate/app/feature/parts/viewmodel/PartViewModel.swift (1 hunks)
🧰 Additional context used
🪛 SwiftLint (0.57.0)
StockMate/StockMate/app/feature/inventory/ui/OutgoingScanView.swift

[Warning] 13-13: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

StockMate/StockMate/app/feature/inventory/ui/IncomingScanView.swift

[Warning] 12-12: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

🔇 Additional comments (19)
StockMate/StockMate/Info.plist (1)

1-5: LGTM!

표준 plist 구조이며 project.pbxproj에서 카메라 권한 설명이 올바르게 구성되어 있습니다.

StockMate/StockMate/app/feature/inventory/ui/InventoryView.swift (1)

129-129: LGTM!

사용 처리 흐름을 별도의 OutgoingScanView로 분리한 것이 논리적으로 적절합니다.

StockMate/StockMate/app/feature/parts/domain/PartRepositoryProtocol.swift (1)

10-12: LGTM!

레포지토리 패턴을 올바르게 따르고 있으며, 기존 OrderRepositoryProtocol과 일관된 구조를 가지고 있습니다.

StockMate/StockMate.xcodeproj/project.pbxproj (2)

17-25: LGTM!

Info.plist 파일 예외 처리가 올바르게 구성되어 있습니다.

Also applies to: 30-32


279-280: LGTM!

카메라 권한 설명이 Debug 및 Release 구성 모두에 적절하게 추가되었습니다. QR 스캔 기능을 위한 필수 설정입니다.

Also applies to: 309-310

StockMate/StockMate/app/feature/orders/domain/OrderRepositoryProtocol.swift (1)

27-31: LGTM!

입고 처리 메서드가 프로토콜에 적절하게 추가되었습니다. 기존 메서드들과 일관된 네이밍과 시그니처를 따르고 있습니다.

StockMate/StockMate/app/feature/parts/data/PartRepositoryImpl.swift (1)

11-16: LGTM!

레포지토리 구현이 깔끔하며 기존 OrderRepositoryImpl 패턴을 일관되게 따르고 있습니다. safeApi 유틸리티를 활용한 에러 처리도 적절합니다.

StockMate/StockMate/app/feature/orders/data/OrderRepositoryImpl.swift (1)

93-105: 입고 처리 메서드 구현이 잘 되었습니다.

기존 cancelOrder 메서드와 동일한 패턴으로 일관성 있게 구현되었으며, 에러 처리와 기본 메시지 처리가 적절합니다.

StockMate/StockMate/app/feature/orders/viewmodel/OrderViewModel.swift (1)

82-96: 입고 처리 메서드가 올바르게 구현되었습니다.

AppResult<String>을 반환하여 호출자가 성공/실패를 직접 처리할 수 있도록 했으며, 성공 시 loadOrders()를 호출하여 목록을 갱신하는 로직이 적절합니다.

StockMate/StockMate/app/feature/inventory/ui/OutgoingScanView.swift (1)

100-100: 기본 수량 1개 설정을 확인하세요.

현재 스캔된 부품의 수량이 항상 1개로 하드코딩되어 있습니다. 향후 사용자가 수량을 입력할 수 있는 기능이 필요할 수 있습니다.

이것이 의도된 동작인지 확인하고, 향후 수량 입력 기능 추가가 필요한지 검토하시기 바랍니다.

StockMate/StockMate/app/feature/parts/viewmodel/PartViewModel.swift (1)

23-43: 부품 사용 처리 메서드가 잘 구현되었습니다.

로딩 상태 관리, 에러 처리, 인증 오류 감지(401/403) 등이 모두 적절하게 구현되어 있으며, @MainActor를 사용한 스레드 안정성도 확보되었습니다.

StockMate/StockMate/app/feature/parts/ui/QRScannerViewController.swift (1)

61-67: QR 코드 재스캔 기능을 고려하세요.

현재 QR 코드를 한 번 스캔하면 세션이 중지되어 다시 스캔할 수 없습니다. 사용자가 여러 개의 QR 코드를 연속으로 스캔해야 하는 경우를 고려하여 세션 재시작 로직을 추가하는 것을 검토하시기 바랍니다.

현재 UX 요구사항에서 한 번의 스캔 후 뷰가 닫히는 것이 의도된 동작인지 확인하세요.

StockMate/StockMate/app/feature/orders/ui/OrderDetailView.swift (1)

28-118: UI 레이아웃 개선이 잘 되었습니다.

주문 정보, 반려 메시지, 배송정보, 요청사항 섹션이 일관된 스타일로 분리되어 가독성과 사용자 경험이 향상되었습니다.

StockMate/StockMate/app/feature/orders/data/OrderApi.swift (3)

121-124: LGTM!

입고 처리를 위한 요청 구조체가 올바르게 정의되었습니다. 단일 필드 구조로 명확하고 간결합니다.


180-190: LGTM!

입고 처리 API 함수가 올바르게 구현되었습니다. 기존 API 함수들과 동일한 패턴을 따르고 있으며, URL 구성과 파라미터 인코딩이 적절합니다.


114-119: 코드베이스에 영향 없음 - 변경사항이 안전하게 격리되어 있습니다.

검증 결과, OrderCreateResponseData의 필드 변경이 기존 코드에 영향을 주지 않습니다:

  • 뷰에서 접근하는 orderStatusOrderResponseItem 모델에서 오며, 이 모델은 여전히 orderStatus 필드를 유지하고 있습니다.
  • createOrder() 응답 처리 시 response.orderId만 사용되므로, OrderCreateResponseData의 필드명 변경은 영향을 주지 않습니다.
  • paymentType은 이미 OrderResponseItem에 존재하므로 일관성이 유지됩니다.
StockMate/StockMate/app/feature/parts/ui/QRScannerView.swift (3)

10-17: LGTM!

UIViewControllerRepresentable 구현이 올바릅니다. QRScannerViewController를 생성하고 coordinator를 delegate로 설정하는 표준 패턴을 따르고 있습니다.


19-19: LGTM!

updateUIViewController가 비어있는 것은 이 경우 적절합니다. QR 스캐너는 생성 후 동적으로 업데이트할 상태가 없으며, 스캔 결과는 delegate 패턴을 통해 전달됩니다.


21-35: LGTM!

Coordinator 구현이 올바릅니다. QRScannerDelegate를 통해 스캔된 코드를 받아 parent의 binding을 업데이트하는 표준 패턴을 따르고 있습니다. final 키워드 사용으로 성능도 최적화되어 있습니다.

Comment on lines +20 to +31
static func releaseParts(items: [ReleaseItemRequest]) -> DataRequest {
let url = ApiClient.baseURL + "api/v1/store/release"
let body: [String: Any] = [
"items": items.map { ["partCode": $0.partCode, "quantity": $0.quantity] }
]
return ApiClient.shared.request(
url,
method: .post,
parameters: body,
encoding: JSONEncoding.default
)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Encodable 프로토콜을 활용하여 타입 안정성을 개선하세요.

ReleaseItemRequest가 이미 Encodable을 준수하고 있지만, 현재 코드는 수동으로 딕셔너리를 구성하고 있습니다. 이는 타입 안정성이 떨어지고 오타 가능성이 있습니다.

+struct ReleasePartsRequest: Encodable {
+    let items: [ReleaseItemRequest]
+}
+
 enum PartApi {
     static func releaseParts(items: [ReleaseItemRequest]) -> DataRequest {
         let url = ApiClient.baseURL + "api/v1/store/release"
-        let body: [String: Any] = [
-            "items": items.map { ["partCode": $0.partCode, "quantity": $0.quantity] }
-        ]
+        let body = ReleasePartsRequest(items: items)
         return ApiClient.shared.request(
             url,
             method: .post,
             parameters: body,
-            encoding: JSONEncoding.default
+            encoder: JSONParameterEncoder.default
         )
     }
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In StockMate/StockMate/app/feature/parts/data/PartApi.swift around lines 20–31,
the code manually constructs a [String: Any] body from ReleaseItemRequest;
instead create a small Encodable wrapper (e.g. struct ReleaseItemsRequest:
Encodable { let items: [ReleaseItemRequest] }) and send that directly with
Alamofire's JSON encoder instead of building dictionaries. Replace the body
dictionary and items.map call with an instance of ReleaseItemsRequest(items:
items) and call ApiClient.shared.request(url, method: .post, parameters:
releaseItemsRequest, encoder: JSONParameterEncoder.default) (or use JSONEncoder
to encode Data into the request body) so the request uses Encodable for
type-safe JSON encoding.

Comment on lines +26 to +58
private func setupCamera() {
captureSession = AVCaptureSession()

guard let videoCaptureDevice = AVCaptureDevice.default(for: .video),
let videoInput = try? AVCaptureDeviceInput(device: videoCaptureDevice),
captureSession.canAddInput(videoInput)
else {
print("카메라 입력 불가")
return
}

captureSession.addInput(videoInput)

let metadataOutput = AVCaptureMetadataOutput()
guard captureSession.canAddOutput(metadataOutput) else {
print("출력 연결 불가")
return
}

captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [.qr]

previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.frame = view.layer.bounds
previewLayer.videoGravity = .resizeAspectFill
view.layer.addSublayer(previewLayer)

// ⚠️ 백그라운드에서 실행
DispatchQueue.global(qos: .userInitiated).async {
self.captureSession.startRunning()
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

카메라 권한 확인 및 에러 처리를 개선하세요.

현재 카메라 설정 실패 시 콘솔에만 출력되고 사용자에게 피드백이 제공되지 않습니다. 카메라 권한 확인과 사용자 친화적인 에러 처리가 필요합니다.

 private func setupCamera() {
+    // 카메라 권한 확인
+    switch AVCaptureDevice.authorizationStatus(for: .video) {
+    case .authorized:
+        break
+    case .notDetermined:
+        AVCaptureDevice.requestAccess(for: .video) { granted in
+            if granted {
+                DispatchQueue.main.async {
+                    self.setupCamera()
+                }
+            }
+        }
+        return
+    case .denied, .restricted:
+        // 사용자에게 설정으로 이동하도록 안내
+        DispatchQueue.main.async {
+            // delegate를 통해 에러 전달하거나 alert 표시
+        }
+        return
+    @unknown default:
+        return
+    }
+    
     captureSession = AVCaptureSession()
 
     guard let videoCaptureDevice = AVCaptureDevice.default(for: .video),
           let videoInput = try? AVCaptureDeviceInput(device: videoCaptureDevice),
           captureSession.canAddInput(videoInput)
     else {
-        print("카메라 입력 불가")
+        // 사용자에게 에러 피드백 제공
+        DispatchQueue.main.async {
+            // delegate를 통해 에러 전달
+        }
         return
     }
🤖 Prompt for AI Agents
In StockMate/StockMate/app/feature/parts/ui/QRScannerViewController.swift around
lines 26 to 58, the camera setup currently only prints errors and does not
check/request camera permission or present user-facing errors; update
setupCamera to first check AVCaptureDevice.authorizationStatus(for: .video) and
if .notDetermined call requestAccess and proceed only on granted, if .denied or
.restricted present a UIAlertController on the main thread explaining the need
for camera access with an action to open UIApplication.openSettingsURLString,
and replace print(...) failure paths with user-facing alerts (also ensure any UI
changes like adding previewLayer or presenting alerts are done on the main
thread); keep startRunning on a background queue but guard against nil
captureSession and call captureSession.stopRunning in failure paths.

@Yoo-Hyuna Yoo-Hyuna merged commit 00022da into dev Nov 1, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant