프로젝트 최초 커밋

This commit is contained in:
JiWoong Sul
2025-07-02 17:45:44 +09:00
commit e346f83c97
235 changed files with 23139 additions and 0 deletions

View File

@@ -0,0 +1,267 @@
import 'package:flutter/material.dart';
import 'package:superport/models/equipment_unified_model.dart';
import 'package:superport/models/company_model.dart';
import 'package:superport/services/mock_data_service.dart';
import 'package:superport/utils/constants.dart';
/// 장비 입고 폼 컨트롤러
///
/// 폼의 전체 상태, 유효성, 저장, 데이터 로딩 등 비즈니스 로직을 담당한다.
class EquipmentInFormController {
final MockDataService dataService;
final int? equipmentInId;
// 폼 키
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
// 입력 상태 변수
String manufacturer = '';
String name = '';
String category = '';
String subCategory = '';
String subSubCategory = '';
String serialNumber = '';
String barcode = '';
int quantity = 1;
DateTime inDate = DateTime.now();
String equipmentType = EquipmentType.new_;
bool hasSerialNumber = true;
// 워런티 관련 상태
String? warrantyLicense;
String? warrantyCode; // 워런티 코드(텍스트 입력)
DateTime warrantyStartDate = DateTime.now();
DateTime warrantyEndDate = DateTime.now().add(const Duration(days: 365));
List<String> warrantyLicenses = [];
// 자동완성 데이터
List<String> manufacturers = [];
List<String> equipmentNames = [];
// 카테고리 자동완성 데이터
List<String> categories = [];
List<String> subCategories = [];
List<String> subSubCategories = [];
// 편집 모드 여부
bool isEditMode = false;
// 입고지, 파트너사 관련 상태
String? warehouseLocation;
String? partnerCompany;
List<String> warehouseLocations = [];
List<String> partnerCompanies = [];
final TextEditingController remarkController = TextEditingController();
EquipmentInFormController({required this.dataService, this.equipmentInId}) {
isEditMode = equipmentInId != null;
_loadManufacturers();
_loadEquipmentNames();
_loadCategories();
_loadSubCategories();
_loadSubSubCategories();
_loadWarehouseLocations();
_loadPartnerCompanies();
_loadWarrantyLicenses();
if (isEditMode) {
_loadEquipmentIn();
}
}
// 제조사 목록 로드
void _loadManufacturers() {
manufacturers = dataService.getAllManufacturers();
}
// 장비명 목록 로드
void _loadEquipmentNames() {
equipmentNames = dataService.getAllEquipmentNames();
}
// 카테고리 목록 로드
void _loadCategories() {
categories = dataService.getAllCategories();
}
// 서브카테고리 목록 로드
void _loadSubCategories() {
subCategories = dataService.getAllSubCategories();
}
// 서브서브카테고리 목록 로드
void _loadSubSubCategories() {
subSubCategories = dataService.getAllSubSubCategories();
}
// 입고지 목록 로드
void _loadWarehouseLocations() {
warehouseLocations =
dataService.getAllWarehouseLocations().map((e) => e.name).toList();
}
// 파트너사 목록 로드
void _loadPartnerCompanies() {
partnerCompanies =
dataService
.getAllCompanies()
.where((c) => c.companyTypes.contains(CompanyType.partner))
.map((c) => c.name)
.toList();
}
// 워런티 라이센스 목록 로드
void _loadWarrantyLicenses() {
// 실제로는 API나 서비스에서 불러와야 하지만, 파트너사와 동일한 데이터 사용
warrantyLicenses = List.from(partnerCompanies);
}
// 기존 데이터 로드(수정 모드)
void _loadEquipmentIn() {
final equipmentIn = dataService.getEquipmentInById(equipmentInId!);
if (equipmentIn != null) {
manufacturer = equipmentIn.equipment.manufacturer;
name = equipmentIn.equipment.name;
category = equipmentIn.equipment.category;
subCategory = equipmentIn.equipment.subCategory;
subSubCategory = equipmentIn.equipment.subSubCategory;
serialNumber = equipmentIn.equipment.serialNumber ?? '';
barcode = equipmentIn.equipment.barcode ?? '';
quantity = equipmentIn.equipment.quantity;
inDate = equipmentIn.inDate;
hasSerialNumber = serialNumber.isNotEmpty;
equipmentType = equipmentIn.type;
warehouseLocation = equipmentIn.warehouseLocation;
partnerCompany = equipmentIn.partnerCompany;
remarkController.text = equipmentIn.remark ?? '';
// 워런티 정보 로드 (실제 구현에서는 기존 값을 불러옵니다)
warrantyLicense = equipmentIn.partnerCompany; // 기본값으로 파트너사 이름 사용
warrantyStartDate = equipmentIn.inDate;
warrantyEndDate = equipmentIn.inDate.add(const Duration(days: 365));
// 워런티 코드도 불러오도록(실제 구현시)
warrantyCode = null; // TODO: 실제 데이터에서 불러올 경우 수정
}
}
// 워런티 기간 계산
String getWarrantyPeriodSummary() {
final difference = warrantyEndDate.difference(warrantyStartDate);
final days = difference.inDays;
if (days <= 0) {
return '유효하지 않은 기간';
}
final years = days ~/ 365;
final remainingDays = days % 365;
String summary = '';
if (years > 0) {
summary += '$years년 ';
}
if (remainingDays > 0) {
summary += '$remainingDays일';
}
return summary.trim();
}
// 저장 처리
bool save() {
if (!formKey.currentState!.validate()) {
return false;
}
formKey.currentState!.save();
// 입력값이 리스트에 없으면 추가
if (partnerCompany != null &&
partnerCompany!.isNotEmpty &&
!partnerCompanies.contains(partnerCompany)) {
partnerCompanies.add(partnerCompany!);
}
if (warehouseLocation != null &&
warehouseLocation!.isNotEmpty &&
!warehouseLocations.contains(warehouseLocation)) {
warehouseLocations.add(warehouseLocation!);
}
if (manufacturer.isNotEmpty && !manufacturers.contains(manufacturer)) {
manufacturers.add(manufacturer);
}
if (name.isNotEmpty && !equipmentNames.contains(name)) {
equipmentNames.add(name);
}
if (category.isNotEmpty && !categories.contains(category)) {
categories.add(category);
}
if (subCategory.isNotEmpty && !subCategories.contains(subCategory)) {
subCategories.add(subCategory);
}
if (subSubCategory.isNotEmpty &&
!subSubCategories.contains(subSubCategory)) {
subSubCategories.add(subSubCategory);
}
if (warrantyLicense != null &&
warrantyLicense!.isNotEmpty &&
!warrantyLicenses.contains(warrantyLicense)) {
warrantyLicenses.add(warrantyLicense!);
}
final equipment = Equipment(
manufacturer: manufacturer,
name: name,
category: category,
subCategory: subCategory,
subSubCategory: subSubCategory,
serialNumber: hasSerialNumber ? serialNumber : null,
barcode: barcode.isNotEmpty ? barcode : null,
quantity: quantity,
remark: remarkController.text.trim(),
warrantyLicense: warrantyLicense,
warrantyStartDate: warrantyStartDate,
warrantyEndDate: warrantyEndDate,
// 워런티 코드 저장 필요시 여기에 추가
);
if (isEditMode) {
final equipmentIn = dataService.getEquipmentInById(equipmentInId!);
if (equipmentIn != null) {
final updatedEquipmentIn = EquipmentIn(
id: equipmentIn.id,
equipment: equipment,
inDate: inDate,
status: equipmentIn.status,
type: equipmentType,
warehouseLocation: warehouseLocation,
partnerCompany: partnerCompany,
remark: remarkController.text.trim(),
);
dataService.updateEquipmentIn(updatedEquipmentIn);
}
} else {
final newEquipmentIn = EquipmentIn(
equipment: equipment,
inDate: inDate,
type: equipmentType,
warehouseLocation: warehouseLocation,
partnerCompany: partnerCompany,
remark: remarkController.text.trim(),
);
dataService.addEquipmentIn(newEquipmentIn);
}
// 저장 후 리스트 재로딩 (중복 방지 및 최신화)
_loadManufacturers();
_loadEquipmentNames();
_loadCategories();
_loadSubCategories();
_loadSubSubCategories();
_loadWarehouseLocations();
_loadPartnerCompanies();
_loadWarrantyLicenses();
return true;
}
void dispose() {
remarkController.dispose();
}
}

View File

@@ -0,0 +1,170 @@
import 'package:superport/models/equipment_unified_model.dart';
import 'package:superport/services/mock_data_service.dart';
import 'package:superport/utils/constants.dart';
// companyTypeToString 함수 import
import 'package:superport/utils/constants.dart'
show companyTypeToString, CompanyType;
import 'package:superport/models/company_model.dart';
import 'package:superport/models/address_model.dart';
// 장비 목록 화면의 상태 및 비즈니스 로직을 담당하는 컨트롤러
class EquipmentListController {
final MockDataService dataService;
List<UnifiedEquipment> equipments = [];
String? selectedStatusFilter;
final Set<String> selectedEquipmentIds = {}; // 'id:status' 형식
EquipmentListController({required this.dataService});
// 데이터 로드 및 상태 필터 적용
void loadData() {
equipments = dataService.getAllEquipments();
if (selectedStatusFilter != null) {
equipments =
equipments.where((e) => e.status == selectedStatusFilter).toList();
}
selectedEquipmentIds.clear();
}
// 상태 필터 변경
void changeStatusFilter(String? status) {
selectedStatusFilter = status;
loadData();
}
// 장비 선택/해제 (모든 상태 지원)
void selectEquipment(int? id, String status, bool? isSelected) {
if (id == null || isSelected == null) return;
final key = '$id:$status';
if (isSelected) {
selectedEquipmentIds.add(key);
} else {
selectedEquipmentIds.remove(key);
}
}
// 선택된 입고 장비 수 반환
int getSelectedInStockCount() {
int count = 0;
for (final idStatusPair in selectedEquipmentIds) {
final parts = idStatusPair.split(':');
if (parts.length == 2 && parts[1] == EquipmentStatus.in_) {
count++;
}
}
return count;
}
// 선택된 전체 장비 수 반환
int getSelectedEquipmentCount() {
return selectedEquipmentIds.length;
}
// 선택된 특정 상태의 장비 수 반환
int getSelectedEquipmentCountByStatus(String status) {
int count = 0;
for (final idStatusPair in selectedEquipmentIds) {
final parts = idStatusPair.split(':');
if (parts.length == 2 && parts[1] == status) {
count++;
}
}
return count;
}
// 선택된 장비들의 UnifiedEquipment 객체 목록 반환
List<UnifiedEquipment> getSelectedEquipments() {
List<UnifiedEquipment> selected = [];
for (final idStatusPair in selectedEquipmentIds) {
final parts = idStatusPair.split(':');
if (parts.length == 2) {
final id = int.tryParse(parts[0]);
if (id != null) {
final equipment = equipments.firstWhere(
(e) => e.id == id && e.status == parts[1],
orElse: () => null as UnifiedEquipment,
);
if (equipment != null) {
selected.add(equipment);
}
}
}
}
return selected;
}
// 선택된 특정 상태의 장비들의 UnifiedEquipment 객체 목록 반환
List<UnifiedEquipment> getSelectedEquipmentsByStatus(String status) {
List<UnifiedEquipment> selected = [];
for (final idStatusPair in selectedEquipmentIds) {
final parts = idStatusPair.split(':');
if (parts.length == 2 && parts[1] == status) {
final id = int.tryParse(parts[0]);
if (id != null) {
final equipment = equipments.firstWhere(
(e) => e.id == id && e.status == status,
orElse: () => null as UnifiedEquipment,
);
if (equipment != null) {
selected.add(equipment);
}
}
}
}
return selected;
}
// 선택된 장비들의 요약 정보를 Map 형태로 반환 (출고/대여/폐기 폼에서 사용)
List<Map<String, dynamic>> getSelectedEquipmentsSummary() {
List<Map<String, dynamic>> summaryList = [];
List<UnifiedEquipment> selectedEquipmentsInStock =
getSelectedEquipmentsByStatus(EquipmentStatus.in_);
for (final equipment in selectedEquipmentsInStock) {
summaryList.add({
'equipment': equipment.equipment,
'equipmentInId': equipment.id,
'status': equipment.status,
});
}
return summaryList;
}
// 출고 정보(회사, 담당자, 라이센스 등) 반환
String getOutEquipmentInfo(int equipmentId, String infoType) {
final equipmentOut = dataService.getEquipmentOutById(equipmentId);
if (equipmentOut != null) {
switch (infoType) {
case 'company':
final company = equipmentOut.company ?? '-';
if (company != '-') {
final companyObj = dataService.getAllCompanies().firstWhere(
(c) => c.name == company,
orElse:
() => Company(
name: company,
address: Address(),
companyTypes: [CompanyType.customer], // 기본값 고객사
),
);
// 여러 유형 중 첫 번째만 표시 (대표 유형)
final typeText =
companyObj.companyTypes.isNotEmpty
? companyTypeToString(companyObj.companyTypes.first)
: '-';
return '$company (${typeText})';
}
return company;
case 'manager':
return equipmentOut.manager ?? '-';
case 'license':
return equipmentOut.license ?? '-';
default:
return '-';
}
}
return '-';
}
}

View File

@@ -0,0 +1,645 @@
import 'package:flutter/material.dart';
import 'package:superport/models/equipment_unified_model.dart';
import 'package:superport/models/company_model.dart';
import 'package:superport/models/address_model.dart';
import 'package:superport/services/mock_data_service.dart';
// 장비 출고 폼의 상태 및 비즈니스 로직을 담당하는 컨트롤러
class EquipmentOutFormController {
final MockDataService dataService;
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
final TextEditingController remarkController = TextEditingController();
// 상태 변수
bool isEditMode = false;
String manufacturer = '';
String name = '';
String category = '';
String subCategory = '';
String subSubCategory = '';
String serialNumber = '';
String barcode = '';
int quantity = 1;
DateTime outDate = DateTime.now();
bool hasSerialNumber = false;
DateTime? inDate;
String returnType = '재입고';
DateTime returnDate = DateTime.now();
bool hasManagers = false;
// 출고 유형(출고/대여/폐기) 상태 변수 추가
String outType = '출고'; // 기본값은 '출고'
// 기존 필드 - 호환성을 위해 유지
String? _selectedCompany;
String? get selectedCompany =>
selectedCompanies.isNotEmpty ? selectedCompanies[0] : null;
set selectedCompany(String? value) {
if (selectedCompanies.isEmpty) {
selectedCompanies.add(value);
} else {
selectedCompanies[0] = value;
}
_selectedCompany = value;
}
String? _selectedManager;
String? get selectedManager =>
selectedManagersPerCompany.isNotEmpty
? selectedManagersPerCompany[0]
: null;
set selectedManager(String? value) {
if (selectedManagersPerCompany.isEmpty) {
selectedManagersPerCompany.add(value);
} else {
selectedManagersPerCompany[0] = value;
}
_selectedManager = value;
}
String? selectedLicense;
List<String> companies = [];
// 회사 및 지점 관련 데이터
List<CompanyBranchInfo> companiesWithBranches = [];
List<String> managers = [];
List<String> filteredManagers = [];
List<String> licenses = [];
// 출고 회사 목록 관리
List<String?> selectedCompanies = [null]; // 첫 번째 드롭다운을 위한 초기값
List<List<String>> availableCompaniesPerDropdown =
[]; // 각 드롭다운마다 사용 가능한 회사 목록
List<String?> selectedManagersPerCompany = [null]; // 각 드롭다운 회사별 선택된 담당자
List<List<String>> filteredManagersPerCompany = []; // 각 드롭다운 회사별 필터링된 담당자 목록
List<bool> hasManagersPerCompany = [false]; // 각 회사별 담당자 유무
// 입력 데이터
Equipment? selectedEquipment;
int? selectedEquipmentInId;
int? equipmentOutId;
List<Map<String, dynamic>>? _selectedEquipments;
EquipmentOutFormController({required this.dataService});
// 선택된 장비 정보 설정 (디버그용)
set selectedEquipments(List<Map<String, dynamic>>? equipments) {
debugPrint('설정된 장비 목록: ${equipments?.length ?? 0}');
if (equipments != null) {
for (var i = 0; i < equipments.length; i++) {
final equipment = equipments[i]['equipment'] as Equipment;
debugPrint('장비 $i: ${equipment.manufacturer} ${equipment.name}');
}
}
_selectedEquipments = equipments;
}
List<Map<String, dynamic>>? get selectedEquipments => _selectedEquipments;
// 드롭다운 데이터 로드
void loadDropdownData() {
final allCompanies = dataService.getAllCompanies();
// 회사와 지점 통합 목록 생성
companiesWithBranches = [];
companies = [];
for (var company in allCompanies) {
// 회사 자체 정보 추가
final companyType =
company.companyTypes.isNotEmpty
? companyTypeToString(company.companyTypes.first)
: '-';
final companyInfo = CompanyBranchInfo(
id: company.id,
name: "${company.name} (${companyType})",
originalName: company.name,
isMainCompany: true,
companyId: company.id,
branchId: null,
);
companiesWithBranches.add(companyInfo);
companies.add(companyInfo.name);
// 지점 정보 추가
if (company.branches != null && company.branches!.isNotEmpty) {
for (var branch in company.branches!) {
final branchInfo = CompanyBranchInfo(
id: branch.id,
name: "${company.name} ${branch.name}",
displayName: branch.name,
originalName: branch.name,
isMainCompany: false,
companyId: company.id,
branchId: branch.id,
parentCompanyName: company.name,
);
companiesWithBranches.add(branchInfo);
companies.add(branchInfo.name);
}
}
}
// 나머지 데이터 로드
final allUsers = dataService.getAllUsers();
managers = allUsers.map((user) => user.name).toList();
filteredManagers = managers;
final allLicenses = dataService.getAllLicenses();
licenses = allLicenses.map((license) => license.name).toList();
if (companies.isEmpty) companies.add('기타');
if (managers.isEmpty) managers.add('기타');
if (licenses.isEmpty) licenses.add('기타');
updateManagersState();
// 출고 회사 드롭다운 초기화
availableCompaniesPerDropdown = [List.from(companies)];
filteredManagersPerCompany = [List.from(managers)];
hasManagersPerCompany = [hasManagers];
// 디버그 정보 출력
debugPrint('드롭다운 데이터 로드 완료');
debugPrint('장비 목록: ${_selectedEquipments?.length ?? 0}');
debugPrint('회사 및 지점 목록: ${companiesWithBranches.length}');
// 수정 모드인 경우 기존 선택값 동기화
if (isEditMode && equipmentOutId != null) {
final equipmentOut = dataService.getEquipmentOutById(equipmentOutId!);
if (equipmentOut != null && equipmentOut.company != null) {
String companyName = '';
// 회사 이름 찾기
for (String company in companies) {
if (company.startsWith(equipmentOut.company!)) {
companyName = company;
break;
}
}
if (companyName.isNotEmpty) {
selectedCompanies[0] = companyName;
filterManagersByCompanyAtIndex(companyName, 0);
// 기존 담당자 설정
if (equipmentOut.manager != null) {
selectedManagersPerCompany[0] = equipmentOut.manager;
}
}
// 라이센스 설정
if (equipmentOut.license != null) {
selectedLicense = equipmentOut.license;
}
}
}
}
// 회사에 따라 담당자 목록 필터링
void filterManagersByCompany(String? companyName) {
if (companyName == null || companyName.isEmpty) {
filteredManagers = managers;
} else {
// 회사 또는 지점 이름에서 CompanyBranchInfo 찾기
CompanyBranchInfo? companyInfo = _findCompanyInfoByDisplayName(
companyName,
);
if (companyInfo != null && companyInfo.companyId != null) {
int companyId = companyInfo.companyId!;
final companyUsers =
dataService
.getAllUsers()
.where((user) => user.companyId == companyId)
.toList();
if (companyUsers.isNotEmpty) {
filteredManagers = companyUsers.map((user) => user.name).toList();
} else {
filteredManagers = ['없음'];
}
} else {
filteredManagers = ['없음'];
}
}
if (selectedManager != null &&
!filteredManagers.contains(selectedManager)) {
selectedManager =
filteredManagers.isNotEmpty ? filteredManagers[0] : null;
}
updateManagersState();
// 첫 번째 회사에 대한 담당자 목록과 동기화
if (filteredManagersPerCompany.isNotEmpty) {
filteredManagersPerCompany[0] = List.from(filteredManagers);
hasManagersPerCompany[0] = hasManagers;
if (selectedManagersPerCompany.isNotEmpty) {
selectedManagersPerCompany[0] = selectedManager;
}
}
}
// 특정 인덱스의 회사에 따라 담당자 목록 필터링
void filterManagersByCompanyAtIndex(String? companyName, int index) {
if (companyName == null || companyName.isEmpty) {
filteredManagersPerCompany[index] = managers;
} else {
// 회사 또는 지점 이름에서 CompanyBranchInfo 찾기
CompanyBranchInfo? companyInfo = _findCompanyInfoByDisplayName(
companyName,
);
if (companyInfo != null && companyInfo.companyId != null) {
int companyId = companyInfo.companyId!;
final companyUsers =
dataService
.getAllUsers()
.where((user) => user.companyId == companyId)
.toList();
if (companyUsers.isNotEmpty) {
filteredManagersPerCompany[index] =
companyUsers.map((user) => user.name).toList();
} else {
filteredManagersPerCompany[index] = ['없음'];
}
} else {
filteredManagersPerCompany[index] = ['없음'];
}
}
if (selectedManagersPerCompany[index] != null &&
!filteredManagersPerCompany[index].contains(
selectedManagersPerCompany[index],
)) {
selectedManagersPerCompany[index] =
filteredManagersPerCompany[index].isNotEmpty
? filteredManagersPerCompany[index][0]
: null;
}
updateManagersStateAtIndex(index);
// 첫 번째 회사인 경우 기존 필드와 동기화
if (index == 0) {
filteredManagers = List.from(filteredManagersPerCompany[0]);
hasManagers = hasManagersPerCompany[0];
_selectedManager = selectedManagersPerCompany[0];
}
}
// 담당자 있는지 상태 업데이트
void updateManagersState() {
hasManagers =
filteredManagers.isNotEmpty &&
!(filteredManagers.length == 1 && filteredManagers[0] == '없음');
}
// 특정 인덱스의 담당자 상태 업데이트
void updateManagersStateAtIndex(int index) {
hasManagersPerCompany[index] =
filteredManagersPerCompany[index].isNotEmpty &&
!(filteredManagersPerCompany[index].length == 1 &&
filteredManagersPerCompany[index][0] == '없음');
}
// 출고 회사 추가
void addCompany() {
// 이미 선택된 회사 제외한 리스트 생성
List<String> availableCompanies = List.from(companies);
for (String? company in selectedCompanies) {
if (company != null) {
availableCompanies.remove(company);
}
}
// 새 드롭다운 추가
selectedCompanies.add(null);
availableCompaniesPerDropdown.add(availableCompanies);
selectedManagersPerCompany.add(null);
filteredManagersPerCompany.add(List.from(managers));
hasManagersPerCompany.add(false);
}
// 가능한 회사 목록 업데이트
void updateAvailableCompanies() {
// 각 드롭다운에 대해 사용 가능한 회사 목록 업데이트
for (int i = 0; i < selectedCompanies.length; i++) {
List<String> availableCompanies = List.from(companies);
// 이미 선택된 회사 제외
for (int j = 0; j < selectedCompanies.length; j++) {
if (i != j && selectedCompanies[j] != null) {
availableCompanies.remove(selectedCompanies[j]);
}
}
availableCompaniesPerDropdown[i] = availableCompanies;
}
}
// 선택 장비로 초기화
void initializeWithSelectedEquipment(Equipment equipment) {
manufacturer = equipment.manufacturer;
name = equipment.name;
category = equipment.category;
subCategory = equipment.subCategory;
subSubCategory = equipment.subSubCategory;
serialNumber = equipment.serialNumber ?? '';
barcode = equipment.barcode ?? '';
quantity = equipment.quantity;
hasSerialNumber = serialNumber.isNotEmpty;
inDate = equipment.inDate;
remarkController.text = equipment.remark ?? '';
}
// 회사/지점 표시 이름을 통해 CompanyBranchInfo 객체 찾기
CompanyBranchInfo? _findCompanyInfoByDisplayName(String displayName) {
for (var info in companiesWithBranches) {
if (info.name == displayName) {
return info;
}
}
return null;
}
// 출고 정보 저장 (UI에서 호출)
void saveEquipmentOut(Function(String) onSuccess, Function(String) onError) {
if (formKey.currentState?.validate() != true) {
onError('폼 유효성 검사 실패');
return;
}
formKey.currentState?.save();
// 선택된 회사가 없는지 확인
bool hasAnySelectedCompany = selectedCompanies.any(
(company) => company != null,
);
if (!hasAnySelectedCompany) {
onError('최소 하나의 출고 회사를 선택해주세요');
return;
}
// 기존 방식으로 첫 번째 회사 정보 처리
String? companyName;
if (selectedCompanies.isNotEmpty && selectedCompanies[0] != null) {
CompanyBranchInfo? companyInfo = _findCompanyInfoByDisplayName(
selectedCompanies[0]!,
);
if (companyInfo != null) {
companyName =
companyInfo.isMainCompany
? companyInfo
.originalName // 본사인 경우 회사 원래 이름
: "${companyInfo.originalName} (${companyInfo.branchId})"; // 지점인 경우 지점 정보 포함
} else {
companyName = selectedCompanies[0]!.replaceAll(
RegExp(r' \(.*\)\$'),
'',
);
}
} else {
onError('최소 하나의 출고 회사를 선택해주세요');
return;
}
if (isEditMode && equipmentOutId != null) {
final equipmentOut = dataService.getEquipmentOutById(equipmentOutId!);
if (equipmentOut != null) {
final updatedEquipmentOut = EquipmentOut(
id: equipmentOut.id,
equipment: equipmentOut.equipment,
outDate: equipmentOut.outDate,
status: returnType == '재입고' ? 'I' : 'R',
company: companyName,
manager: equipmentOut.manager,
license: equipmentOut.license,
returnDate: returnDate,
returnType: returnType,
remark: remarkController.text.trim(),
);
dataService.updateEquipmentOut(updatedEquipmentOut);
onSuccess('장비 출고 상태 변경 완료');
} else {
onError('출고 정보를 찾을 수 없습니다');
}
} else {
if (selectedEquipments != null && selectedEquipments!.isNotEmpty) {
// 여러 회사에 각각 출고 처리
List<String> successCompanies = [];
// 선택된 모든 회사에 대해 출고 처리
for (int i = 0; i < selectedCompanies.length; i++) {
if (selectedCompanies[i] == null) continue;
CompanyBranchInfo? companyInfo = _findCompanyInfoByDisplayName(
selectedCompanies[i]!,
);
String curCompanyName;
if (companyInfo != null) {
curCompanyName =
companyInfo.isMainCompany
? companyInfo
.originalName // 본사인 경우 회사 원래 이름
: "${companyInfo.originalName} (${companyInfo.branchId})"; // 지점인 경우 지점 정보 포함
} else {
curCompanyName = selectedCompanies[i]!.replaceAll(
RegExp(r' \(.*\)\$'),
'',
);
}
String? curManager = selectedManagersPerCompany[i];
if (curManager == null || curManager == '없음') {
// 담당자 없는 회사는 건너뛰기
continue;
}
// 해당 회사에 모든 장비 출고 처리
for (final equipmentData in selectedEquipments!) {
final equipment = equipmentData['equipment'] as Equipment;
final equipmentInId = equipmentData['equipmentInId'] as int;
final newEquipmentOut = EquipmentOut(
equipment: equipment,
outDate: outDate,
company: curCompanyName,
manager: curManager,
license: selectedLicense,
remark: remarkController.text.trim(),
);
dataService.changeEquipmentStatus(equipmentInId, newEquipmentOut);
}
successCompanies.add(companyInfo?.name ?? curCompanyName);
}
if (successCompanies.isEmpty) {
onError('모든 회사에 담당자가 없어 출고 처리할 수 없습니다');
} else {
onSuccess('${successCompanies.join(", ")} 회사로 다중 장비 출고 처리 완료');
}
} else if (selectedEquipmentInId != null) {
final equipment = Equipment(
manufacturer: manufacturer,
name: name,
category: category,
subCategory: subCategory,
subSubCategory: subSubCategory,
serialNumber: (hasSerialNumber) ? serialNumber : null,
barcode: barcode.isNotEmpty ? barcode : null,
quantity: quantity,
inDate: inDate,
remark: remarkController.text.trim(),
);
// 선택된 모든 회사에 대해 출고 처리
List<String> successCompanies = [];
for (int i = 0; i < selectedCompanies.length; i++) {
if (selectedCompanies[i] == null) continue;
CompanyBranchInfo? companyInfo = _findCompanyInfoByDisplayName(
selectedCompanies[i]!,
);
String curCompanyName;
if (companyInfo != null) {
curCompanyName =
companyInfo.isMainCompany
? companyInfo
.originalName // 본사인 경우 회사 원래 이름
: "${companyInfo.originalName} (${companyInfo.branchId})"; // 지점인 경우 지점 정보 포함
} else {
curCompanyName = selectedCompanies[i]!.replaceAll(
RegExp(r' \(.*\)\$'),
'',
);
}
String? curManager = selectedManagersPerCompany[i];
if (curManager == null || curManager == '없음') {
// 담당자 없는 회사는 건너뛰기
continue;
}
final newEquipmentOut = EquipmentOut(
equipment: equipment,
outDate: outDate,
company: curCompanyName,
manager: curManager,
license: selectedLicense,
remark: remarkController.text.trim(),
);
dataService.changeEquipmentStatus(
selectedEquipmentInId!,
newEquipmentOut,
);
successCompanies.add(companyInfo?.name ?? curCompanyName);
break; // 한 장비는 한 회사에만 출고
}
if (successCompanies.isEmpty) {
onError('모든 회사에 담당자가 없어 출고 처리할 수 없습니다');
} else {
onSuccess('${successCompanies.join(", ")} 회사로 장비 출고 처리 완료');
}
} else {
final equipment = Equipment(
manufacturer: manufacturer,
name: name,
category: category,
subCategory: subCategory,
subSubCategory: subSubCategory,
serialNumber: null,
barcode: null,
quantity: 1,
inDate: inDate,
remark: remarkController.text.trim(),
);
// 선택된 모든 회사에 대해 출고 처리
List<String> successCompanies = [];
for (int i = 0; i < selectedCompanies.length; i++) {
if (selectedCompanies[i] == null) continue;
CompanyBranchInfo? companyInfo = _findCompanyInfoByDisplayName(
selectedCompanies[i]!,
);
String curCompanyName;
if (companyInfo != null) {
curCompanyName =
companyInfo.isMainCompany
? companyInfo
.originalName // 본사인 경우 회사 원래 이름
: "${companyInfo.originalName} (${companyInfo.branchId})"; // 지점인 경우 지점 정보 포함
} else {
curCompanyName = selectedCompanies[i]!.replaceAll(
RegExp(r' \(.*\)\$'),
'',
);
}
String? curManager = selectedManagersPerCompany[i];
if (curManager == null || curManager == '없음') {
// 담당자 없는 회사는 건너뛰기
continue;
}
final newEquipmentOut = EquipmentOut(
equipment: equipment,
outDate: outDate,
company: curCompanyName,
manager: curManager,
license: selectedLicense,
remark: remarkController.text.trim(),
);
dataService.addEquipmentOut(newEquipmentOut);
successCompanies.add(companyInfo?.name ?? curCompanyName);
}
if (successCompanies.isEmpty) {
onError('모든 회사에 담당자가 없어 출고 처리할 수 없습니다');
} else {
onSuccess('${successCompanies.join(", ")} 회사로 새 출고 장비 추가 완료');
}
}
}
}
// 날짜 포맷 유틸리티
String formatDate(DateTime date) {
return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
}
void dispose() {
remarkController.dispose();
}
}
/// 회사 및 지점 정보를 저장하는 클래스
class CompanyBranchInfo {
final int? id;
final String name; // 표시용 이름 (회사명 + 지점명 또는 회사명 (유형))
final String originalName; // 원래 이름 (회사 본사명 또는 지점명)
final String? displayName; // UI에 표시할 이름 (주로 지점명)
final bool isMainCompany; // 본사인지 지점인지 구분
final int? companyId; // 회사 ID
final int? branchId; // 지점 ID
final String? parentCompanyName; // 부모 회사명 (지점인 경우)
CompanyBranchInfo({
required this.id,
required this.name,
required this.originalName,
this.displayName,
required this.isMainCompany,
required this.companyId,
required this.branchId,
this.parentCompanyName,
});
}