feat(inventory): 재고 현황 요약/상세 플로우를 릴리스
- lib/features/inventory/summary 계층과 warehouse select 위젯을 추가해 목록/상세, 자동 새로고침, 필터, 상세 시트를 구현 - PermissionBootstrapper, scope 파서, 라우트 가드로 inventory.view 기반 권한 부여와 메뉴 노출을 통합(lib/core, lib/main.dart 등) - Inventory Summary API/QA/Audit 문서와 PR 템플릿, CHANGELOG를 신규 스펙과 검증 커맨드로 업데이트 - DTO 직렬화 의존성을 추가하고 Golden·Widget·단위 테스트를 작성했으며 flutter analyze / flutter test --coverage를 통과
This commit is contained in:
@@ -9,13 +9,12 @@ import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import '../../../../core/constants/app_sections.dart';
|
||||
import '../../../../core/network/api_error.dart';
|
||||
import '../../../../core/network/failure.dart';
|
||||
import '../../../../core/permissions/permission_bootstrapper.dart';
|
||||
import '../../../../core/permissions/permission_manager.dart';
|
||||
import '../../../auth/application/auth_service.dart';
|
||||
import '../../../auth/domain/entities/auth_session.dart';
|
||||
import '../../../auth/domain/entities/login_request.dart';
|
||||
import '../../../masters/group/domain/entities/group.dart';
|
||||
import '../../../masters/group/domain/repositories/group_repository.dart';
|
||||
import '../../../masters/group_permission/application/permission_synchronizer.dart';
|
||||
import '../../../masters/group_permission/domain/repositories/group_permission_repository.dart';
|
||||
|
||||
/// Superport 로그인 화면. 간단한 유효성 검증 후 대시보드로 이동한다.
|
||||
@@ -356,66 +355,11 @@ class _LoginPageState extends State<LoginPage> {
|
||||
}
|
||||
|
||||
Future<void> _applyPermissions(AuthSession session) async {
|
||||
final manager = PermissionScope.of(context);
|
||||
manager.clearServerPermissions();
|
||||
|
||||
final aggregated = <String, Set<PermissionAction>>{};
|
||||
for (final permission in session.permissions) {
|
||||
final map = permission.toPermissionMap();
|
||||
for (final entry in map.entries) {
|
||||
aggregated
|
||||
.putIfAbsent(entry.key, () => <PermissionAction>{})
|
||||
.addAll(entry.value);
|
||||
}
|
||||
}
|
||||
if (aggregated.isNotEmpty) {
|
||||
manager.applyServerPermissions(aggregated);
|
||||
return;
|
||||
}
|
||||
|
||||
await _synchronizePermissions(groupId: session.user.primaryGroupId);
|
||||
}
|
||||
|
||||
Future<void> _synchronizePermissions({int? groupId}) async {
|
||||
final manager = PermissionScope.of(context);
|
||||
manager.clearServerPermissions();
|
||||
|
||||
final groupRepository = GetIt.I<GroupRepository>();
|
||||
int? targetGroupId = groupId;
|
||||
|
||||
if (targetGroupId == null) {
|
||||
final defaultGroups = await groupRepository.list(
|
||||
page: 1,
|
||||
pageSize: 1,
|
||||
isDefault: true,
|
||||
);
|
||||
var targetGroup = _firstGroupWithId(defaultGroups.items);
|
||||
|
||||
if (targetGroup == null) {
|
||||
final fallbackGroups = await groupRepository.list(page: 1, pageSize: 1);
|
||||
targetGroup = _firstGroupWithId(fallbackGroups.items);
|
||||
}
|
||||
targetGroupId = targetGroup?.id;
|
||||
}
|
||||
|
||||
if (targetGroupId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final permissionRepository = GetIt.I<GroupPermissionRepository>();
|
||||
final synchronizer = PermissionSynchronizer(
|
||||
repository: permissionRepository,
|
||||
manager: manager,
|
||||
final bootstrapper = PermissionBootstrapper(
|
||||
manager: PermissionScope.of(context),
|
||||
groupRepository: GetIt.I<GroupRepository>(),
|
||||
groupPermissionRepository: GetIt.I<GroupPermissionRepository>(),
|
||||
);
|
||||
await synchronizer.syncForGroup(targetGroupId);
|
||||
}
|
||||
|
||||
Group? _firstGroupWithId(List<Group> groups) {
|
||||
for (final group in groups) {
|
||||
if (group.id != null) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
await bootstrapper.apply(session);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user