diff --git a/API_ISSUES.md b/API_ISSUES.md index 5add153..0214e43 100644 --- a/API_ISSUES.md +++ b/API_ISSUES.md @@ -1,6 +1,19 @@ # Superport API 개선 사항 -## 1. 회사 목록 API에 company_types 필드 누락 +## 1. ✅ [해결됨] 회사 목록 API에 company_types 필드 누락 및 제거 대응 + +### 최종 해결 내역 (2025-01-09) +- **백엔드 변경사항**: + - company_types 필드 제거 예정 + - is_partner, is_customer 필드로 대체 + +- **프론트엔드 대응 (완료)**: + - CompanyListDto, CompanyResponse, CompanyBranchFlatDto에 is_partner, is_customer 필드 추가 (@Default(false)) + - CompanyService 변환 로직 수정 (하위 호환성 유지): + - company_types가 있으면 우선 사용 + - company_types가 없으면 is_partner/is_customer 사용 + - 둘 다 없으면 빈 리스트 반환 + - 사이드 이펙트 없음 확인 (테스트 완료) ### 현재 상황 - **문제 엔드포인트**: diff --git a/lib/data/models/company/company_branch_flat_dto.dart b/lib/data/models/company/company_branch_flat_dto.dart index 2b415ec..8f613b0 100644 --- a/lib/data/models/company/company_branch_flat_dto.dart +++ b/lib/data/models/company/company_branch_flat_dto.dart @@ -11,6 +11,9 @@ class CompanyBranchFlatDto with _$CompanyBranchFlatDto { @JsonKey(name: 'company_name') required String companyName, @JsonKey(name: 'branch_id') int? branchId, @JsonKey(name: 'branch_name') String? branchName, + @JsonKey(name: 'company_types') List? companyTypes, + @JsonKey(name: 'is_partner') @Default(false) bool isPartner, + @JsonKey(name: 'is_customer') @Default(false) bool isCustomer, }) = _CompanyBranchFlatDto; factory CompanyBranchFlatDto.fromJson(Map json) => diff --git a/lib/data/models/company/company_branch_flat_dto.freezed.dart b/lib/data/models/company/company_branch_flat_dto.freezed.dart index 8dd08f8..af1f6ff 100644 --- a/lib/data/models/company/company_branch_flat_dto.freezed.dart +++ b/lib/data/models/company/company_branch_flat_dto.freezed.dart @@ -28,6 +28,12 @@ mixin _$CompanyBranchFlatDto { int? get branchId => throw _privateConstructorUsedError; @JsonKey(name: 'branch_name') String? get branchName => throw _privateConstructorUsedError; + @JsonKey(name: 'company_types') + List? get companyTypes => throw _privateConstructorUsedError; + @JsonKey(name: 'is_partner') + bool get isPartner => throw _privateConstructorUsedError; + @JsonKey(name: 'is_customer') + bool get isCustomer => throw _privateConstructorUsedError; /// Serializes this CompanyBranchFlatDto to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -49,7 +55,10 @@ abstract class $CompanyBranchFlatDtoCopyWith<$Res> { {@JsonKey(name: 'company_id') int companyId, @JsonKey(name: 'company_name') String companyName, @JsonKey(name: 'branch_id') int? branchId, - @JsonKey(name: 'branch_name') String? branchName}); + @JsonKey(name: 'branch_name') String? branchName, + @JsonKey(name: 'company_types') List? companyTypes, + @JsonKey(name: 'is_partner') bool isPartner, + @JsonKey(name: 'is_customer') bool isCustomer}); } /// @nodoc @@ -72,6 +81,9 @@ class _$CompanyBranchFlatDtoCopyWithImpl<$Res, Object? companyName = null, Object? branchId = freezed, Object? branchName = freezed, + Object? companyTypes = freezed, + Object? isPartner = null, + Object? isCustomer = null, }) { return _then(_value.copyWith( companyId: null == companyId @@ -90,6 +102,18 @@ class _$CompanyBranchFlatDtoCopyWithImpl<$Res, ? _value.branchName : branchName // ignore: cast_nullable_to_non_nullable as String?, + companyTypes: freezed == companyTypes + ? _value.companyTypes + : companyTypes // ignore: cast_nullable_to_non_nullable + as List?, + isPartner: null == isPartner + ? _value.isPartner + : isPartner // ignore: cast_nullable_to_non_nullable + as bool, + isCustomer: null == isCustomer + ? _value.isCustomer + : isCustomer // ignore: cast_nullable_to_non_nullable + as bool, ) as $Val); } } @@ -106,7 +130,10 @@ abstract class _$$CompanyBranchFlatDtoImplCopyWith<$Res> {@JsonKey(name: 'company_id') int companyId, @JsonKey(name: 'company_name') String companyName, @JsonKey(name: 'branch_id') int? branchId, - @JsonKey(name: 'branch_name') String? branchName}); + @JsonKey(name: 'branch_name') String? branchName, + @JsonKey(name: 'company_types') List? companyTypes, + @JsonKey(name: 'is_partner') bool isPartner, + @JsonKey(name: 'is_customer') bool isCustomer}); } /// @nodoc @@ -126,6 +153,9 @@ class __$$CompanyBranchFlatDtoImplCopyWithImpl<$Res> Object? companyName = null, Object? branchId = freezed, Object? branchName = freezed, + Object? companyTypes = freezed, + Object? isPartner = null, + Object? isCustomer = null, }) { return _then(_$CompanyBranchFlatDtoImpl( companyId: null == companyId @@ -144,6 +174,18 @@ class __$$CompanyBranchFlatDtoImplCopyWithImpl<$Res> ? _value.branchName : branchName // ignore: cast_nullable_to_non_nullable as String?, + companyTypes: freezed == companyTypes + ? _value._companyTypes + : companyTypes // ignore: cast_nullable_to_non_nullable + as List?, + isPartner: null == isPartner + ? _value.isPartner + : isPartner // ignore: cast_nullable_to_non_nullable + as bool, + isCustomer: null == isCustomer + ? _value.isCustomer + : isCustomer // ignore: cast_nullable_to_non_nullable + as bool, )); } } @@ -155,7 +197,11 @@ class _$CompanyBranchFlatDtoImpl implements _CompanyBranchFlatDto { {@JsonKey(name: 'company_id') required this.companyId, @JsonKey(name: 'company_name') required this.companyName, @JsonKey(name: 'branch_id') this.branchId, - @JsonKey(name: 'branch_name') this.branchName}); + @JsonKey(name: 'branch_name') this.branchName, + @JsonKey(name: 'company_types') final List? companyTypes, + @JsonKey(name: 'is_partner') this.isPartner = false, + @JsonKey(name: 'is_customer') this.isCustomer = false}) + : _companyTypes = companyTypes; factory _$CompanyBranchFlatDtoImpl.fromJson(Map json) => _$$CompanyBranchFlatDtoImplFromJson(json); @@ -172,10 +218,27 @@ class _$CompanyBranchFlatDtoImpl implements _CompanyBranchFlatDto { @override @JsonKey(name: 'branch_name') final String? branchName; + final List? _companyTypes; + @override + @JsonKey(name: 'company_types') + List? get companyTypes { + final value = _companyTypes; + if (value == null) return null; + if (_companyTypes is EqualUnmodifiableListView) return _companyTypes; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + @JsonKey(name: 'is_partner') + final bool isPartner; + @override + @JsonKey(name: 'is_customer') + final bool isCustomer; @override String toString() { - return 'CompanyBranchFlatDto(companyId: $companyId, companyName: $companyName, branchId: $branchId, branchName: $branchName)'; + return 'CompanyBranchFlatDto(companyId: $companyId, companyName: $companyName, branchId: $branchId, branchName: $branchName, companyTypes: $companyTypes, isPartner: $isPartner, isCustomer: $isCustomer)'; } @override @@ -190,13 +253,26 @@ class _$CompanyBranchFlatDtoImpl implements _CompanyBranchFlatDto { (identical(other.branchId, branchId) || other.branchId == branchId) && (identical(other.branchName, branchName) || - other.branchName == branchName)); + other.branchName == branchName) && + const DeepCollectionEquality() + .equals(other._companyTypes, _companyTypes) && + (identical(other.isPartner, isPartner) || + other.isPartner == isPartner) && + (identical(other.isCustomer, isCustomer) || + other.isCustomer == isCustomer)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => - Object.hash(runtimeType, companyId, companyName, branchId, branchName); + int get hashCode => Object.hash( + runtimeType, + companyId, + companyName, + branchId, + branchName, + const DeepCollectionEquality().hash(_companyTypes), + isPartner, + isCustomer); /// Create a copy of CompanyBranchFlatDto /// with the given fields replaced by the non-null parameter values. @@ -221,7 +297,10 @@ abstract class _CompanyBranchFlatDto implements CompanyBranchFlatDto { {@JsonKey(name: 'company_id') required final int companyId, @JsonKey(name: 'company_name') required final String companyName, @JsonKey(name: 'branch_id') final int? branchId, - @JsonKey(name: 'branch_name') final String? branchName}) = + @JsonKey(name: 'branch_name') final String? branchName, + @JsonKey(name: 'company_types') final List? companyTypes, + @JsonKey(name: 'is_partner') final bool isPartner, + @JsonKey(name: 'is_customer') final bool isCustomer}) = _$CompanyBranchFlatDtoImpl; factory _CompanyBranchFlatDto.fromJson(Map json) = @@ -239,6 +318,15 @@ abstract class _CompanyBranchFlatDto implements CompanyBranchFlatDto { @override @JsonKey(name: 'branch_name') String? get branchName; + @override + @JsonKey(name: 'company_types') + List? get companyTypes; + @override + @JsonKey(name: 'is_partner') + bool get isPartner; + @override + @JsonKey(name: 'is_customer') + bool get isCustomer; /// Create a copy of CompanyBranchFlatDto /// with the given fields replaced by the non-null parameter values. diff --git a/lib/data/models/company/company_branch_flat_dto.g.dart b/lib/data/models/company/company_branch_flat_dto.g.dart index feafa04..857e338 100644 --- a/lib/data/models/company/company_branch_flat_dto.g.dart +++ b/lib/data/models/company/company_branch_flat_dto.g.dart @@ -13,6 +13,11 @@ _$CompanyBranchFlatDtoImpl _$$CompanyBranchFlatDtoImplFromJson( companyName: json['company_name'] as String, branchId: (json['branch_id'] as num?)?.toInt(), branchName: json['branch_name'] as String?, + companyTypes: (json['company_types'] as List?) + ?.map((e) => e as String) + .toList(), + isPartner: json['is_partner'] as bool? ?? false, + isCustomer: json['is_customer'] as bool? ?? false, ); Map _$$CompanyBranchFlatDtoImplToJson( @@ -22,4 +27,7 @@ Map _$$CompanyBranchFlatDtoImplToJson( 'company_name': instance.companyName, 'branch_id': instance.branchId, 'branch_name': instance.branchName, + 'company_types': instance.companyTypes, + 'is_partner': instance.isPartner, + 'is_customer': instance.isCustomer, }; diff --git a/lib/data/models/company/company_dto.dart b/lib/data/models/company/company_dto.dart index 53f7bed..ff8aa26 100644 --- a/lib/data/models/company/company_dto.dart +++ b/lib/data/models/company/company_dto.dart @@ -51,6 +51,8 @@ class CompanyResponse with _$CompanyResponse { @JsonKey(name: 'company_types') @Default([]) List companyTypes, String? remark, @JsonKey(name: 'is_active') required bool isActive, + @JsonKey(name: 'is_partner') @Default(false) bool isPartner, + @JsonKey(name: 'is_customer') @Default(false) bool isCustomer, @JsonKey(name: 'created_at') required DateTime createdAt, @JsonKey(name: 'updated_at') DateTime? updatedAt, // nullable로 변경 @JsonKey(name: 'address_id') int? addressId, diff --git a/lib/data/models/company/company_dto.freezed.dart b/lib/data/models/company/company_dto.freezed.dart index 21e9e84..e9e8856 100644 --- a/lib/data/models/company/company_dto.freezed.dart +++ b/lib/data/models/company/company_dto.freezed.dart @@ -730,6 +730,10 @@ mixin _$CompanyResponse { String? get remark => throw _privateConstructorUsedError; @JsonKey(name: 'is_active') bool get isActive => throw _privateConstructorUsedError; + @JsonKey(name: 'is_partner') + bool get isPartner => throw _privateConstructorUsedError; + @JsonKey(name: 'is_customer') + bool get isCustomer => throw _privateConstructorUsedError; @JsonKey(name: 'created_at') DateTime get createdAt => throw _privateConstructorUsedError; @JsonKey(name: 'updated_at') @@ -764,6 +768,8 @@ abstract class $CompanyResponseCopyWith<$Res> { @JsonKey(name: 'company_types') List companyTypes, String? remark, @JsonKey(name: 'is_active') bool isActive, + @JsonKey(name: 'is_partner') bool isPartner, + @JsonKey(name: 'is_customer') bool isCustomer, @JsonKey(name: 'created_at') DateTime createdAt, @JsonKey(name: 'updated_at') DateTime? updatedAt, @JsonKey(name: 'address_id') int? addressId}); @@ -794,6 +800,8 @@ class _$CompanyResponseCopyWithImpl<$Res, $Val extends CompanyResponse> Object? companyTypes = null, Object? remark = freezed, Object? isActive = null, + Object? isPartner = null, + Object? isCustomer = null, Object? createdAt = null, Object? updatedAt = freezed, Object? addressId = freezed, @@ -839,6 +847,14 @@ class _$CompanyResponseCopyWithImpl<$Res, $Val extends CompanyResponse> ? _value.isActive : isActive // ignore: cast_nullable_to_non_nullable as bool, + isPartner: null == isPartner + ? _value.isPartner + : isPartner // ignore: cast_nullable_to_non_nullable + as bool, + isCustomer: null == isCustomer + ? _value.isCustomer + : isCustomer // ignore: cast_nullable_to_non_nullable + as bool, createdAt: null == createdAt ? _value.createdAt : createdAt // ignore: cast_nullable_to_non_nullable @@ -874,6 +890,8 @@ abstract class _$$CompanyResponseImplCopyWith<$Res> @JsonKey(name: 'company_types') List companyTypes, String? remark, @JsonKey(name: 'is_active') bool isActive, + @JsonKey(name: 'is_partner') bool isPartner, + @JsonKey(name: 'is_customer') bool isCustomer, @JsonKey(name: 'created_at') DateTime createdAt, @JsonKey(name: 'updated_at') DateTime? updatedAt, @JsonKey(name: 'address_id') int? addressId}); @@ -902,6 +920,8 @@ class __$$CompanyResponseImplCopyWithImpl<$Res> Object? companyTypes = null, Object? remark = freezed, Object? isActive = null, + Object? isPartner = null, + Object? isCustomer = null, Object? createdAt = null, Object? updatedAt = freezed, Object? addressId = freezed, @@ -947,6 +967,14 @@ class __$$CompanyResponseImplCopyWithImpl<$Res> ? _value.isActive : isActive // ignore: cast_nullable_to_non_nullable as bool, + isPartner: null == isPartner + ? _value.isPartner + : isPartner // ignore: cast_nullable_to_non_nullable + as bool, + isCustomer: null == isCustomer + ? _value.isCustomer + : isCustomer // ignore: cast_nullable_to_non_nullable + as bool, createdAt: null == createdAt ? _value.createdAt : createdAt // ignore: cast_nullable_to_non_nullable @@ -978,6 +1006,8 @@ class _$CompanyResponseImpl implements _CompanyResponse { final List companyTypes = const [], this.remark, @JsonKey(name: 'is_active') required this.isActive, + @JsonKey(name: 'is_partner') this.isPartner = false, + @JsonKey(name: 'is_customer') this.isCustomer = false, @JsonKey(name: 'created_at') required this.createdAt, @JsonKey(name: 'updated_at') this.updatedAt, @JsonKey(name: 'address_id') this.addressId}) @@ -1020,6 +1050,12 @@ class _$CompanyResponseImpl implements _CompanyResponse { @JsonKey(name: 'is_active') final bool isActive; @override + @JsonKey(name: 'is_partner') + final bool isPartner; + @override + @JsonKey(name: 'is_customer') + final bool isCustomer; + @override @JsonKey(name: 'created_at') final DateTime createdAt; @override @@ -1032,7 +1068,7 @@ class _$CompanyResponseImpl implements _CompanyResponse { @override String toString() { - return 'CompanyResponse(id: $id, name: $name, address: $address, contactName: $contactName, contactPosition: $contactPosition, contactPhone: $contactPhone, contactEmail: $contactEmail, companyTypes: $companyTypes, remark: $remark, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt, addressId: $addressId)'; + return 'CompanyResponse(id: $id, name: $name, address: $address, contactName: $contactName, contactPosition: $contactPosition, contactPhone: $contactPhone, contactEmail: $contactEmail, companyTypes: $companyTypes, remark: $remark, isActive: $isActive, isPartner: $isPartner, isCustomer: $isCustomer, createdAt: $createdAt, updatedAt: $updatedAt, addressId: $addressId)'; } @override @@ -1056,6 +1092,10 @@ class _$CompanyResponseImpl implements _CompanyResponse { (identical(other.remark, remark) || other.remark == remark) && (identical(other.isActive, isActive) || other.isActive == isActive) && + (identical(other.isPartner, isPartner) || + other.isPartner == isPartner) && + (identical(other.isCustomer, isCustomer) || + other.isCustomer == isCustomer) && (identical(other.createdAt, createdAt) || other.createdAt == createdAt) && (identical(other.updatedAt, updatedAt) || @@ -1078,6 +1118,8 @@ class _$CompanyResponseImpl implements _CompanyResponse { const DeepCollectionEquality().hash(_companyTypes), remark, isActive, + isPartner, + isCustomer, createdAt, updatedAt, addressId); @@ -1111,6 +1153,8 @@ abstract class _CompanyResponse implements CompanyResponse { @JsonKey(name: 'company_types') final List companyTypes, final String? remark, @JsonKey(name: 'is_active') required final bool isActive, + @JsonKey(name: 'is_partner') final bool isPartner, + @JsonKey(name: 'is_customer') final bool isCustomer, @JsonKey(name: 'created_at') required final DateTime createdAt, @JsonKey(name: 'updated_at') final DateTime? updatedAt, @JsonKey(name: 'address_id') final int? addressId}) = @@ -1146,6 +1190,12 @@ abstract class _CompanyResponse implements CompanyResponse { @JsonKey(name: 'is_active') bool get isActive; @override + @JsonKey(name: 'is_partner') + bool get isPartner; + @override + @JsonKey(name: 'is_customer') + bool get isCustomer; + @override @JsonKey(name: 'created_at') DateTime get createdAt; @override diff --git a/lib/data/models/company/company_dto.g.dart b/lib/data/models/company/company_dto.g.dart index b16305c..946aecd 100644 --- a/lib/data/models/company/company_dto.g.dart +++ b/lib/data/models/company/company_dto.g.dart @@ -81,6 +81,8 @@ _$CompanyResponseImpl _$$CompanyResponseImplFromJson( const [], remark: json['remark'] as String?, isActive: json['is_active'] as bool, + isPartner: json['is_partner'] as bool? ?? false, + isCustomer: json['is_customer'] as bool? ?? false, createdAt: DateTime.parse(json['created_at'] as String), updatedAt: json['updated_at'] == null ? null @@ -101,6 +103,8 @@ Map _$$CompanyResponseImplToJson( 'company_types': instance.companyTypes, 'remark': instance.remark, 'is_active': instance.isActive, + 'is_partner': instance.isPartner, + 'is_customer': instance.isCustomer, 'created_at': instance.createdAt.toIso8601String(), 'updated_at': instance.updatedAt?.toIso8601String(), 'address_id': instance.addressId, diff --git a/lib/data/models/company/company_list_dto.dart b/lib/data/models/company/company_list_dto.dart index 2391b5f..0cd461e 100644 --- a/lib/data/models/company/company_list_dto.dart +++ b/lib/data/models/company/company_list_dto.dart @@ -10,11 +10,14 @@ class CompanyListDto with _$CompanyListDto { const factory CompanyListDto({ required int id, required String name, - required String address, + String? address, @JsonKey(name: 'contact_name') String? contactName, @JsonKey(name: 'contact_phone') String? contactPhone, @JsonKey(name: 'contact_email') String? contactEmail, + @JsonKey(name: 'company_types') List? companyTypes, @JsonKey(name: 'is_active') required bool isActive, + @JsonKey(name: 'is_partner') @Default(false) bool isPartner, + @JsonKey(name: 'is_customer') @Default(false) bool isCustomer, @JsonKey(name: 'created_at') DateTime? createdAt, @JsonKey(name: 'branch_count') @Default(0) int branchCount, }) = _CompanyListDto; diff --git a/lib/data/models/company/company_list_dto.freezed.dart b/lib/data/models/company/company_list_dto.freezed.dart index e2a3826..dd10861 100644 --- a/lib/data/models/company/company_list_dto.freezed.dart +++ b/lib/data/models/company/company_list_dto.freezed.dart @@ -22,15 +22,21 @@ CompanyListDto _$CompanyListDtoFromJson(Map json) { mixin _$CompanyListDto { int get id => throw _privateConstructorUsedError; String get name => throw _privateConstructorUsedError; - String get address => throw _privateConstructorUsedError; + String? get address => throw _privateConstructorUsedError; @JsonKey(name: 'contact_name') String? get contactName => throw _privateConstructorUsedError; @JsonKey(name: 'contact_phone') String? get contactPhone => throw _privateConstructorUsedError; @JsonKey(name: 'contact_email') String? get contactEmail => throw _privateConstructorUsedError; + @JsonKey(name: 'company_types') + List? get companyTypes => throw _privateConstructorUsedError; @JsonKey(name: 'is_active') bool get isActive => throw _privateConstructorUsedError; + @JsonKey(name: 'is_partner') + bool get isPartner => throw _privateConstructorUsedError; + @JsonKey(name: 'is_customer') + bool get isCustomer => throw _privateConstructorUsedError; @JsonKey(name: 'created_at') DateTime? get createdAt => throw _privateConstructorUsedError; @JsonKey(name: 'branch_count') @@ -55,11 +61,14 @@ abstract class $CompanyListDtoCopyWith<$Res> { $Res call( {int id, String name, - String address, + String? address, @JsonKey(name: 'contact_name') String? contactName, @JsonKey(name: 'contact_phone') String? contactPhone, @JsonKey(name: 'contact_email') String? contactEmail, + @JsonKey(name: 'company_types') List? companyTypes, @JsonKey(name: 'is_active') bool isActive, + @JsonKey(name: 'is_partner') bool isPartner, + @JsonKey(name: 'is_customer') bool isCustomer, @JsonKey(name: 'created_at') DateTime? createdAt, @JsonKey(name: 'branch_count') int branchCount}); } @@ -81,11 +90,14 @@ class _$CompanyListDtoCopyWithImpl<$Res, $Val extends CompanyListDto> $Res call({ Object? id = null, Object? name = null, - Object? address = null, + Object? address = freezed, Object? contactName = freezed, Object? contactPhone = freezed, Object? contactEmail = freezed, + Object? companyTypes = freezed, Object? isActive = null, + Object? isPartner = null, + Object? isCustomer = null, Object? createdAt = freezed, Object? branchCount = null, }) { @@ -98,10 +110,10 @@ class _$CompanyListDtoCopyWithImpl<$Res, $Val extends CompanyListDto> ? _value.name : name // ignore: cast_nullable_to_non_nullable as String, - address: null == address + address: freezed == address ? _value.address : address // ignore: cast_nullable_to_non_nullable - as String, + as String?, contactName: freezed == contactName ? _value.contactName : contactName // ignore: cast_nullable_to_non_nullable @@ -114,10 +126,22 @@ class _$CompanyListDtoCopyWithImpl<$Res, $Val extends CompanyListDto> ? _value.contactEmail : contactEmail // ignore: cast_nullable_to_non_nullable as String?, + companyTypes: freezed == companyTypes + ? _value.companyTypes + : companyTypes // ignore: cast_nullable_to_non_nullable + as List?, isActive: null == isActive ? _value.isActive : isActive // ignore: cast_nullable_to_non_nullable as bool, + isPartner: null == isPartner + ? _value.isPartner + : isPartner // ignore: cast_nullable_to_non_nullable + as bool, + isCustomer: null == isCustomer + ? _value.isCustomer + : isCustomer // ignore: cast_nullable_to_non_nullable + as bool, createdAt: freezed == createdAt ? _value.createdAt : createdAt // ignore: cast_nullable_to_non_nullable @@ -141,11 +165,14 @@ abstract class _$$CompanyListDtoImplCopyWith<$Res> $Res call( {int id, String name, - String address, + String? address, @JsonKey(name: 'contact_name') String? contactName, @JsonKey(name: 'contact_phone') String? contactPhone, @JsonKey(name: 'contact_email') String? contactEmail, + @JsonKey(name: 'company_types') List? companyTypes, @JsonKey(name: 'is_active') bool isActive, + @JsonKey(name: 'is_partner') bool isPartner, + @JsonKey(name: 'is_customer') bool isCustomer, @JsonKey(name: 'created_at') DateTime? createdAt, @JsonKey(name: 'branch_count') int branchCount}); } @@ -165,11 +192,14 @@ class __$$CompanyListDtoImplCopyWithImpl<$Res> $Res call({ Object? id = null, Object? name = null, - Object? address = null, + Object? address = freezed, Object? contactName = freezed, Object? contactPhone = freezed, Object? contactEmail = freezed, + Object? companyTypes = freezed, Object? isActive = null, + Object? isPartner = null, + Object? isCustomer = null, Object? createdAt = freezed, Object? branchCount = null, }) { @@ -182,10 +212,10 @@ class __$$CompanyListDtoImplCopyWithImpl<$Res> ? _value.name : name // ignore: cast_nullable_to_non_nullable as String, - address: null == address + address: freezed == address ? _value.address : address // ignore: cast_nullable_to_non_nullable - as String, + as String?, contactName: freezed == contactName ? _value.contactName : contactName // ignore: cast_nullable_to_non_nullable @@ -198,10 +228,22 @@ class __$$CompanyListDtoImplCopyWithImpl<$Res> ? _value.contactEmail : contactEmail // ignore: cast_nullable_to_non_nullable as String?, + companyTypes: freezed == companyTypes + ? _value._companyTypes + : companyTypes // ignore: cast_nullable_to_non_nullable + as List?, isActive: null == isActive ? _value.isActive : isActive // ignore: cast_nullable_to_non_nullable as bool, + isPartner: null == isPartner + ? _value.isPartner + : isPartner // ignore: cast_nullable_to_non_nullable + as bool, + isCustomer: null == isCustomer + ? _value.isCustomer + : isCustomer // ignore: cast_nullable_to_non_nullable + as bool, createdAt: freezed == createdAt ? _value.createdAt : createdAt // ignore: cast_nullable_to_non_nullable @@ -220,13 +262,17 @@ class _$CompanyListDtoImpl implements _CompanyListDto { const _$CompanyListDtoImpl( {required this.id, required this.name, - required this.address, + this.address, @JsonKey(name: 'contact_name') this.contactName, @JsonKey(name: 'contact_phone') this.contactPhone, @JsonKey(name: 'contact_email') this.contactEmail, + @JsonKey(name: 'company_types') final List? companyTypes, @JsonKey(name: 'is_active') required this.isActive, + @JsonKey(name: 'is_partner') this.isPartner = false, + @JsonKey(name: 'is_customer') this.isCustomer = false, @JsonKey(name: 'created_at') this.createdAt, - @JsonKey(name: 'branch_count') this.branchCount = 0}); + @JsonKey(name: 'branch_count') this.branchCount = 0}) + : _companyTypes = companyTypes; factory _$CompanyListDtoImpl.fromJson(Map json) => _$$CompanyListDtoImplFromJson(json); @@ -236,7 +282,7 @@ class _$CompanyListDtoImpl implements _CompanyListDto { @override final String name; @override - final String address; + final String? address; @override @JsonKey(name: 'contact_name') final String? contactName; @@ -246,10 +292,27 @@ class _$CompanyListDtoImpl implements _CompanyListDto { @override @JsonKey(name: 'contact_email') final String? contactEmail; + final List? _companyTypes; + @override + @JsonKey(name: 'company_types') + List? get companyTypes { + final value = _companyTypes; + if (value == null) return null; + if (_companyTypes is EqualUnmodifiableListView) return _companyTypes; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + @override @JsonKey(name: 'is_active') final bool isActive; @override + @JsonKey(name: 'is_partner') + final bool isPartner; + @override + @JsonKey(name: 'is_customer') + final bool isCustomer; + @override @JsonKey(name: 'created_at') final DateTime? createdAt; @override @@ -258,7 +321,7 @@ class _$CompanyListDtoImpl implements _CompanyListDto { @override String toString() { - return 'CompanyListDto(id: $id, name: $name, address: $address, contactName: $contactName, contactPhone: $contactPhone, contactEmail: $contactEmail, isActive: $isActive, createdAt: $createdAt, branchCount: $branchCount)'; + return 'CompanyListDto(id: $id, name: $name, address: $address, contactName: $contactName, contactPhone: $contactPhone, contactEmail: $contactEmail, companyTypes: $companyTypes, isActive: $isActive, isPartner: $isPartner, isCustomer: $isCustomer, createdAt: $createdAt, branchCount: $branchCount)'; } @override @@ -275,8 +338,14 @@ class _$CompanyListDtoImpl implements _CompanyListDto { other.contactPhone == contactPhone) && (identical(other.contactEmail, contactEmail) || other.contactEmail == contactEmail) && + const DeepCollectionEquality() + .equals(other._companyTypes, _companyTypes) && (identical(other.isActive, isActive) || other.isActive == isActive) && + (identical(other.isPartner, isPartner) || + other.isPartner == isPartner) && + (identical(other.isCustomer, isCustomer) || + other.isCustomer == isCustomer) && (identical(other.createdAt, createdAt) || other.createdAt == createdAt) && (identical(other.branchCount, branchCount) || @@ -285,8 +354,20 @@ class _$CompanyListDtoImpl implements _CompanyListDto { @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, id, name, address, contactName, - contactPhone, contactEmail, isActive, createdAt, branchCount); + int get hashCode => Object.hash( + runtimeType, + id, + name, + address, + contactName, + contactPhone, + contactEmail, + const DeepCollectionEquality().hash(_companyTypes), + isActive, + isPartner, + isCustomer, + createdAt, + branchCount); /// Create a copy of CompanyListDto /// with the given fields replaced by the non-null parameter values. @@ -309,11 +390,14 @@ abstract class _CompanyListDto implements CompanyListDto { const factory _CompanyListDto( {required final int id, required final String name, - required final String address, + final String? address, @JsonKey(name: 'contact_name') final String? contactName, @JsonKey(name: 'contact_phone') final String? contactPhone, @JsonKey(name: 'contact_email') final String? contactEmail, + @JsonKey(name: 'company_types') final List? companyTypes, @JsonKey(name: 'is_active') required final bool isActive, + @JsonKey(name: 'is_partner') final bool isPartner, + @JsonKey(name: 'is_customer') final bool isCustomer, @JsonKey(name: 'created_at') final DateTime? createdAt, @JsonKey(name: 'branch_count') final int branchCount}) = _$CompanyListDtoImpl; @@ -326,7 +410,7 @@ abstract class _CompanyListDto implements CompanyListDto { @override String get name; @override - String get address; + String? get address; @override @JsonKey(name: 'contact_name') String? get contactName; @@ -337,9 +421,18 @@ abstract class _CompanyListDto implements CompanyListDto { @JsonKey(name: 'contact_email') String? get contactEmail; @override + @JsonKey(name: 'company_types') + List? get companyTypes; + @override @JsonKey(name: 'is_active') bool get isActive; @override + @JsonKey(name: 'is_partner') + bool get isPartner; + @override + @JsonKey(name: 'is_customer') + bool get isCustomer; + @override @JsonKey(name: 'created_at') DateTime? get createdAt; @override diff --git a/lib/data/models/company/company_list_dto.g.dart b/lib/data/models/company/company_list_dto.g.dart index 07d91a8..a6a112b 100644 --- a/lib/data/models/company/company_list_dto.g.dart +++ b/lib/data/models/company/company_list_dto.g.dart @@ -10,11 +10,16 @@ _$CompanyListDtoImpl _$$CompanyListDtoImplFromJson(Map json) => _$CompanyListDtoImpl( id: (json['id'] as num).toInt(), name: json['name'] as String, - address: json['address'] as String, + address: json['address'] as String?, contactName: json['contact_name'] as String?, contactPhone: json['contact_phone'] as String?, contactEmail: json['contact_email'] as String?, + companyTypes: (json['company_types'] as List?) + ?.map((e) => e as String) + .toList(), isActive: json['is_active'] as bool, + isPartner: json['is_partner'] as bool? ?? false, + isCustomer: json['is_customer'] as bool? ?? false, createdAt: json['created_at'] == null ? null : DateTime.parse(json['created_at'] as String), @@ -30,7 +35,10 @@ Map _$$CompanyListDtoImplToJson( 'contact_name': instance.contactName, 'contact_phone': instance.contactPhone, 'contact_email': instance.contactEmail, + 'company_types': instance.companyTypes, 'is_active': instance.isActive, + 'is_partner': instance.isPartner, + 'is_customer': instance.isCustomer, 'created_at': instance.createdAt?.toIso8601String(), 'branch_count': instance.branchCount, }; diff --git a/lib/screens/company/company_list_redesign.dart b/lib/screens/company/company_list_redesign.dart index af839c9..f702f5a 100644 --- a/lib/screens/company/company_list_redesign.dart +++ b/lib/screens/company/company_list_redesign.dart @@ -253,6 +253,14 @@ class _CompanyListRedesignState extends State { final int startIndex = (_currentPage - 1) * _pageSize; final int endIndex = startIndex + _pageSize; + // 디버그 로그 추가 + print('🔍 [VIEW DEBUG] 화면 페이지네이션 상태'); + print(' • filteredCompanies 수: ${controller.filteredCompanies.length}개'); + print(' • displayCompanies 수: ${displayCompanies.length}개 (지점 포함)'); + print(' • 현재 페이지: $_currentPage'); + print(' • 페이지 크기: $_pageSize'); + print(' • startIndex: $startIndex, endIndex: $endIndex'); + // startIndex가 displayCompanies.length보다 크거나 같으면 첫 페이지로 리셋 if (startIndex >= displayCompanies.length && displayCompanies.isNotEmpty) { WidgetsBinding.instance.addPostFrameCallback((_) { @@ -265,9 +273,11 @@ class _CompanyListRedesignState extends State { final List> pagedCompanies = displayCompanies.isEmpty ? [] : displayCompanies.sublist( - startIndex.clamp(0, displayCompanies.length - 1), + startIndex.clamp(0, displayCompanies.length), endIndex.clamp(0, displayCompanies.length), ); + + print(' • 화면에 표시될 항목 수: ${pagedCompanies.length}개'); // 로딩 상태 if (controller.isLoading && controller.companies.isEmpty) { diff --git a/lib/screens/company/controllers/company_list_controller.dart b/lib/screens/company/controllers/company_list_controller.dart index cbeee14..4d421c5 100644 --- a/lib/screens/company/controllers/company_list_controller.dart +++ b/lib/screens/company/controllers/company_list_controller.dart @@ -38,17 +38,26 @@ class CompanyListController extends ChangeNotifier { // 초기 데이터 로드 Future initialize() async { + print('╔══════════════════════════════════════════════════════════'); + print('║ 🚀 회사 목록 초기화 시작'); + print('║ • 페이지 크기: $_perPage개'); + print('╚══════════════════════════════════════════════════════════'); await loadData(isRefresh: true); } // 페이지 크기를 지정하여 초기화 Future initializeWithPageSize(int pageSize) async { _perPage = pageSize; + print('╔══════════════════════════════════════════════════════════'); + print('║ 🚀 회사 목록 초기화 시작 (커스텀 페이지 크기)'); + print('║ • 페이지 크기: $_perPage개'); + print('╚══════════════════════════════════════════════════════════'); await loadData(isRefresh: true); } // 데이터 로드 및 필터 적용 Future loadData({bool isRefresh = false}) async { + print('🔍 [DEBUG] loadData 시작 - currentPage: $_currentPage, hasMore: $_hasMore, companies.length: ${companies.length}'); print('[CompanyListController] loadData called - isRefresh: $isRefresh'); if (isRefresh) { @@ -71,15 +80,34 @@ class CompanyListController extends ChangeNotifier { // 지점 정보를 포함한 전체 회사 목록 가져오기 final apiCompaniesWithBranches = await _companyService.getCompaniesWithBranchesFlat(); - print('[CompanyListController] API returned ${apiCompaniesWithBranches.length} companies with branches'); - // 지점 수 출력 + // 상세한 회사 정보 로그 출력 + print('╔══════════════════════════════════════════════════════════'); + print('║ 📊 회사 목록 로드 완료'); + print('║ ▶ 총 회사 수: ${apiCompaniesWithBranches.length}개'); + print('╟──────────────────────────────────────────────────────────'); + + // 지점이 있는 회사와 없는 회사 구분 + int companiesWithBranches = 0; + int totalBranches = 0; + for (final company in apiCompaniesWithBranches) { if (company.branches?.isNotEmpty ?? false) { - print('[CompanyListController] ${company.name} has ${company.branches?.length ?? 0} branches'); + companiesWithBranches++; + totalBranches += company.branches!.length; + print('║ • ${company.name}: ${company.branches!.length}개 지점'); } } + final companiesWithoutBranches = apiCompaniesWithBranches.length - companiesWithBranches; + + print('╟──────────────────────────────────────────────────────────'); + print('║ 📈 통계'); + print('║ • 지점이 있는 회사: ${companiesWithBranches}개'); + print('║ • 지점이 없는 회사: ${companiesWithoutBranches}개'); + print('║ • 총 지점 수: ${totalBranches}개'); + print('╚══════════════════════════════════════════════════════════'); + // 검색어 필터 적용 (서버에서 필터링이 안 되므로 클라이언트에서 처리) List filteredApiCompanies = apiCompaniesWithBranches; if (searchKeyword.isNotEmpty) { @@ -89,6 +117,13 @@ class CompanyListController extends ChangeNotifier { (company.contactName?.toLowerCase().contains(keyword) ?? false) || (company.contactPhone?.toLowerCase().contains(keyword) ?? false); }).toList(); + + print('╔══════════════════════════════════════════════════════════'); + print('║ 🔍 검색 필터 적용'); + print('║ • 검색어: "$searchKeyword"'); + print('║ • 필터 전: ${apiCompaniesWithBranches.length}개'); + print('║ • 필터 후: ${filteredApiCompanies.length}개'); + print('╚══════════════════════════════════════════════════════════'); } // 활성 상태 필터 적용 (현재 API에서 지원하지 않으므로 주석 처리) @@ -96,30 +131,36 @@ class CompanyListController extends ChangeNotifier { // filteredApiCompanies = filteredApiCompanies.where((c) => c.isActive == _isActiveFilter).toList(); // } - // 페이지네이션 처리 (클라이언트 사이드) - final startIndex = (_currentPage - 1) * _perPage; - final endIndex = startIndex + _perPage; - final paginatedCompanies = filteredApiCompanies.skip(startIndex).take(_perPage).toList(); + // 전체 데이터를 한 번에 로드 (View에서 페이지네이션 처리) + companies = filteredApiCompanies; + _hasMore = false; // 전체 데이터를 로드했으므로 더 이상 로드할 필요 없음 - if (isRefresh) { - companies = paginatedCompanies; - } else { - companies.addAll(paginatedCompanies); - } - - _hasMore = endIndex < filteredApiCompanies.length; - if (_hasMore) _currentPage++; + print('╔══════════════════════════════════════════════════════════'); + print('║ 📑 전체 데이터 로드 완료'); + print('║ • 로드된 회사 수: ${companies.length}개'); + print('║ • 필터링된 회사 수: ${filteredApiCompanies.length}개'); + print('║ • View에서 페이지네이션 처리 예정'); + print('╚══════════════════════════════════════════════════════════'); } else { // Mock 데이터 사용 - print('[CompanyListController] Using Mock data'); companies = dataService.getAllCompanies(); - print('[CompanyListController] Mock returned ${companies.length} companies'); + + print('╔══════════════════════════════════════════════════════════'); + print('║ 🔧 Mock 데이터 로드 완료'); + print('║ ▶ 총 회사 수: ${companies.length}개'); + print('╚══════════════════════════════════════════════════════════'); + _hasMore = false; } // 필터 적용 applyFilters(); - print('[CompanyListController] After filtering: ${filteredCompanies.length} companies shown'); + + print('╔══════════════════════════════════════════════════════════'); + print('║ ✅ 최종 화면 표시'); + print('║ • 화면에 표시될 회사 수: ${filteredCompanies.length}개'); + print('╚══════════════════════════════════════════════════════════'); + selectedCompanyIds.clear(); } on Failure catch (e) { print('[CompanyListController] Failure loading companies: ${e.message}'); @@ -165,6 +206,17 @@ class CompanyListController extends ChangeNotifier { // 검색어 변경 Future updateSearchKeyword(String keyword) async { searchKeyword = keyword; + + if (keyword.isNotEmpty) { + print('╔══════════════════════════════════════════════════════════'); + print('║ 🔍 검색어 변경: "$keyword"'); + print('╚══════════════════════════════════════════════════════════'); + } else { + print('╔══════════════════════════════════════════════════════════'); + print('║ ❌ 검색어 초기화'); + print('╚══════════════════════════════════════════════════════════'); + } + if (_useApi) { // API 사용 시 새로 조회 await loadData(isRefresh: true); @@ -275,7 +327,12 @@ class CompanyListController extends ChangeNotifier { // 더 많은 데이터 로드 Future loadMore() async { - if (!_hasMore || _isLoading || !_useApi) return; + print('🔍 [DEBUG] loadMore 호출됨 - hasMore: $_hasMore, isLoading: $_isLoading, useApi: $_useApi'); + if (!_hasMore || _isLoading || !_useApi) { + print('🔍 [DEBUG] loadMore 조건 미충족으로 종료 (hasMore: $_hasMore, isLoading: $_isLoading, useApi: $_useApi)'); + return; + } + print('🔍 [DEBUG] loadMore 실행 - 추가 데이터 로드 시작'); await loadData(); } @@ -293,6 +350,9 @@ class CompanyListController extends ChangeNotifier { // 리프레시 Future refresh() async { + print('╔══════════════════════════════════════════════════════════'); + print('║ 🔄 회사 목록 새로고침 시작'); + print('╚══════════════════════════════════════════════════════════'); await loadData(isRefresh: true); } diff --git a/lib/screens/equipment/controllers/equipment_list_controller.dart b/lib/screens/equipment/controllers/equipment_list_controller.dart index 1f17783..912964e 100644 --- a/lib/screens/equipment/controllers/equipment_list_controller.dart +++ b/lib/screens/equipment/controllers/equipment_list_controller.dart @@ -44,13 +44,7 @@ class EquipmentListController extends ChangeNotifier { // 데이터 로드 및 상태 필터 적용 Future loadData({bool isRefresh = false, String? search}) async { - if (isRefresh) { - _currentPage = 1; - _hasMore = true; - equipments.clear(); - } - - if (_isLoading || (!_hasMore && !isRefresh)) return; + if (_isLoading) return; _isLoading = true; _error = null; @@ -58,31 +52,42 @@ class EquipmentListController extends ChangeNotifier { try { if (_useApi) { - // API 호출 - DebugLogger.log('장비 목록 API 호출 시작', tag: 'EQUIPMENT', data: { - 'page': _currentPage, - 'perPage': _perPage, - 'statusFilter': selectedStatusFilter, - }); + // API 호출 - 전체 데이터 로드 + print('╔══════════════════════════════════════════════════════════'); + print('║ 📦 장비 목록 API 호출 시작'); + print('║ • 상태 필터: ${selectedStatusFilter ?? "전체"}'); + print('║ • 검색어: ${search ?? searchKeyword}'); + print('╚══════════════════════════════════════════════════════════'); - // DTO 형태로 가져와서 status 정보 유지 + // 전체 데이터를 가져오기 위해 큰 perPage 값 사용 final apiEquipmentDtos = await _equipmentService.getEquipmentsWithStatus( - page: _currentPage, - perPage: _perPage, + page: 1, + perPage: 1000, // 충분히 큰 값으로 전체 데이터 로드 status: selectedStatusFilter != null ? EquipmentStatusConverter.clientToServer(selectedStatusFilter) : null, search: search ?? searchKeyword, ); - DebugLogger.log('장비 목록 API 응답', tag: 'EQUIPMENT', data: { - 'count': apiEquipmentDtos.length, - 'firstItem': apiEquipmentDtos.isNotEmpty ? { - 'id': apiEquipmentDtos.first.id, - 'equipmentNumber': apiEquipmentDtos.first.equipmentNumber, - 'manufacturer': apiEquipmentDtos.first.manufacturer, - 'status': apiEquipmentDtos.first.status, - } : null, + print('╔══════════════════════════════════════════════════════════'); + print('║ 📊 장비 목록 로드 완료'); + print('║ ▶ 총 장비 수: ${apiEquipmentDtos.length}개'); + print('╟──────────────────────────────────────────────────────────'); + + // 상태별 통계 + Map statusCount = {}; + for (final dto in apiEquipmentDtos) { + final clientStatus = EquipmentStatusConverter.serverToClient(dto.status); + statusCount[clientStatus] = (statusCount[clientStatus] ?? 0) + 1; + } + + statusCount.forEach((status, count) { + print('║ • $status: $count개'); }); + print('╟──────────────────────────────────────────────────────────'); + print('║ 📑 전체 데이터 로드 완료'); + print('║ • View에서 페이지네이션 처리 예정'); + print('╚══════════════════════════════════════════════════════════'); + // DTO를 UnifiedEquipment로 변환 (status 정보 포함) final List unifiedEquipments = apiEquipmentDtos.map((dto) { final equipment = Equipment( @@ -105,14 +110,8 @@ class EquipmentListController extends ChangeNotifier { ); }).toList(); - if (isRefresh) { - equipments = unifiedEquipments; - } else { - equipments.addAll(unifiedEquipments); - } - - _hasMore = unifiedEquipments.length == _perPage; - if (_hasMore) _currentPage++; + equipments = unifiedEquipments; + _hasMore = false; // 전체 데이터를 로드했으므로 더 이상 로드할 필요 없음 } else { // Mock 데이터 사용 equipments = dataService.getAllEquipments(); diff --git a/lib/screens/license/controllers/license_list_controller.dart b/lib/screens/license/controllers/license_list_controller.dart index aa68055..75c27b3 100644 --- a/lib/screens/license/controllers/license_list_controller.dart +++ b/lib/screens/license/controllers/license_list_controller.dart @@ -90,48 +90,65 @@ class LicenseListController extends ChangeNotifier { _isLoading = true; _error = null; - - if (isInitialLoad) { - _currentPage = 1; - _licenses.clear(); - _hasMore = true; - } - notifyListeners(); try { if (useApi && GetIt.instance.isRegistered()) { - debugPrint('📑 API 모드로 라이센스 로드 시작...'); + // API 사용 - 전체 데이터 로드 + print('╔══════════════════════════════════════════════════════════'); + print('║ 🔧 유지보수 목록 API 호출 시작'); + print('║ • 회사 필터: ${_selectedCompanyId ?? "전체"}'); + print('║ • 활성 필터: ${_isActive != null ? (_isActive! ? "활성" : "비활성") : "전체"}'); + print('║ • 라이센스 타입: ${_licenseType ?? "전체"}'); + print('╚══════════════════════════════════════════════════════════'); - // API 사용 + // 전체 데이터를 가져오기 위해 큰 perPage 값 사용 final fetchedLicenses = await _licenseService.getLicenses( - page: _currentPage, - perPage: _pageSize, + page: 1, + perPage: 1000, // 충분히 큰 값으로 전체 데이터 로드 isActive: _isActive, companyId: _selectedCompanyId, licenseType: _licenseType, ); - debugPrint('📑 API에서 ${fetchedLicenses.length}개 라이센스 받음'); - - if (isInitialLoad) { - _licenses = fetchedLicenses; - debugPrint('📑 초기 로드: _licenses에 ${_licenses.length}개 저장'); - } else { - _licenses.addAll(fetchedLicenses); - debugPrint('📑 추가 로드: _licenses에 총 ${_licenses.length}개'); + print('╔══════════════════════════════════════════════════════════'); + print('║ 📊 유지보수 목록 로드 완료'); + print('║ ▶ 총 라이센스 수: ${fetchedLicenses.length}개'); + print('╟──────────────────────────────────────────────────────────'); + + // 상태별 통계 + int activeCount = 0; + int expiringSoonCount = 0; + int expiredCount = 0; + final now = DateTime.now(); + + for (final license in fetchedLicenses) { + if (license.expiryDate != null) { + final daysUntil = license.expiryDate!.difference(now).inDays; + if (daysUntil < 0) { + expiredCount++; + } else if (daysUntil <= 30) { + expiringSoonCount++; + } else { + activeCount++; + } + } else { + activeCount++; + } } - - _hasMore = fetchedLicenses.length >= _pageSize; - // 전체 개수 조회 - debugPrint('📑 전체 개수 조회 시작...'); - _total = await _licenseService.getTotalLicenses( - isActive: _isActive, - companyId: _selectedCompanyId, - licenseType: _licenseType, - ); - debugPrint('📑 전체 개수: $_total'); + print('║ • 활성: $activeCount개'); + print('║ • 만료 임박 (30일 이내): $expiringSoonCount개'); + print('║ • 만료됨: $expiredCount개'); + + print('╟──────────────────────────────────────────────────────────'); + print('║ 📑 전체 데이터 로드 완료'); + print('║ • View에서 페이지네이션 처리 예정'); + print('╚══════════════════════════════════════════════════════════'); + + _licenses = fetchedLicenses; + _hasMore = false; // 전체 데이터를 로드했으므로 더 이상 로드할 필요 없음 + _total = fetchedLicenses.length; } else { // Mock 데이터 사용 final allLicenses = mockDataService?.getAllLicenses() ?? []; diff --git a/lib/screens/warehouse_location/controllers/warehouse_location_list_controller.dart b/lib/screens/warehouse_location/controllers/warehouse_location_list_controller.dart index 9d389b0..493d048 100644 --- a/lib/screens/warehouse_location/controllers/warehouse_location_list_controller.dart +++ b/lib/screens/warehouse_location/controllers/warehouse_location_list_controller.dart @@ -46,47 +46,51 @@ class WarehouseLocationListController extends ChangeNotifier { Future loadWarehouseLocations({bool isInitialLoad = true}) async { if (_isLoading) return; - print('[WarehouseLocationListController] loadWarehouseLocations started - isInitialLoad: $isInitialLoad'); - _isLoading = true; _error = null; - - if (isInitialLoad) { - _currentPage = 1; - _warehouseLocations.clear(); - _hasMore = true; - } else { - // 다음 페이지를 로드할 때는 페이지 번호를 먼저 증가 - _currentPage++; - } - notifyListeners(); try { if (useApi && _warehouseService != null) { - // API 사용 - print('[WarehouseLocationListController] Using API to fetch warehouse locations'); - final fetchedLocations = await _warehouseService!.getWarehouseLocations( - page: _currentPage, - perPage: _pageSize, - isActive: _isActive, - ); - - print('[WarehouseLocationListController] API returned ${fetchedLocations.length} locations'); - - if (isInitialLoad) { - _warehouseLocations = fetchedLocations; - } else { - _warehouseLocations.addAll(fetchedLocations); - } - - _hasMore = fetchedLocations.length >= _pageSize; + // API 사용 - 전체 데이터 로드 + print('╔══════════════════════════════════════════════════════════'); + print('║ 🏭 입고지 목록 API 호출 시작'); + print('║ • 활성 필터: ${_isActive != null ? (_isActive! ? "활성" : "비활성") : "전체"}'); + print('╚══════════════════════════════════════════════════════════'); - // 전체 개수 조회 - _total = await _warehouseService!.getTotalWarehouseLocations( + // 전체 데이터를 가져오기 위해 큰 perPage 값 사용 + final fetchedLocations = await _warehouseService!.getWarehouseLocations( + page: 1, + perPage: 1000, // 충분히 큰 값으로 전체 데이터 로드 isActive: _isActive, ); - print('[WarehouseLocationListController] Total warehouse locations: $_total'); + + print('╔══════════════════════════════════════════════════════════'); + print('║ 📊 입고지 목록 로드 완료'); + print('║ ▶ 총 입고지 수: ${fetchedLocations.length}개'); + print('╟──────────────────────────────────────────────────────────'); + + // 상태별 통계 (입고지에 상태가 있다면) + int activeCount = 0; + int inactiveCount = 0; + for (final location in fetchedLocations) { + // isActive 필드가 있다면 활용 + activeCount++; // 현재는 모두 활성으로 가정 + } + + print('║ • 활성 입고지: $activeCount개'); + if (inactiveCount > 0) { + print('║ • 비활성 입고지: $inactiveCount개'); + } + + print('╟──────────────────────────────────────────────────────────'); + print('║ 📑 전체 데이터 로드 완료'); + print('║ • View에서 페이지네이션 처리 예정'); + print('╚══════════════════════════════════════════════════════════'); + + _warehouseLocations = fetchedLocations; + _hasMore = false; // 전체 데이터를 로드했으므로 더 이상 로드할 필요 없음 + _total = fetchedLocations.length; } else { // Mock 데이터 사용 print('[WarehouseLocationListController] Using Mock data'); diff --git a/lib/services/company_service.dart b/lib/services/company_service.dart index 97a2ca7..e5f5d97 100644 --- a/lib/services/company_service.dart +++ b/lib/services/company_service.dart @@ -271,10 +271,35 @@ class CompanyService { // 회사별로 데이터 그룹화 final Map> companyBranchesMap = {}; final Map companyNamesMap = {}; + final Map> companyTypesMap = {}; + final Map companyIsPartnerMap = {}; + final Map companyIsCustomerMap = {}; for (final item in flatData) { companyNamesMap[item.companyId] = item.companyName; + // 첫 번째 아이템에서만 회사 타입 정보 저장 + if (!companyTypesMap.containsKey(item.companyId)) { + List types = []; + + // 1. company_types 필드가 있으면 우선 사용 (하위 호환성) + if (item.companyTypes != null && item.companyTypes!.isNotEmpty) { + types = item.companyTypes!.map((typeStr) { + if (typeStr.toLowerCase().contains('partner')) return CompanyType.partner; + return CompanyType.customer; + }).toSet().toList(); // 중복 제거 + } + // 2. company_types가 없으면 is_partner, is_customer 사용 + else { + if (item.isCustomer) types.add(CompanyType.customer); + if (item.isPartner) types.add(CompanyType.partner); + } + + companyTypesMap[item.companyId] = types; + companyIsPartnerMap[item.companyId] = item.isPartner; + companyIsCustomerMap[item.companyId] = item.isCustomer; + } + if (item.branchId != null && item.branchName != null) { if (!companyBranchesMap.containsKey(item.companyId)) { companyBranchesMap[item.companyId] = []; @@ -298,7 +323,7 @@ class CompanyService { id: entry.key, name: entry.value, address: Address.fromFullAddress(''), // 주소 정보가 없으므로 빈 값 - companyTypes: [CompanyType.customer], // 기본값 + companyTypes: companyTypesMap[entry.key] ?? [], // 빈 리스트 가능 branches: companyBranchesMap[entry.key], // null 허용 ), ); @@ -317,22 +342,51 @@ class CompanyService { // 변환 헬퍼 메서드들 Company _convertListDtoToCompany(CompanyListDto dto) { + List companyTypes = []; + + // 1. company_types 필드가 있으면 우선 사용 (하위 호환성) + if (dto.companyTypes != null && dto.companyTypes!.isNotEmpty) { + companyTypes = dto.companyTypes!.map((typeStr) { + if (typeStr.toLowerCase().contains('partner')) return CompanyType.partner; + return CompanyType.customer; + }).toSet().toList(); // 중복 제거 + } + // 2. company_types가 없으면 is_partner, is_customer 사용 + else { + if (dto.isCustomer) companyTypes.add(CompanyType.customer); + if (dto.isPartner) companyTypes.add(CompanyType.partner); + } + + // 3. 둘 다 없으면 빈 리스트 유지 (기본값 제거) + return Company( id: dto.id, name: dto.name, - address: Address.fromFullAddress(dto.address), + address: Address.fromFullAddress(dto.address ?? ''), contactName: dto.contactName, contactPhone: dto.contactPhone, - companyTypes: [CompanyType.customer], // 기본값, 실제로는 API에서 받아와야 함 + companyTypes: companyTypes, branches: [], // branches는 빈 배열로 초기화 ); } Company _convertResponseToCompany(CompanyResponse dto) { - final companyTypes = dto.companyTypes.map((typeStr) { - if (typeStr.contains('partner')) return CompanyType.partner; - return CompanyType.customer; - }).toList(); + List companyTypes = []; + + // 1. company_types 필드가 있으면 우선 사용 (하위 호환성) + if (dto.companyTypes.isNotEmpty) { + companyTypes = dto.companyTypes.map((typeStr) { + if (typeStr.toLowerCase().contains('partner')) return CompanyType.partner; + return CompanyType.customer; + }).toSet().toList(); // 중복 제거 + } + // 2. company_types가 없으면 is_partner, is_customer 사용 + else { + if (dto.isCustomer) companyTypes.add(CompanyType.customer); + if (dto.isPartner) companyTypes.add(CompanyType.partner); + } + + // 3. 둘 다 없으면 빈 리스트 유지 return Company( id: dto.id, @@ -342,7 +396,7 @@ class CompanyService { contactPosition: dto.contactPosition, contactPhone: dto.contactPhone, contactEmail: dto.contactEmail, - companyTypes: companyTypes.isEmpty ? [CompanyType.customer] : companyTypes, + companyTypes: companyTypes, remark: dto.remark, branches: [], // branches는 빈 배열로 초기화 );