feat(approvals): 결재 상세 전표 연동과 스코프 권한 매핑 확장
- 결재 상세 다이얼로그에 전표 요약·라인·고객 섹션을 추가하고 현재 사용자 단계 강조 및 비고 입력 검증을 개선함 - 대시보드·결재 목록에서 전표 리포지토리와 AuthService를 주입해 상세 진입과 결재 관리 이동 버튼을 제공함 - StockTransactionApprovalInput이 template/steps를 config 노드로 직렬화하도록 변경하고 통합 테스트를 갱신함 - scope 권한 문자열을 리소스권으로 변환하는 PermissionScopeMapper와 단위 테스트를 추가하고 AuthPermission을 연동함 - 재고 메뉴 정렬, 상세 컨트롤러 오류 리셋, 요청자 자동완성 상태 동기화 등 주변 UI 버그를 수정하고 테스트를 보강함
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
@@ -18,6 +19,7 @@ import '../../../../widgets/components/superport_dialog.dart';
|
||||
import '../../../../widgets/components/superport_table.dart';
|
||||
import '../../../../widgets/components/superport_pagination_controls.dart';
|
||||
import '../../../../widgets/components/feature_disabled_placeholder.dart';
|
||||
import '../../../auth/application/auth_service.dart';
|
||||
import '../../domain/entities/approval.dart';
|
||||
import '../../domain/repositories/approval_repository.dart';
|
||||
import '../../domain/repositories/approval_template_repository.dart';
|
||||
@@ -26,6 +28,7 @@ import '../../domain/usecases/list_approval_drafts_use_case.dart';
|
||||
import '../../domain/usecases/save_approval_draft_use_case.dart';
|
||||
import '../../../inventory/lookups/domain/repositories/inventory_lookup_repository.dart';
|
||||
import '../../../inventory/shared/widgets/employee_autocomplete_field.dart';
|
||||
import '../../../inventory/transactions/domain/repositories/stock_transaction_repository.dart';
|
||||
import '../controllers/approval_controller.dart';
|
||||
import '../dialogs/approval_detail_dialog.dart';
|
||||
|
||||
@@ -100,6 +103,7 @@ class _ApprovalEnabledPageState extends State<_ApprovalEnabledPage> {
|
||||
_controller = ApprovalController(
|
||||
approvalRepository: GetIt.I<ApprovalRepository>(),
|
||||
templateRepository: GetIt.I<ApprovalTemplateRepository>(),
|
||||
transactionRepository: GetIt.I<StockTransactionRepository>(),
|
||||
lookupRepository: GetIt.I.isRegistered<InventoryLookupRepository>()
|
||||
? GetIt.I<InventoryLookupRepository>()
|
||||
: null,
|
||||
@@ -229,6 +233,9 @@ class _ApprovalEnabledPageState extends State<_ApprovalEnabledPage> {
|
||||
_approvalsResourcePath,
|
||||
PermissionAction.edit,
|
||||
);
|
||||
final currentUserId = GetIt.I.isRegistered<AuthService>()
|
||||
? GetIt.I<AuthService>().session?.user.id
|
||||
: null;
|
||||
|
||||
await showApprovalDetailDialog(
|
||||
context: context,
|
||||
@@ -236,6 +243,7 @@ class _ApprovalEnabledPageState extends State<_ApprovalEnabledPage> {
|
||||
dateFormat: _dateTimeFormat,
|
||||
canPerformStepActions: canPerformStepActions,
|
||||
canApplyTemplate: canApplyTemplate,
|
||||
currentUserId: currentUserId,
|
||||
);
|
||||
|
||||
if (!mounted) {
|
||||
@@ -245,6 +253,31 @@ class _ApprovalEnabledPageState extends State<_ApprovalEnabledPage> {
|
||||
_controller.clearSelection();
|
||||
}
|
||||
|
||||
void _handleRequesterFieldChanged() {
|
||||
void updateSelection() {
|
||||
final selectedLabel = _selectedRequester == null
|
||||
? ''
|
||||
: '${_selectedRequester!.name} (${_selectedRequester!.employeeNo})';
|
||||
if (_requesterController.text.trim() != selectedLabel) {
|
||||
_selectedRequester = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
final phase = SchedulerBinding.instance.schedulerPhase;
|
||||
if (phase == SchedulerPhase.persistentCallbacks ||
|
||||
phase == SchedulerPhase.transientCallbacks) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
setState(updateSelection);
|
||||
});
|
||||
return;
|
||||
}
|
||||
setState(updateSelection);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.removeListener(_handleControllerUpdate);
|
||||
@@ -323,16 +356,7 @@ class _ApprovalEnabledPageState extends State<_ApprovalEnabledPage> {
|
||||
onSuggestionSelected: (suggestion) {
|
||||
setState(() => _selectedRequester = suggestion);
|
||||
},
|
||||
onChanged: () {
|
||||
setState(() {
|
||||
final selectedLabel = _selectedRequester == null
|
||||
? ''
|
||||
: '${_selectedRequester!.name} (${_selectedRequester!.employeeNo})';
|
||||
if (_requesterController.text.trim() != selectedLabel) {
|
||||
_selectedRequester = null;
|
||||
}
|
||||
});
|
||||
},
|
||||
onChanged: _handleRequesterFieldChanged,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
|
||||
Reference in New Issue
Block a user