- 전체 371개 파일 중 82개 미사용 파일 식별 - Phase 1: 33개 파일 삭제 예정 (100% 안전) - Phase 2: 30개 파일 삭제 검토 예정 - Phase 3: 19개 파일 수동 검토 예정 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
358 lines
9.7 KiB
Dart
358 lines
9.7 KiB
Dart
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<EquipmentHistoryUseCase>();
|
|
|
|
// 상태 변수 (백엔드 스키마 기반)
|
|
List<EquipmentHistoryDto> _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<EquipmentHistoryDto> 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<void> 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<String, int> 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<bool> 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<bool> 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<bool> 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<List<EquipmentHistoryDto>> 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<EquipmentHistoryDto> 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<void> loadInventoryStatus() async {
|
|
await loadHistory(refresh: true);
|
|
}
|
|
|
|
// loadWarehouseStock 메서드 (창고별 재고 로드)
|
|
Future<void> loadWarehouseStock({int? warehouseId}) async {
|
|
setFilters(warehouseId: warehouseId);
|
|
}
|
|
|
|
// getAvailableStock 메서드
|
|
Future<int> 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<List<int>> getAvailableEquipments({int? warehouseId}) async {
|
|
try {
|
|
final result = await _useCase.getEquipmentHistories(
|
|
page: 1,
|
|
pageSize: AppConstants.maxBulkPageSize,
|
|
warehousesId: warehouseId,
|
|
);
|
|
|
|
// 재고가 있는 장비 ID들만 반환
|
|
Map<int, int> 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<void> previousPage() async {
|
|
if (_currentPage > 1) {
|
|
_currentPage--;
|
|
await loadHistory();
|
|
}
|
|
}
|
|
|
|
Future<void> nextPage() async {
|
|
if (_currentPage < totalPages) {
|
|
_currentPage++;
|
|
await loadHistory();
|
|
}
|
|
}
|
|
|
|
// 에러 클리어
|
|
void clearError() {
|
|
_error = null;
|
|
notifyListeners();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_historyList.clear();
|
|
super.dispose();
|
|
}
|
|
} |