248 lines
7.4 KiB
Dart
248 lines
7.4 KiB
Dart
import 'package:injectable/injectable.dart';
|
|
import 'package:superport/data/models/equipment_history_dto.dart';
|
|
import 'package:superport/data/repositories/equipment_history_repository.dart';
|
|
|
|
@lazySingleton
|
|
class EquipmentHistoryUseCase {
|
|
final EquipmentHistoryRepository _repository;
|
|
|
|
EquipmentHistoryUseCase(this._repository);
|
|
|
|
// 재고 이력 조회
|
|
Future<EquipmentHistoryListResponse> getEquipmentHistories({
|
|
int? page,
|
|
int? pageSize,
|
|
int? equipmentsId,
|
|
int? warehousesId,
|
|
int? companiesId,
|
|
String? transactionType,
|
|
String? startDate,
|
|
String? endDate,
|
|
}) async {
|
|
return await _repository.getEquipmentHistories(
|
|
page: page,
|
|
pageSize: pageSize,
|
|
equipmentsId: equipmentsId,
|
|
warehousesId: warehousesId,
|
|
companiesId: companiesId,
|
|
transactionType: transactionType,
|
|
startDate: startDate,
|
|
endDate: endDate,
|
|
);
|
|
}
|
|
|
|
// 특정 이력 상세 조회
|
|
Future<EquipmentHistoryDto> getEquipmentHistoryById(int id) async {
|
|
return await _repository.getEquipmentHistoryById(id);
|
|
}
|
|
|
|
// 장비별 이력 조회
|
|
Future<List<EquipmentHistoryDto>> getEquipmentHistoriesByEquipmentId(
|
|
int equipmentId,
|
|
) async {
|
|
return await _repository.getEquipmentHistoriesByEquipmentId(equipmentId);
|
|
}
|
|
|
|
// 창고별 이력 조회
|
|
Future<List<EquipmentHistoryDto>> getEquipmentHistoriesByWarehouseId(
|
|
int warehouseId,
|
|
) async {
|
|
return await _repository.getEquipmentHistoriesByWarehouseId(warehouseId);
|
|
}
|
|
|
|
// 장비별 재고 현황 계산 (백엔드 기반)
|
|
Future<int> getCurrentStock(int equipmentId, {int? warehouseId}) async {
|
|
final histories = await getEquipmentHistoriesByEquipmentId(equipmentId);
|
|
|
|
int totalStock = 0;
|
|
for (final history in histories) {
|
|
if (warehouseId != null && history.warehousesId != warehouseId) continue;
|
|
|
|
if (history.transactionType == TransactionType.input) {
|
|
totalStock += history.quantity;
|
|
} else if (history.transactionType == TransactionType.output) {
|
|
totalStock -= history.quantity;
|
|
}
|
|
}
|
|
|
|
return totalStock;
|
|
}
|
|
|
|
// 입고 처리 (백엔드 스키마 기반)
|
|
Future<EquipmentHistoryDto> createStockIn({
|
|
required int equipmentsId,
|
|
required int warehousesId,
|
|
required int quantity,
|
|
DateTime? transactedAt,
|
|
String? remark,
|
|
}) async {
|
|
// 비즈니스 규칙 검증
|
|
if (quantity <= 0) {
|
|
throw Exception('입고 수량은 0보다 커야 합니다.');
|
|
}
|
|
|
|
final request = EquipmentHistoryRequestDto(
|
|
equipmentsId: equipmentsId,
|
|
warehousesId: warehousesId,
|
|
transactionType: TransactionType.input,
|
|
quantity: quantity,
|
|
transactedAt: transactedAt ?? DateTime.now(),
|
|
remark: remark,
|
|
);
|
|
|
|
return await _repository.createEquipmentHistory(request);
|
|
}
|
|
|
|
// 출고 처리 (백엔드 스키마 기반)
|
|
Future<EquipmentHistoryDto> createStockOut({
|
|
required int equipmentsId,
|
|
required int warehousesId,
|
|
required int quantity,
|
|
DateTime? transactedAt,
|
|
String? remark,
|
|
}) async {
|
|
// 비즈니스 규칙 검증
|
|
if (quantity <= 0) {
|
|
throw Exception('출고 수량은 0보다 커야 합니다.');
|
|
}
|
|
|
|
// 재고 확인
|
|
final currentStock = await getCurrentStock(equipmentsId, warehouseId: warehousesId);
|
|
if (currentStock < quantity) {
|
|
throw Exception('재고가 부족합니다. (현재 재고: $currentStock개)');
|
|
}
|
|
|
|
final request = EquipmentHistoryRequestDto(
|
|
equipmentsId: equipmentsId,
|
|
warehousesId: warehousesId,
|
|
transactionType: TransactionType.output,
|
|
quantity: quantity,
|
|
transactedAt: transactedAt ?? DateTime.now(),
|
|
remark: remark,
|
|
);
|
|
|
|
return await _repository.createEquipmentHistory(request);
|
|
}
|
|
|
|
// 이력 수정
|
|
Future<EquipmentHistoryDto> updateEquipmentHistory(
|
|
int id,
|
|
EquipmentHistoryUpdateRequestDto request,
|
|
) async {
|
|
// 수정 권한 검증 (필요시 추가)
|
|
// 이미 완료된 트랜잭션은 수정 불가 등의 규칙
|
|
|
|
return await _repository.updateEquipmentHistory(id, request);
|
|
}
|
|
|
|
// 이력 삭제
|
|
Future<void> deleteEquipmentHistory(int id) async {
|
|
// 삭제 권한 검증 (필요시 추가)
|
|
// 감사 추적을 위해 실제로는 soft delete 고려
|
|
|
|
await _repository.deleteEquipmentHistory(id);
|
|
}
|
|
|
|
// 재고 이동 (창고 간 이동)
|
|
Future<void> transferStock({
|
|
required int equipmentsId,
|
|
required int quantity,
|
|
required int fromWarehouseId,
|
|
required int toWarehouseId,
|
|
String? remark,
|
|
}) async {
|
|
// 1. 출고 처리 (from warehouse)
|
|
await createStockOut(
|
|
equipmentsId: equipmentsId,
|
|
warehousesId: fromWarehouseId,
|
|
quantity: quantity,
|
|
remark: remark ?? '창고 이동: $fromWarehouseId → $toWarehouseId',
|
|
);
|
|
|
|
// 2. 입고 처리 (to warehouse)
|
|
await createStockIn(
|
|
equipmentsId: equipmentsId,
|
|
warehousesId: toWarehouseId,
|
|
quantity: quantity,
|
|
remark: remark ?? '창고 이동: $fromWarehouseId → $toWarehouseId',
|
|
);
|
|
}
|
|
|
|
// 재고 조정 (실사 후 조정)
|
|
Future<EquipmentHistoryDto> adjustInventory({
|
|
required int equipmentsId,
|
|
required int actualQuantity,
|
|
required int warehousesId,
|
|
String? remark,
|
|
}) async {
|
|
// 현재 재고 확인
|
|
final currentStock = await getCurrentStock(equipmentsId, warehouseId: warehousesId);
|
|
final difference = actualQuantity - currentStock;
|
|
|
|
if (difference == 0) {
|
|
throw Exception('재고 조정이 필요하지 않습니다.');
|
|
}
|
|
|
|
if (difference > 0) {
|
|
// 재고 증가 - 입고 처리
|
|
return await createStockIn(
|
|
equipmentsId: equipmentsId,
|
|
warehousesId: warehousesId,
|
|
quantity: difference,
|
|
remark: remark ?? '재고 조정: +$difference개',
|
|
);
|
|
} else {
|
|
// 재고 감소 - 출고 처리
|
|
return await createStockOut(
|
|
equipmentsId: equipmentsId,
|
|
warehousesId: warehousesId,
|
|
quantity: -difference,
|
|
remark: remark ?? '재고 조정: $difference개',
|
|
);
|
|
}
|
|
}
|
|
|
|
// 재고 부족 장비 확인 (단순화)
|
|
Future<List<int>> checkLowStockEquipments({
|
|
int minimumStock = 10,
|
|
int? warehouseId,
|
|
List<int>? equipmentIds,
|
|
}) async {
|
|
final lowStockEquipments = <int>[];
|
|
|
|
// 특정 장비 ID 목록이 제공된 경우, 해당 장비들만 확인
|
|
if (equipmentIds != null) {
|
|
for (final equipmentId in equipmentIds) {
|
|
final currentStock = await getCurrentStock(equipmentId, warehouseId: warehouseId);
|
|
if (currentStock < minimumStock) {
|
|
lowStockEquipments.add(equipmentId);
|
|
}
|
|
}
|
|
}
|
|
|
|
return lowStockEquipments;
|
|
}
|
|
|
|
// 이력 생성 (범용)
|
|
Future<EquipmentHistoryDto> createEquipmentHistory(
|
|
EquipmentHistoryRequestDto request,
|
|
) async {
|
|
// 비즈니스 규칙 검증
|
|
if (request.quantity <= 0) {
|
|
throw Exception('수량은 0보다 커야 합니다.');
|
|
}
|
|
|
|
// 출고인 경우 재고 확인
|
|
if (request.transactionType == TransactionType.output) {
|
|
final currentStock = await getCurrentStock(
|
|
request.equipmentsId,
|
|
warehouseId: request.warehousesId,
|
|
);
|
|
if (currentStock < request.quantity) {
|
|
throw Exception('재고가 부족합니다. (현재 재고: $currentStock개)');
|
|
}
|
|
}
|
|
|
|
return await _repository.createEquipmentHistory(request);
|
|
}
|
|
} |