feat(approvals): 결재 상세 전표 연동과 스코프 권한 매핑 확장
- 결재 상세 다이얼로그에 전표 요약·라인·고객 섹션을 추가하고 현재 사용자 단계 강조 및 비고 입력 검증을 개선함 - 대시보드·결재 목록에서 전표 리포지토리와 AuthService를 주입해 상세 진입과 결재 관리 이동 버튼을 제공함 - StockTransactionApprovalInput이 template/steps를 config 노드로 직렬화하도록 변경하고 통합 테스트를 갱신함 - scope 권한 문자열을 리소스권으로 변환하는 PermissionScopeMapper와 단위 테스트를 추가하고 AuthPermission을 연동함 - 재고 메뉴 정렬, 상세 컨트롤러 오류 리셋, 요청자 자동완성 상태 동기화 등 주변 UI 버그를 수정하고 테스트를 보강함
This commit is contained in:
@@ -100,7 +100,7 @@ final List<MenuRouteDefinition> menuRouteDefinitions = [
|
||||
defaultLabel: '재고 현황',
|
||||
icon: lucide.LucideIcons.chartNoAxesColumnIncreasing,
|
||||
builder: (context, state) => InventorySummaryPage(routeUri: state.uri),
|
||||
defaultOrder: 20,
|
||||
defaultOrder: 11,
|
||||
extraRequirements: const [
|
||||
PermissionRequirement(resource: PermissionResources.inventoryScope),
|
||||
],
|
||||
@@ -112,7 +112,7 @@ final List<MenuRouteDefinition> menuRouteDefinitions = [
|
||||
defaultLabel: '입고',
|
||||
icon: lucide.LucideIcons.packagePlus,
|
||||
builder: (context, state) => InboundPage(routeUri: state.uri),
|
||||
defaultOrder: 21,
|
||||
defaultOrder: 12,
|
||||
),
|
||||
MenuRouteDefinition(
|
||||
menuCode: 'inventory.issues',
|
||||
@@ -121,7 +121,7 @@ final List<MenuRouteDefinition> menuRouteDefinitions = [
|
||||
defaultLabel: '출고',
|
||||
icon: lucide.LucideIcons.packageMinus,
|
||||
builder: (context, state) => OutboundPage(routeUri: state.uri),
|
||||
defaultOrder: 22,
|
||||
defaultOrder: 13,
|
||||
),
|
||||
MenuRouteDefinition(
|
||||
menuCode: 'inventory.rentals',
|
||||
@@ -129,7 +129,7 @@ final List<MenuRouteDefinition> menuRouteDefinitions = [
|
||||
defaultLabel: '대여',
|
||||
icon: lucide.LucideIcons.handshake,
|
||||
builder: (context, state) => RentalPage(routeUri: state.uri),
|
||||
defaultOrder: 23,
|
||||
defaultOrder: 14,
|
||||
),
|
||||
MenuRouteDefinition(
|
||||
menuCode: 'inventory.vendors',
|
||||
|
||||
97
lib/core/permissions/permission_scope_mapper.dart
Normal file
97
lib/core/permissions/permission_scope_mapper.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
import 'permission_manager.dart';
|
||||
import 'permission_resources.dart';
|
||||
|
||||
/// 서버가 내려주는 scope 권한 코드를 실사용 리소스 권한으로 변환한다.
|
||||
class PermissionScopeMapper {
|
||||
const PermissionScopeMapper._();
|
||||
|
||||
/// scope:<code> 형식의 권한에서 [PermissionManager]가 이해할 수 있는 리소스 맵을 생성한다.
|
||||
static Map<String, Set<PermissionAction>>? map(String scope) {
|
||||
final code = _normalize(scope);
|
||||
if (code.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final definition = _definitions[code];
|
||||
if (definition == null || definition.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final mapped = <String, Set<PermissionAction>>{};
|
||||
for (final entry in definition.entries) {
|
||||
mapped[entry.key] = entry.value.toSet();
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
|
||||
static String _normalize(String value) {
|
||||
final trimmed = value.trim().toLowerCase();
|
||||
if (trimmed.isEmpty) {
|
||||
return '';
|
||||
}
|
||||
if (trimmed.startsWith('scope:')) {
|
||||
return trimmed.substring('scope:'.length);
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
static const Map<String, Map<String, Set<PermissionAction>>> _definitions = {
|
||||
'approval.approve': {
|
||||
PermissionResources.approvals: {PermissionAction.approve},
|
||||
},
|
||||
'approvals': {
|
||||
PermissionResources.approvals: {PermissionAction.view},
|
||||
},
|
||||
'approvals.history': {
|
||||
PermissionResources.approvalHistories: {PermissionAction.view},
|
||||
},
|
||||
'approvals.steps': {
|
||||
PermissionResources.approvalSteps: {PermissionAction.view},
|
||||
},
|
||||
'approvals.templates': {
|
||||
PermissionResources.approvalTemplates: {PermissionAction.view},
|
||||
},
|
||||
'dashboard': {
|
||||
PermissionResources.dashboard: {PermissionAction.view},
|
||||
},
|
||||
'dashboard.view': {
|
||||
PermissionResources.dashboard: {PermissionAction.view},
|
||||
},
|
||||
'approval.view_all': {
|
||||
PermissionResources.approvals: {PermissionAction.view},
|
||||
PermissionResources.approvalSteps: {PermissionAction.view},
|
||||
PermissionResources.approvalHistories: {PermissionAction.view},
|
||||
},
|
||||
'approval.manage': {
|
||||
PermissionResources.approvals: {
|
||||
PermissionAction.view,
|
||||
PermissionAction.create,
|
||||
PermissionAction.edit,
|
||||
PermissionAction.delete,
|
||||
},
|
||||
PermissionResources.approvalSteps: {
|
||||
PermissionAction.view,
|
||||
PermissionAction.create,
|
||||
PermissionAction.edit,
|
||||
PermissionAction.delete,
|
||||
},
|
||||
PermissionResources.approvalHistories: {PermissionAction.view},
|
||||
PermissionResources.approvalTemplates: {
|
||||
PermissionAction.view,
|
||||
PermissionAction.create,
|
||||
PermissionAction.edit,
|
||||
PermissionAction.delete,
|
||||
},
|
||||
},
|
||||
'inventory.view': {
|
||||
PermissionResources.inventorySummary: {PermissionAction.view},
|
||||
},
|
||||
'inventory.receipts': {
|
||||
PermissionResources.stockTransactions: {PermissionAction.view},
|
||||
},
|
||||
'inventory.issues': {
|
||||
PermissionResources.stockTransactions: {PermissionAction.view},
|
||||
},
|
||||
'inventory.rentals': {
|
||||
PermissionResources.stockTransactions: {PermissionAction.view},
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user