feat: 결재·마스터 실연동 업데이트
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_client.dart';
|
||||
import 'package:superport_v2/core/network/api_routes.dart';
|
||||
|
||||
import '../../domain/entities/customer.dart';
|
||||
import '../../domain/repositories/customer_repository.dart';
|
||||
@@ -12,7 +13,7 @@ class CustomerRepositoryRemote implements CustomerRepository {
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
static const _basePath = '/customers';
|
||||
static const _basePath = '${ApiRoutes.apiV1}/customers';
|
||||
|
||||
/// 고객 목록을 조회한다.
|
||||
@override
|
||||
@@ -39,6 +40,17 @@ class CustomerRepositoryRemote implements CustomerRepository {
|
||||
return CustomerDto.parsePaginated(response.data ?? const {});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Customer> fetchDetail(int id, {bool includeZipcode = true}) async {
|
||||
final response = await _api.get<Map<String, dynamic>>(
|
||||
'$_basePath/$id',
|
||||
query: {if (includeZipcode) 'include': 'zipcode'},
|
||||
options: Options(responseType: ResponseType.json),
|
||||
);
|
||||
final data = (response.data?['data'] as Map<String, dynamic>?) ?? {};
|
||||
return CustomerDto.fromJson(data).toEntity();
|
||||
}
|
||||
|
||||
/// 고객을 생성한다.
|
||||
@override
|
||||
Future<Customer> create(CustomerInput input) async {
|
||||
|
||||
@@ -14,6 +14,9 @@ abstract class CustomerRepository {
|
||||
bool? isActive,
|
||||
});
|
||||
|
||||
/// 고객 단건 상세를 조회한다.
|
||||
Future<Customer> fetchDetail(int id, {bool includeZipcode = true});
|
||||
|
||||
/// 고객을 생성한다.
|
||||
Future<Customer> create(CustomerInput input);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/failure.dart';
|
||||
|
||||
import '../../domain/entities/customer.dart';
|
||||
import '../../domain/repositories/customer_repository.dart';
|
||||
@@ -78,8 +79,9 @@ class CustomerController extends ChangeNotifier {
|
||||
if (response.pageSize > 0 && response.pageSize != _pageSize) {
|
||||
_pageSize = response.pageSize;
|
||||
}
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
@@ -129,8 +131,9 @@ class CustomerController extends ChangeNotifier {
|
||||
final created = await _repository.create(input);
|
||||
await fetch(page: 1);
|
||||
return created;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -145,8 +148,9 @@ class CustomerController extends ChangeNotifier {
|
||||
final updated = await _repository.update(id, input);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return updated;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -161,8 +165,9 @@ class CustomerController extends ChangeNotifier {
|
||||
await _repository.delete(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return true;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return false;
|
||||
} finally {
|
||||
@@ -177,8 +182,9 @@ class CustomerController extends ChangeNotifier {
|
||||
final restored = await _repository.restore(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return restored;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
|
||||
@@ -32,7 +32,9 @@ class GroupDto {
|
||||
return GroupDto(
|
||||
id: json['id'] as int?,
|
||||
groupName: json['group_name'] as String,
|
||||
description: json['description'] as String?,
|
||||
description:
|
||||
json['description'] as String? ??
|
||||
json['group_description'] as String?,
|
||||
isDefault: (json['is_default'] as bool?) ?? false,
|
||||
isActive: (json['is_active'] as bool?) ?? true,
|
||||
isDeleted: (json['is_deleted'] as bool?) ?? false,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_client.dart';
|
||||
import 'package:superport_v2/core/network/api_routes.dart';
|
||||
|
||||
import '../../domain/entities/group.dart';
|
||||
import '../../domain/repositories/group_repository.dart';
|
||||
@@ -12,7 +13,7 @@ class GroupRepositoryRemote implements GroupRepository {
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
static const _basePath = '/groups';
|
||||
static const _basePath = '${ApiRoutes.apiV1}/groups';
|
||||
|
||||
/// 그룹 목록을 조회한다.
|
||||
@override
|
||||
@@ -22,7 +23,16 @@ class GroupRepositoryRemote implements GroupRepository {
|
||||
String? query,
|
||||
bool? isDefault,
|
||||
bool? isActive,
|
||||
bool includePermissions = false,
|
||||
bool includeEmployees = false,
|
||||
}) async {
|
||||
final includeParts = <String>[];
|
||||
if (includePermissions) {
|
||||
includeParts.add('permissions');
|
||||
}
|
||||
if (includeEmployees) {
|
||||
includeParts.add('employees');
|
||||
}
|
||||
final response = await _api.get<Map<String, dynamic>>(
|
||||
_basePath,
|
||||
query: {
|
||||
@@ -31,6 +41,7 @@ class GroupRepositoryRemote implements GroupRepository {
|
||||
if (query != null && query.isNotEmpty) 'q': query,
|
||||
if (isDefault != null) 'is_default': isDefault,
|
||||
if (isActive != null) 'is_active': isActive,
|
||||
if (includeParts.isNotEmpty) 'include': includeParts.join(','),
|
||||
},
|
||||
options: Options(responseType: ResponseType.json),
|
||||
);
|
||||
|
||||
@@ -10,6 +10,8 @@ abstract class GroupRepository {
|
||||
String? query,
|
||||
bool? isDefault,
|
||||
bool? isActive,
|
||||
bool includePermissions = false,
|
||||
bool includeEmployees = false,
|
||||
});
|
||||
|
||||
/// 그룹 신규 등록
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/failure.dart';
|
||||
|
||||
import 'package:superport_v2/core/permissions/permission_manager.dart';
|
||||
|
||||
import '../../domain/entities/group.dart';
|
||||
import '../../domain/repositories/group_repository.dart';
|
||||
import '../../../group_permission/application/permission_synchronizer.dart';
|
||||
import '../../../group_permission/domain/repositories/group_permission_repository.dart';
|
||||
|
||||
/// 기본 그룹 여부 필터.
|
||||
enum GroupDefaultFilter { all, defaultOnly, nonDefault }
|
||||
@@ -15,10 +20,17 @@ enum GroupStatusFilter { all, activeOnly, inactiveOnly }
|
||||
/// - 목록 조회 및 필터, 페이징 상태를 담당한다.
|
||||
/// - 생성/수정/삭제/복구 요청을 래핑하여 UI와 통신한다.
|
||||
class GroupController extends ChangeNotifier {
|
||||
GroupController({required GroupRepository repository})
|
||||
: _repository = repository;
|
||||
GroupController({
|
||||
required GroupRepository repository,
|
||||
GroupPermissionRepository? permissionRepository,
|
||||
PermissionManager? permissionManager,
|
||||
}) : _repository = repository,
|
||||
_permissionRepository = permissionRepository,
|
||||
_permissionManager = permissionManager;
|
||||
|
||||
final GroupRepository _repository;
|
||||
final GroupPermissionRepository? _permissionRepository;
|
||||
final PermissionManager? _permissionManager;
|
||||
|
||||
PaginatedResult<Group>? _result;
|
||||
bool _isLoading = false;
|
||||
@@ -60,8 +72,9 @@ class GroupController extends ChangeNotifier {
|
||||
isActive: isActive,
|
||||
);
|
||||
_result = response;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
@@ -92,9 +105,11 @@ class GroupController extends ChangeNotifier {
|
||||
try {
|
||||
final created = await _repository.create(input);
|
||||
await fetch(page: 1);
|
||||
await _maybeSync(created.id);
|
||||
return created;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -108,9 +123,11 @@ class GroupController extends ChangeNotifier {
|
||||
try {
|
||||
final updated = await _repository.update(id, input);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
await _maybeSync(updated.id);
|
||||
return updated;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -124,9 +141,11 @@ class GroupController extends ChangeNotifier {
|
||||
try {
|
||||
await _repository.delete(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
await _maybeSync(id);
|
||||
return true;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return false;
|
||||
} finally {
|
||||
@@ -140,9 +159,11 @@ class GroupController extends ChangeNotifier {
|
||||
try {
|
||||
final restored = await _repository.restore(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
await _maybeSync(restored.id);
|
||||
return restored;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -161,4 +182,28 @@ class GroupController extends ChangeNotifier {
|
||||
_isSubmitting = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _maybeSync(int? groupId) async {
|
||||
if (groupId == null) {
|
||||
return;
|
||||
}
|
||||
await _syncPermissionsForGroup(groupId);
|
||||
}
|
||||
|
||||
Future<void> _syncPermissionsForGroup(int groupId) async {
|
||||
final repository = _permissionRepository;
|
||||
final manager = _permissionManager;
|
||||
if (repository == null || manager == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final synchronizer = PermissionSynchronizer(
|
||||
repository: repository,
|
||||
manager: manager,
|
||||
);
|
||||
await synchronizer.syncForGroup(groupId);
|
||||
} catch (_) {
|
||||
// 권한 동기화 실패는 UI 동작에 영향을 주지 않도록 무시한다.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:superport_v2/core/permissions/permission_manager.dart';
|
||||
|
||||
import '../domain/entities/group_permission.dart';
|
||||
import '../domain/mappers/group_permission_mapper.dart';
|
||||
import '../domain/repositories/group_permission_repository.dart';
|
||||
|
||||
/// 서버에서 그룹 메뉴 권한을 조회해 [PermissionManager]에 반영하는 동기화기.
|
||||
class PermissionSynchronizer {
|
||||
PermissionSynchronizer({
|
||||
required GroupPermissionRepository repository,
|
||||
required PermissionManager manager,
|
||||
this.pageSize = 200,
|
||||
}) : _repository = repository,
|
||||
_manager = manager;
|
||||
|
||||
final GroupPermissionRepository _repository;
|
||||
final PermissionManager _manager;
|
||||
final int pageSize;
|
||||
|
||||
/// 지정한 [groupId]의 메뉴 권한을 조회해 [PermissionManager]에 적용한다.
|
||||
Future<void> syncForGroup(int groupId) async {
|
||||
final collected = <GroupPermission>[];
|
||||
var page = 1;
|
||||
|
||||
while (true) {
|
||||
final response = await _repository.list(
|
||||
page: page,
|
||||
pageSize: pageSize,
|
||||
groupId: groupId,
|
||||
includeDeleted: false,
|
||||
isActive: true,
|
||||
);
|
||||
collected.addAll(response.items);
|
||||
|
||||
final currentPageSize = response.pageSize == 0
|
||||
? response.items.length
|
||||
: response.pageSize;
|
||||
if (currentPageSize == 0) {
|
||||
break;
|
||||
}
|
||||
final fetched = page * currentPageSize;
|
||||
if (fetched >= response.total) {
|
||||
break;
|
||||
}
|
||||
page += 1;
|
||||
}
|
||||
|
||||
final permissionMap = buildPermissionMap(collected);
|
||||
_manager.applyServerPermissions(permissionMap);
|
||||
}
|
||||
}
|
||||
@@ -111,22 +111,39 @@ class GroupPermissionGroupDto {
|
||||
|
||||
/// 권한 대상 메뉴 정보를 담는 DTO.
|
||||
class GroupPermissionMenuDto {
|
||||
GroupPermissionMenuDto({required this.id, required this.menuName});
|
||||
GroupPermissionMenuDto({
|
||||
required this.id,
|
||||
required this.menuCode,
|
||||
required this.menuName,
|
||||
this.path,
|
||||
});
|
||||
|
||||
final int id;
|
||||
final String menuCode;
|
||||
final String menuName;
|
||||
final String? path;
|
||||
|
||||
/// JSON에서 메뉴 정보를 파싱한다.
|
||||
factory GroupPermissionMenuDto.fromJson(Map<String, dynamic> json) {
|
||||
final fallbackName =
|
||||
json['menu_name'] as String? ?? json['name'] as String? ?? '-';
|
||||
final code =
|
||||
json['menu_code'] as String? ?? json['code'] as String? ?? fallbackName;
|
||||
return GroupPermissionMenuDto(
|
||||
id: json['id'] as int? ?? json['menu_id'] as int,
|
||||
menuName: json['menu_name'] as String? ?? json['name'] as String? ?? '-',
|
||||
menuCode: code,
|
||||
menuName: fallbackName,
|
||||
path: json['path'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
/// DTO를 [GroupPermissionMenu] 엔티티로 변환한다.
|
||||
GroupPermissionMenu toEntity() =>
|
||||
GroupPermissionMenu(id: id, menuName: menuName);
|
||||
GroupPermissionMenu toEntity() => GroupPermissionMenu(
|
||||
id: id,
|
||||
menuCode: menuCode,
|
||||
menuName: menuName,
|
||||
path: path,
|
||||
);
|
||||
}
|
||||
|
||||
/// 문자열/DateTime 값을 파싱해 [DateTime]으로 변환한다.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_client.dart';
|
||||
import 'package:superport_v2/core/network/api_routes.dart';
|
||||
|
||||
import '../../domain/entities/group_permission.dart';
|
||||
import '../../domain/repositories/group_permission_repository.dart';
|
||||
@@ -13,7 +14,7 @@ class GroupPermissionRepositoryRemote implements GroupPermissionRepository {
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
static const _basePath = '/group-menu-permissions';
|
||||
static const _basePath = '${ApiRoutes.apiV1}/group-menu-permissions';
|
||||
|
||||
/// 그룹 권한 목록을 조회한다.
|
||||
@override
|
||||
|
||||
@@ -70,10 +70,17 @@ class GroupPermissionGroup {
|
||||
}
|
||||
|
||||
class GroupPermissionMenu {
|
||||
GroupPermissionMenu({required this.id, required this.menuName});
|
||||
GroupPermissionMenu({
|
||||
required this.id,
|
||||
required this.menuCode,
|
||||
required this.menuName,
|
||||
this.path,
|
||||
});
|
||||
|
||||
final int id;
|
||||
final String menuCode;
|
||||
final String menuName;
|
||||
final String? path;
|
||||
}
|
||||
|
||||
/// 그룹 권한 생성/수정 입력 모델
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import 'package:superport_v2/core/permissions/permission_manager.dart';
|
||||
import 'package:superport_v2/core/permissions/permission_resources.dart';
|
||||
|
||||
import '../entities/group_permission.dart';
|
||||
|
||||
/// 그룹-메뉴 권한 목록을 [PermissionManager]에 적용할 수 있는 맵으로 변환한다.
|
||||
///
|
||||
/// - 메뉴 경로([GroupPermissionMenu.path])가 비어 있으면 해당 항목은 건너뛴다.
|
||||
/// - 읽기 권한은 [PermissionAction.view]로 매핑하고, CRUD 권한은 각각 대응한다.
|
||||
Map<String, Set<PermissionAction>> buildPermissionMap(
|
||||
Iterable<GroupPermission> permissions,
|
||||
) {
|
||||
final result = <String, Set<PermissionAction>>{};
|
||||
for (final permission in permissions) {
|
||||
final path = PermissionResources.normalize(permission.menu.path ?? '');
|
||||
if (path.isEmpty) {
|
||||
continue;
|
||||
}
|
||||
final actions = result.putIfAbsent(path, () => <PermissionAction>{});
|
||||
if (permission.canRead) {
|
||||
actions.add(PermissionAction.view);
|
||||
}
|
||||
if (permission.canCreate) {
|
||||
actions.add(PermissionAction.create);
|
||||
}
|
||||
if (permission.canUpdate) {
|
||||
actions.add(PermissionAction.edit);
|
||||
}
|
||||
if (permission.canDelete) {
|
||||
actions.add(PermissionAction.delete);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/failure.dart';
|
||||
|
||||
import '../../../../../core/permissions/permission_manager.dart';
|
||||
import '../../application/permission_synchronizer.dart';
|
||||
import '../../../group/domain/entities/group.dart';
|
||||
import '../../../group/domain/repositories/group_repository.dart';
|
||||
import '../../../menu/domain/entities/menu.dart';
|
||||
@@ -20,13 +23,16 @@ class GroupPermissionController extends ChangeNotifier {
|
||||
required GroupPermissionRepository permissionRepository,
|
||||
required GroupRepository groupRepository,
|
||||
required MenuRepository menuRepository,
|
||||
PermissionManager? permissionManager,
|
||||
}) : _permissionRepository = permissionRepository,
|
||||
_groupRepository = groupRepository,
|
||||
_menuRepository = menuRepository;
|
||||
_menuRepository = menuRepository,
|
||||
_permissionManager = permissionManager;
|
||||
|
||||
final GroupPermissionRepository _permissionRepository;
|
||||
final GroupRepository _groupRepository;
|
||||
final MenuRepository _menuRepository;
|
||||
final PermissionManager? _permissionManager;
|
||||
|
||||
PaginatedResult<GroupPermission>? _result;
|
||||
bool _isLoading = false;
|
||||
@@ -63,8 +69,9 @@ class GroupPermissionController extends ChangeNotifier {
|
||||
_groups
|
||||
..clear()
|
||||
..addAll(response.items);
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoadingGroups = false;
|
||||
notifyListeners();
|
||||
@@ -84,8 +91,9 @@ class GroupPermissionController extends ChangeNotifier {
|
||||
_menus
|
||||
..clear()
|
||||
..addAll(response.items);
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoadingMenus = false;
|
||||
notifyListeners();
|
||||
@@ -112,8 +120,9 @@ class GroupPermissionController extends ChangeNotifier {
|
||||
includeDeleted: _includeDeleted,
|
||||
);
|
||||
_result = response;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
@@ -150,9 +159,11 @@ class GroupPermissionController extends ChangeNotifier {
|
||||
try {
|
||||
final created = await _permissionRepository.create(input);
|
||||
await fetch(page: 1);
|
||||
await _syncPermissionsForGroup(input.groupId);
|
||||
return created;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -166,9 +177,11 @@ class GroupPermissionController extends ChangeNotifier {
|
||||
try {
|
||||
final updated = await _permissionRepository.update(id, input);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
await _syncPermissionsForGroup(input.groupId);
|
||||
return updated;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -180,11 +193,16 @@ class GroupPermissionController extends ChangeNotifier {
|
||||
Future<bool> delete(int id) async {
|
||||
_setSubmitting(true);
|
||||
try {
|
||||
final groupId = _resolveGroupIdForPermission(id);
|
||||
await _permissionRepository.delete(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
if (groupId != null) {
|
||||
await _syncPermissionsForGroup(groupId);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return false;
|
||||
} finally {
|
||||
@@ -198,9 +216,11 @@ class GroupPermissionController extends ChangeNotifier {
|
||||
try {
|
||||
final restored = await _permissionRepository.restore(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
await _syncPermissionsForGroup(restored.group.id);
|
||||
return restored;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -219,4 +239,33 @@ class GroupPermissionController extends ChangeNotifier {
|
||||
_isSubmitting = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _syncPermissionsForGroup(int groupId) async {
|
||||
final manager = _permissionManager;
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final synchronizer = PermissionSynchronizer(
|
||||
repository: _permissionRepository,
|
||||
manager: manager,
|
||||
);
|
||||
await synchronizer.syncForGroup(groupId);
|
||||
} catch (_) {
|
||||
// 권한 동기화 실패는 사용자 경험에 영향이 없도록 무시한다.
|
||||
}
|
||||
}
|
||||
|
||||
int? _resolveGroupIdForPermission(int permissionId) {
|
||||
final current = _result?.items;
|
||||
if (current == null) {
|
||||
return null;
|
||||
}
|
||||
for (final item in current) {
|
||||
if (item.id == permissionId) {
|
||||
return item.group.id;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:superport_v2/widgets/components/filter_bar.dart';
|
||||
import 'package:superport_v2/widgets/components/superport_dialog.dart';
|
||||
|
||||
import '../../../../../core/config/environment.dart';
|
||||
import '../../../../../core/permissions/permission_manager.dart';
|
||||
import '../../../../../widgets/spec_page.dart';
|
||||
import '../../../group/domain/entities/group.dart';
|
||||
import '../../../group/domain/repositories/group_repository.dart';
|
||||
@@ -118,14 +119,27 @@ class _GroupPermissionEnabledPageState
|
||||
final intl.DateFormat _dateFormat = intl.DateFormat('yyyy-MM-dd HH:mm');
|
||||
String? _lastError;
|
||||
|
||||
bool _initialized = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
if (_initialized) {
|
||||
return;
|
||||
}
|
||||
final permissionManager = PermissionScope.of(context);
|
||||
_controller = GroupPermissionController(
|
||||
permissionRepository: GetIt.I<GroupPermissionRepository>(),
|
||||
groupRepository: GetIt.I<GroupRepository>(),
|
||||
menuRepository: GetIt.I<MenuRepository>(),
|
||||
permissionManager: permissionManager,
|
||||
)..addListener(_handleControllerUpdate);
|
||||
_initialized = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await _controller.loadGroups();
|
||||
await _controller.loadMenus();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_client.dart';
|
||||
import 'package:superport_v2/core/network/api_routes.dart';
|
||||
|
||||
import '../../domain/entities/menu.dart';
|
||||
import '../../domain/repositories/menu_repository.dart';
|
||||
@@ -12,7 +13,7 @@ class MenuRepositoryRemote implements MenuRepository {
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
static const _basePath = '/menus';
|
||||
static const _basePath = '${ApiRoutes.apiV1}/menus';
|
||||
|
||||
/// 메뉴 목록을 조회한다.
|
||||
@override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/failure.dart';
|
||||
|
||||
import '../../domain/entities/menu.dart';
|
||||
import '../../domain/repositories/menu_repository.dart';
|
||||
@@ -50,8 +51,9 @@ class MenuController extends ChangeNotifier {
|
||||
includeDeleted: false,
|
||||
);
|
||||
_parents = response.items;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoadingParents = false;
|
||||
notifyListeners();
|
||||
@@ -78,8 +80,9 @@ class MenuController extends ChangeNotifier {
|
||||
includeDeleted: _includeDeleted,
|
||||
);
|
||||
_result = response;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
@@ -118,8 +121,9 @@ class MenuController extends ChangeNotifier {
|
||||
await fetch(page: 1);
|
||||
await loadParents();
|
||||
return created;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -135,8 +139,9 @@ class MenuController extends ChangeNotifier {
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
await loadParents();
|
||||
return updated;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -152,8 +157,9 @@ class MenuController extends ChangeNotifier {
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
await loadParents();
|
||||
return true;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return false;
|
||||
} finally {
|
||||
@@ -169,8 +175,9 @@ class MenuController extends ChangeNotifier {
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
await loadParents();
|
||||
return restored;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_client.dart';
|
||||
import 'package:superport_v2/core/network/api_routes.dart';
|
||||
|
||||
import '../../domain/entities/product.dart';
|
||||
import '../../domain/repositories/product_repository.dart';
|
||||
@@ -12,7 +13,7 @@ class ProductRepositoryRemote implements ProductRepository {
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
static const _basePath = '/products';
|
||||
static const _basePath = '${ApiRoutes.apiV1}/products';
|
||||
|
||||
/// 제품 목록을 조회한다.
|
||||
@override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/failure.dart';
|
||||
|
||||
import '../../../vendor/domain/entities/vendor.dart';
|
||||
import '../../../vendor/domain/repositories/vendor_repository.dart';
|
||||
@@ -77,8 +78,9 @@ class ProductController extends ChangeNotifier {
|
||||
if (response.pageSize > 0 && response.pageSize != _pageSize) {
|
||||
_pageSize = response.pageSize;
|
||||
}
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
@@ -94,8 +96,9 @@ class ProductController extends ChangeNotifier {
|
||||
final uomResult = await _uomRepository.list(page: 1, pageSize: 100);
|
||||
_vendorOptions = vendorResult.items;
|
||||
_uomOptions = uomResult.items;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoadingLookups = false;
|
||||
notifyListeners();
|
||||
@@ -154,8 +157,9 @@ class ProductController extends ChangeNotifier {
|
||||
final created = await _productRepository.create(input);
|
||||
await fetch(page: 1);
|
||||
return created;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -170,8 +174,9 @@ class ProductController extends ChangeNotifier {
|
||||
final updated = await _productRepository.update(id, input);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return updated;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -186,8 +191,9 @@ class ProductController extends ChangeNotifier {
|
||||
await _productRepository.delete(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return true;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return false;
|
||||
} finally {
|
||||
@@ -202,8 +208,9 @@ class ProductController extends ChangeNotifier {
|
||||
final restored = await _productRepository.restore(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return restored;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_client.dart';
|
||||
import 'package:superport_v2/core/network/api_routes.dart';
|
||||
|
||||
import '../../domain/entities/uom.dart';
|
||||
import '../../domain/repositories/uom_repository.dart';
|
||||
@@ -12,7 +13,7 @@ class UomRepositoryRemote implements UomRepository {
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
static const _basePath = '/uoms';
|
||||
static const _basePath = '${ApiRoutes.apiV1}/uoms';
|
||||
|
||||
/// UOM 목록을 조회한다.
|
||||
@override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_client.dart';
|
||||
import 'package:superport_v2/core/network/api_routes.dart';
|
||||
|
||||
import '../../domain/entities/user.dart';
|
||||
import '../../domain/repositories/user_repository.dart';
|
||||
@@ -12,7 +13,7 @@ class UserRepositoryRemote implements UserRepository {
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
static const _basePath = '/employees';
|
||||
static const _basePath = '${ApiRoutes.apiV1}/employees';
|
||||
|
||||
/// 사용자 목록을 조회한다.
|
||||
@override
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/failure.dart';
|
||||
|
||||
import '../../../../../core/permissions/permission_manager.dart';
|
||||
import '../../../group/domain/entities/group.dart';
|
||||
import '../../../group/domain/repositories/group_repository.dart';
|
||||
import '../../../group_permission/application/permission_synchronizer.dart';
|
||||
import '../../../group_permission/domain/repositories/group_permission_repository.dart';
|
||||
import '../../domain/entities/user.dart';
|
||||
import '../../domain/repositories/user_repository.dart';
|
||||
|
||||
@@ -14,11 +18,17 @@ class UserController extends ChangeNotifier {
|
||||
UserController({
|
||||
required UserRepository userRepository,
|
||||
required GroupRepository groupRepository,
|
||||
GroupPermissionRepository? permissionRepository,
|
||||
PermissionManager? permissionManager,
|
||||
}) : _userRepository = userRepository,
|
||||
_groupRepository = groupRepository;
|
||||
_groupRepository = groupRepository,
|
||||
_permissionRepository = permissionRepository,
|
||||
_permissionManager = permissionManager;
|
||||
|
||||
final UserRepository _userRepository;
|
||||
final GroupRepository _groupRepository;
|
||||
final GroupPermissionRepository? _permissionRepository;
|
||||
final PermissionManager? _permissionManager;
|
||||
|
||||
PaginatedResult<UserAccount>? _result;
|
||||
bool _isLoading = false;
|
||||
@@ -47,8 +57,9 @@ class UserController extends ChangeNotifier {
|
||||
try {
|
||||
final response = await _groupRepository.list(page: 1, pageSize: 100);
|
||||
_groups = response.items;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoadingGroups = false;
|
||||
notifyListeners();
|
||||
@@ -74,8 +85,9 @@ class UserController extends ChangeNotifier {
|
||||
isActive: isActive,
|
||||
);
|
||||
_result = response;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
@@ -106,9 +118,11 @@ class UserController extends ChangeNotifier {
|
||||
try {
|
||||
final created = await _userRepository.create(input);
|
||||
await fetch(page: 1);
|
||||
await _syncPermissions(input.groupId);
|
||||
return created;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -122,9 +136,11 @@ class UserController extends ChangeNotifier {
|
||||
try {
|
||||
final updated = await _userRepository.update(id, input);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
await _syncPermissions(input.groupId);
|
||||
return updated;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -136,11 +152,16 @@ class UserController extends ChangeNotifier {
|
||||
Future<bool> delete(int id) async {
|
||||
_setSubmitting(true);
|
||||
try {
|
||||
final groupId = _resolveGroupId(id);
|
||||
await _userRepository.delete(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
if (groupId != null) {
|
||||
await _syncPermissions(groupId);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return false;
|
||||
} finally {
|
||||
@@ -154,9 +175,14 @@ class UserController extends ChangeNotifier {
|
||||
try {
|
||||
final restored = await _userRepository.restore(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
final groupId = restored.group?.id;
|
||||
if (groupId != null) {
|
||||
await _syncPermissions(groupId);
|
||||
}
|
||||
return restored;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -175,4 +201,34 @@ class UserController extends ChangeNotifier {
|
||||
_isSubmitting = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _syncPermissions(int groupId) async {
|
||||
final manager = _permissionManager;
|
||||
final repository = _permissionRepository;
|
||||
if (manager == null || repository == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final synchronizer = PermissionSynchronizer(
|
||||
repository: repository,
|
||||
manager: manager,
|
||||
);
|
||||
await synchronizer.syncForGroup(groupId);
|
||||
} catch (_) {
|
||||
// 권한 동기화 실패는 무시하고 기존 흐름을 유지한다.
|
||||
}
|
||||
}
|
||||
|
||||
int? _resolveGroupId(int userId) {
|
||||
final items = _result?.items;
|
||||
if (items == null) {
|
||||
return null;
|
||||
}
|
||||
for (final user in items) {
|
||||
if (user.id == userId) {
|
||||
return user.group?.id;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@ import 'package:superport_v2/widgets/components/filter_bar.dart';
|
||||
import 'package:superport_v2/widgets/components/superport_dialog.dart';
|
||||
|
||||
import '../../../../../core/config/environment.dart';
|
||||
import '../../../../../core/permissions/permission_manager.dart';
|
||||
import '../../../../../widgets/spec_page.dart';
|
||||
import '../../../group/domain/entities/group.dart';
|
||||
import '../../../group/domain/repositories/group_repository.dart';
|
||||
import '../../../group_permission/domain/repositories/group_permission_repository.dart';
|
||||
import '../../domain/entities/user.dart';
|
||||
import '../../domain/repositories/user_repository.dart';
|
||||
import '../controllers/user_controller.dart';
|
||||
@@ -96,17 +98,31 @@ class _UserEnabledPageState extends State<_UserEnabledPage> {
|
||||
final FocusNode _searchFocus = FocusNode();
|
||||
bool _groupsLoaded = false;
|
||||
String? _lastError;
|
||||
bool _initialized = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
if (_initialized) {
|
||||
return;
|
||||
}
|
||||
final permissionManager = PermissionScope.of(context);
|
||||
_controller = UserController(
|
||||
userRepository: GetIt.I<UserRepository>(),
|
||||
groupRepository: GetIt.I<GroupRepository>(),
|
||||
permissionRepository: GetIt.I<GroupPermissionRepository>(),
|
||||
permissionManager: permissionManager,
|
||||
)..addListener(_handleControllerUpdate);
|
||||
_initialized = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await _controller.loadGroups();
|
||||
await _controller.fetch();
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_groupsLoaded = true;
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:dio/dio.dart';
|
||||
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_client.dart';
|
||||
import 'package:superport_v2/core/network/api_routes.dart';
|
||||
|
||||
import '../../domain/entities/vendor.dart';
|
||||
import '../../domain/repositories/vendor_repository.dart';
|
||||
@@ -13,7 +14,7 @@ class VendorRepositoryRemote implements VendorRepository {
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
static const _basePath = '/vendors'; // TODO: 백엔드 경로 확정 시 수정
|
||||
static const _basePath = '${ApiRoutes.apiV1}/vendors';
|
||||
|
||||
@override
|
||||
Future<PaginatedResult<Vendor>> list({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/failure.dart';
|
||||
|
||||
import '../../domain/entities/vendor.dart';
|
||||
import '../../domain/repositories/vendor_repository.dart';
|
||||
@@ -55,8 +56,9 @@ class VendorController extends ChangeNotifier {
|
||||
if (response.pageSize > 0 && response.pageSize != _pageSize) {
|
||||
_pageSize = response.pageSize;
|
||||
}
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
@@ -94,8 +96,9 @@ class VendorController extends ChangeNotifier {
|
||||
final vendor = await _repository.create(input);
|
||||
await fetch(page: 1);
|
||||
return vendor;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -110,8 +113,9 @@ class VendorController extends ChangeNotifier {
|
||||
final vendor = await _repository.update(id, input);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return vendor;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -126,8 +130,9 @@ class VendorController extends ChangeNotifier {
|
||||
await _repository.delete(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return true;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return false;
|
||||
} finally {
|
||||
@@ -142,8 +147,9 @@ class VendorController extends ChangeNotifier {
|
||||
final vendor = await _repository.restore(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return vendor;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_client.dart';
|
||||
import 'package:superport_v2/core/network/api_routes.dart';
|
||||
|
||||
import '../../domain/entities/warehouse.dart';
|
||||
import '../../domain/repositories/warehouse_repository.dart';
|
||||
@@ -12,7 +13,7 @@ class WarehouseRepositoryRemote implements WarehouseRepository {
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
static const _basePath = '/warehouses';
|
||||
static const _basePath = '${ApiRoutes.apiV1}/warehouses';
|
||||
|
||||
/// 창고 목록을 조회한다.
|
||||
@override
|
||||
@@ -21,6 +22,7 @@ class WarehouseRepositoryRemote implements WarehouseRepository {
|
||||
int pageSize = 20,
|
||||
String? query,
|
||||
bool? isActive,
|
||||
bool includeZipcode = true,
|
||||
}) async {
|
||||
final response = await _api.get<Map<String, dynamic>>(
|
||||
_basePath,
|
||||
@@ -29,6 +31,7 @@ class WarehouseRepositoryRemote implements WarehouseRepository {
|
||||
'page_size': pageSize,
|
||||
if (query != null && query.isNotEmpty) 'q': query,
|
||||
if (isActive != null) 'is_active': isActive,
|
||||
if (includeZipcode) 'include': 'zipcode',
|
||||
},
|
||||
options: Options(responseType: ResponseType.json),
|
||||
);
|
||||
|
||||
@@ -10,6 +10,7 @@ abstract class WarehouseRepository {
|
||||
int pageSize = 20,
|
||||
String? query,
|
||||
bool? isActive,
|
||||
bool includeZipcode = true,
|
||||
});
|
||||
|
||||
/// 창고를 생성한다.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/failure.dart';
|
||||
|
||||
import '../../domain/entities/warehouse.dart';
|
||||
import '../../domain/repositories/warehouse_repository.dart';
|
||||
@@ -53,8 +54,9 @@ class WarehouseController extends ChangeNotifier {
|
||||
if (response.pageSize > 0 && response.pageSize != _pageSize) {
|
||||
_pageSize = response.pageSize;
|
||||
}
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
@@ -95,8 +97,9 @@ class WarehouseController extends ChangeNotifier {
|
||||
final created = await _repository.create(input);
|
||||
await fetch(page: 1);
|
||||
return created;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -111,8 +114,9 @@ class WarehouseController extends ChangeNotifier {
|
||||
final updated = await _repository.update(id, input);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return updated;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
@@ -127,8 +131,9 @@ class WarehouseController extends ChangeNotifier {
|
||||
await _repository.delete(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return true;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return false;
|
||||
} finally {
|
||||
@@ -143,8 +148,9 @@ class WarehouseController extends ChangeNotifier {
|
||||
final restored = await _repository.restore(id);
|
||||
await fetch(page: _result?.page ?? 1);
|
||||
return restored;
|
||||
} catch (e) {
|
||||
_errorMessage = e.toString();
|
||||
} catch (error) {
|
||||
final failure = Failure.from(error);
|
||||
_errorMessage = failure.describe();
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user