import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import '../../../data/models/equipment_history_dto.dart'; import '../../../domain/usecases/equipment_history_usecase.dart'; import '../../../core/constants/app_constants.dart'; class EquipmentHistoryController extends ChangeNotifier { final EquipmentHistoryUseCase _useCase; EquipmentHistoryController({ EquipmentHistoryUseCase? useCase, }) : _useCase = useCase ?? GetIt.instance(); // 상태 변수 (백엔드 스키마 기반) List _historyList = []; bool _isLoading = false; String? _error; // 페이지네이션 int _currentPage = 1; int _pageSize = AppConstants.historyPageSize; int _totalCount = 0; // 필터 (백엔드 실제 필드만) String _searchQuery = ''; String? _transactionType; int? _warehouseId; int? _equipmentId; DateTime? _startDate; DateTime? _endDate; // Getters (백엔드 실제 데이터만) List get historyList => _historyList; bool get isLoading => _isLoading; String? get error => _error; int get currentPage => _currentPage; int get totalPages => (_totalCount / _pageSize).ceil(); int get totalCount => _totalCount; String get searchQuery => _searchQuery; // 간단한 통계 (백엔드 실제 데이터 기반) int get totalTransactions => _historyList.length; int get totalInQuantity => _historyList .where((item) => item.transactionType == 'I') .fold(0, (sum, item) => sum + item.quantity); int get totalOutQuantity => _historyList .where((item) => item.transactionType == 'O') .fold(0, (sum, item) => sum + item.quantity); // 재고 이력 조회 Future loadHistory({bool refresh = false}) async { if (refresh) { _currentPage = 1; _historyList.clear(); } _isLoading = true; _error = null; notifyListeners(); try { final result = await _useCase.getEquipmentHistories( page: _currentPage, pageSize: _pageSize, transactionType: _transactionType, warehousesId: _warehouseId, equipmentsId: _equipmentId, startDate: _startDate?.toIso8601String(), endDate: _endDate?.toIso8601String(), ); // result는 EquipmentHistoryListResponse 타입으로 Either가 아님 if (refresh) { _historyList = result.items; } else { _historyList.addAll(result.items); } _totalCount = result.totalCount; } catch (e) { _error = e.toString(); } finally { _isLoading = false; notifyListeners(); } } // 백엔드 스키마 기반 단순 재고 조회 (EquipmentHistoryDto 기반) // 특정 장비의 현재 재고량 계산 (입고량 - 출고량) int calculateEquipmentStock(int equipmentId) { final equipmentHistories = _historyList.where((h) => h.equipmentsId == equipmentId); int totalIn = equipmentHistories .where((h) => h.transactionType == 'I') .fold(0, (sum, h) => sum + h.quantity); int totalOut = equipmentHistories .where((h) => h.transactionType == 'O') .fold(0, (sum, h) => sum + h.quantity); return totalIn - totalOut; } // 백엔드 스키마 기반 단순 필터링 void setFilters({ String? transactionType, int? warehouseId, int? equipmentId, DateTime? startDate, DateTime? endDate, String? searchQuery, }) { _transactionType = transactionType; _warehouseId = warehouseId; _equipmentId = equipmentId; _startDate = startDate; _endDate = endDate; if (searchQuery != null) _searchQuery = searchQuery; _currentPage = 1; loadHistory(refresh: true); } void clearFilters() { _transactionType = null; _warehouseId = null; _equipmentId = null; _startDate = null; _endDate = null; _searchQuery = ''; _currentPage = 1; loadHistory(refresh: true); } // 백엔드 스키마 기반 단순 통계 Map getStockSummary() { int totalIn = _historyList .where((h) => h.transactionType == 'I') .fold(0, (sum, h) => sum + h.quantity); int totalOut = _historyList .where((h) => h.transactionType == 'O') .fold(0, (sum, h) => sum + h.quantity); return { 'totalStock': totalIn - totalOut, 'totalIn': totalIn, 'totalOut': totalOut, }; } // 입고 처리 (백엔드 스키마 기반) Future createStockIn({ required int equipmentsId, required int warehousesId, required int quantity, DateTime? transactedAt, String? remark, }) async { _isLoading = true; _error = null; notifyListeners(); try { final request = EquipmentHistoryRequestDto( equipmentsId: equipmentsId, warehousesId: warehousesId, transactionType: 'I', // 입고 quantity: quantity, transactedAt: transactedAt ?? DateTime.now(), remark: remark, ); await _useCase.createEquipmentHistory(request); await loadHistory(refresh: true); return true; } catch (e) { _error = e.toString(); return false; } finally { _isLoading = false; notifyListeners(); } } // 출고 처리 (백엔드 스키마 기반) Future createStockOut({ required int equipmentsId, required int warehousesId, required int quantity, DateTime? transactedAt, String? remark, }) async { _isLoading = true; _error = null; notifyListeners(); try { final request = EquipmentHistoryRequestDto( equipmentsId: equipmentsId, warehousesId: warehousesId, transactionType: 'O', // 출고 quantity: quantity, transactedAt: transactedAt ?? DateTime.now(), remark: remark, ); await _useCase.createEquipmentHistory(request); await loadHistory(refresh: true); return true; } catch (e) { _error = e.toString(); return false; } finally { _isLoading = false; notifyListeners(); } } // createHistory 메서드 (별칭) Future createHistory(EquipmentHistoryRequestDto request) async { _isLoading = true; _error = null; notifyListeners(); try { await _useCase.createEquipmentHistory(request); await loadHistory(refresh: true); return true; } catch (e) { _error = e.toString(); return false; } finally { _isLoading = false; notifyListeners(); } } // searchEquipmentHistories 메서드 Future> searchEquipmentHistories({ String? query, String? transactionType, int? equipmentId, int? warehouseId, }) async { try { final result = await _useCase.getEquipmentHistories( page: 1, pageSize: AppConstants.bulkPageSize, transactionType: transactionType, equipmentsId: equipmentId, warehousesId: warehouseId, ); List histories = result.items; // 간단한 텍스트 검색 (remark 필드 기반) if (query != null && query.isNotEmpty) { histories = histories.where((h) => h.remark?.toLowerCase().contains(query.toLowerCase()) ?? false ).toList(); } return histories; } catch (e) { _error = e.toString(); notifyListeners(); return []; } } // setSearchQuery 메서드 void setSearchQuery(String query) { _searchQuery = query; setFilters(searchQuery: query); } // loadInventoryStatus 메서드 (단순 재고 상태 로드) Future loadInventoryStatus() async { await loadHistory(refresh: true); } // loadWarehouseStock 메서드 (창고별 재고 로드) Future loadWarehouseStock({int? warehouseId}) async { setFilters(warehouseId: warehouseId); } // getAvailableStock 메서드 Future getAvailableStock(int equipmentId, {int? warehouseId}) async { try { final result = await _useCase.getEquipmentHistories( page: 1, pageSize: AppConstants.maxBulkPageSize, equipmentsId: equipmentId, warehousesId: warehouseId, ); int totalIn = result.items .where((h) => h.transactionType == 'I') .fold(0, (sum, h) => sum + h.quantity); int totalOut = result.items .where((h) => h.transactionType == 'O') .fold(0, (sum, h) => sum + h.quantity); return totalIn - totalOut; } catch (e) { return 0; } } // getAvailableEquipments 메서드 (사용 가능한 장비 목록) Future> getAvailableEquipments({int? warehouseId}) async { try { final result = await _useCase.getEquipmentHistories( page: 1, pageSize: AppConstants.maxBulkPageSize, warehousesId: warehouseId, ); // 재고가 있는 장비 ID들만 반환 Map stockMap = {}; for (var history in result.items) { stockMap[history.equipmentsId] = (stockMap[history.equipmentsId] ?? 0) + (history.transactionType == 'I' ? history.quantity : -history.quantity); } return stockMap.entries .where((entry) => entry.value > 0) .map((entry) => entry.key) .toList(); } catch (e) { return []; } } // 페이지네이션 메서드들 Future previousPage() async { if (_currentPage > 1) { _currentPage--; await loadHistory(); } } Future nextPage() async { if (_currentPage < totalPages) { _currentPage++; await loadHistory(); } } // 에러 클리어 void clearError() { _error = null; notifyListeners(); } @override void dispose() { _historyList.clear(); super.dispose(); } }