fix(inventory): 파트너 연동 및 상세 모달 동작 안정화

- 입고 레코드에 파트너 식별자와 고객 요약을 캐싱하고 상세 칩으로 노출

- 입고 등록 모달에서 파트너 선택 복원과 고객 동기화를 지원하며 취소 시 상세를 복귀하도록 수정

- 재고 컨트롤러에 고객 동기화 유틸리티와 결재 상태 로딩을 추가하고 단위 테스트를 확장

- 제품·파트너 자동완성 위젯을 재작성해 초기 로딩, 검색, 외부 컨트롤러 동기화를 안정화

- 재고 상세/공통 모달 닫기와 출고·대여 편집 모달의 네비게이터 호출을 루트 기준으로 통일

- 테스트: flutter analyze, flutter test (기존 레이아웃 검증 케이스 실패 지속)
This commit is contained in:
JiWoong Sul
2025-10-27 20:02:21 +09:00
parent 14624c4165
commit 259b056072
14 changed files with 1054 additions and 155 deletions

View File

@@ -16,11 +16,13 @@ class InboundController extends ChangeNotifier {
InboundController({
required StockTransactionRepository transactionRepository,
required TransactionLineRepository lineRepository,
required TransactionCustomerRepository customerRepository,
required InventoryLookupRepository lookupRepository,
List<String> fallbackStatusOptions = const ['작성중', '승인대기', '승인완료'],
List<String> transactionTypeKeywords = const ['입고', 'inbound'],
}) : _transactionRepository = transactionRepository,
_lineRepository = lineRepository,
_customerRepository = customerRepository,
_lookupRepository = lookupRepository,
_fallbackStatusOptions = List<String>.unmodifiable(
fallbackStatusOptions,
@@ -33,6 +35,7 @@ class InboundController extends ChangeNotifier {
final StockTransactionRepository _transactionRepository;
final TransactionLineRepository _lineRepository;
final TransactionCustomerRepository _customerRepository;
final InventoryLookupRepository _lookupRepository;
final List<String> _fallbackStatusOptions;
final List<String> _transactionTypeKeywords;
@@ -46,6 +49,8 @@ class InboundController extends ChangeNotifier {
String? _errorMessage;
StockTransactionListFilter? _lastFilter;
final Set<int> _processingTransactionIds = <int>{};
List<LookupItem> _approvalStatuses = const [];
LookupItem? _defaultApprovalStatus;
UnmodifiableListView<String> get statusOptions =>
UnmodifiableListView(_statusOptions);
@@ -54,6 +59,9 @@ class InboundController extends ChangeNotifier {
UnmodifiableMapView(_statusLookup);
LookupItem? get transactionType => _transactionType;
LookupItem? get defaultApprovalStatus => _defaultApprovalStatus;
UnmodifiableListView<LookupItem> get approvalStatuses =>
UnmodifiableListView(_approvalStatuses);
PaginatedResult<StockTransaction>? get result => _result;
@@ -97,6 +105,21 @@ class InboundController extends ChangeNotifier {
}
}
/// 결재 상태 목록을 조회한다.
Future<void> loadApprovalStatuses() async {
try {
final items = await _lookupRepository.fetchApprovalStatuses();
if (items.isEmpty) {
return;
}
_approvalStatuses = items;
_defaultApprovalStatus = _resolveDefaultApprovalStatus(items);
notifyListeners();
} catch (_) {
// 오류 시 기존 상태 유지.
}
}
/// 입고 트랜잭션 타입을 조회한다.
Future<bool> resolveTransactionType() async {
if (_transactionType != null) {
@@ -156,6 +179,15 @@ class InboundController extends ChangeNotifier {
await fetchTransactions(filter: target);
}
LookupItem? _resolveDefaultApprovalStatus(List<LookupItem> items) {
for (final item in items) {
if (item.isDefault) {
return item;
}
}
return items.isEmpty ? null : items.first;
}
/// 재고 트랜잭션을 생성하고 필요 시 목록을 갱신한다.
Future<InboundRecord> createTransaction(
StockTransactionCreateInput input, {
@@ -448,4 +480,29 @@ class InboundController extends ChangeNotifier {
await _lineRepository.addLines(transactionId, plan.createdLines);
}
}
/// 고객 연결 변경 계획을 실행하여 파트너사 정보를 동기화한다.
Future<void> syncTransactionCustomers(
int transactionId,
TransactionCustomerSyncPlan plan,
) async {
if (!plan.hasChanges) {
return;
}
if (plan.updatedCustomers.isNotEmpty) {
await _customerRepository.updateCustomers(
transactionId,
plan.updatedCustomers,
);
}
for (final linkId in plan.deletedCustomerIds) {
await _customerRepository.deleteCustomer(linkId);
}
if (plan.createdCustomers.isNotEmpty) {
await _customerRepository.addCustomers(
transactionId,
plan.createdCustomers,
);
}
}
}